diff --git a/.gitignore b/.gitignore index b8f68a26f..bebcef932 100644 --- a/.gitignore +++ b/.gitignore @@ -116,7 +116,7 @@ contrib/debian/files contrib/debian/substvars src/rpcmisc~.cpp -src/komodod -src/genVERUSTEST src/komodo-cli +src/komodod src/komodo-tx +src/komodo-test diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..e69de29bb diff --git a/Dockerfile b/Dockerfile index 92b0b779c..7a4308f7d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN apt-get -y update && \ apt-get -y upgrade && \ apt-get -y install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev \ unzip python zlib1g-dev wget bsdmainutils automake libssl-dev libprotobuf-dev \ - protobuf-compiler libqrencode-dev libdb++-dev software-properties-common libcurl4-openssl-dev && \ + protobuf-compiler libqrencode-dev libdb++-dev software-properties-common libcurl4-openssl-dev curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/Makefile.am b/Makefile.am index 143b2cc68..d3171b206 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,6 +15,7 @@ endif BITCOIND_BIN=$(top_builddir)/src/zcashd$(EXEEXT) BITCOIN_CLI_BIN=$(top_builddir)/src/zcash-cli$(EXEEXT) +#WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) if TARGET_DARWIN @@ -32,26 +33,26 @@ endif DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ - $(top_srcdir)/contrib/devtools/security-check.py + $(top_srcdir)/contrib/devtools/security-check.py WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ - $(top_srcdir)/share/pixmaps/nsis-header.bmp \ - $(top_srcdir)/share/pixmaps/nsis-wizard.bmp + $(top_srcdir)/share/pixmaps/nsis-header.bmp \ + $(top_srcdir)/share/pixmaps/nsis-wizard.bmp if TARGET_DARWIN OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \ - $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ - $(top_srcdir)/contrib/macdeploy/DS_Store \ - $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ - $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh + $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ + $(top_srcdir)/contrib/macdeploy/DS_Store \ + $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ + $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh endif if TARGET_DARWIN COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ - leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ - baseline_filtered.info block_test_filtered.info \ - leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info + leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ + baseline_filtered.info block_test_filtered.info \ + leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info # zcash-gtest.info zcash-gtest_filtered.info zcash-gtest_coverage.info else COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ @@ -104,9 +105,9 @@ $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR $(INSTALL_DATA) $< $@ OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ - $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ - $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings - + $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ + $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings + endif if BUILD_DARWIN @@ -155,6 +156,9 @@ $(BITCOIND_BIN): FORCE $(BITCOIN_CLI_BIN): FORCE $(MAKE) -C src $(@F) +#$(WALLET_UTILITY_BIN): FORCE +# $(MAKE) -C src $(@F) + if USE_LCOV baseline.info: @@ -163,27 +167,27 @@ baseline.info: if BUILD_DARWIN baseline_filtered.info: baseline.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ - "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ + "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ else baseline_filtered.info: baseline.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ endif leveldb_baseline.info: baseline_filtered.info @@ -192,27 +196,27 @@ leveldb_baseline.info: baseline_filtered.info if BUILD_DARWIN leveldb_baseline_filtered.info: leveldb_baseline.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ - "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ + "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ else leveldb_baseline_filtered.info: leveldb_baseline.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ endif baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info @@ -227,27 +231,27 @@ test_bitcoin.info: baseline_filtered_combined.info if BUILD_DARWIN test_bitcoin_filtered.info: test_bitcoin.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ - "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ + "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ else test_bitcoin_filtered.info: test_bitcoin.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ endif @@ -261,32 +265,32 @@ block_test.info: test_bitcoin_filtered.info if BUILD_DARWIN block_test_filtered.info: block_test.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ - "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ - "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/$(BUILD)/include/*.h" \ + "$(abs_builddir)/depends/$(BUILD)/include/boost/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gmock/*" \ + "$(abs_builddir)/depends/$(BUILD)/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ else block_test_filtered.info: block_test.info $(LCOV) -r $< "/usr/include/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ - "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ - "$(abs_builddir)/src/gtest/*" \ - "$(abs_builddir)/src/test/*" \ - "$(abs_builddir)/src/wallet/gtest/*" \ - "$(abs_builddir)/src/wallet/test/*" \ - -o $@ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/*.h" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \ + "$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \ + "$(abs_builddir)/src/gtest/*" \ + "$(abs_builddir)/src/test/*" \ + "$(abs_builddir)/src/wallet/gtest/*" \ + "$(abs_builddir)/src/wallet/test/*" \ + -o $@ endif test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ if ! BUILD_DARWIN zcash-gtest_coverage.info: baseline_filtered_combined.info zcash-gtest_filtered.info @@ -295,7 +299,7 @@ endif if BUILD_DARWIN total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt else total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info zcash-gtest_filtered.info block_test_filtered.info $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a zcash-gtest_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt @@ -303,19 +307,19 @@ endif test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info - $(GENHTML) -s $< -o $(@D) - @touch $@ + $(GENHTML) -s $< -o $(@D) + @touch $@ if TARGET_DARWIN zcash-gtest.coverage/.dirstamp: zcash-gtest_coverage.info - $(GENHTML) -s $< -o $(@D) - @touch $@ + $(GENHTML) -s $< -o $(@D) + @touch $@ cov-zcash: zcash-gtest.coverage/.dirstamp endif total.coverage/.dirstamp: total_coverage.info - $(GENHTML) -s $< -o $(@D) - @touch $@ + $(GENHTML) -s $< -o $(@D) + @touch $@ if BUILD_DARWIN cov: test_bitcoin.coverage/.dirstamp cov-zcash total.coverage/.dirstamp diff --git a/README.md b/README.md index 25c573317..5d85d013d 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,48 @@ -Komodo 1.0.15 +## Komodo with Bitcore +This version of Komodo contains Bitcore support for komodo and all its assetchains. ## Komodod This software is Komodo client, generally you will use this if you want to mine KMD or setup a full node. It downloads and stores the entire history of Komodo transactions; depending on the speed of your computer and network connection, the synchronization process could take a day or more once the blockchain has reached a significant size. + ## Development Resources - Komodo Web: [https://komodoplatform.com/](https://komodoplatform.com/) -- Organization web: [https://www.supernet.org](https://www.supernet.org) -- Forum: [https://forum.supernet.org/](https://forum.supernet.org/) -- Mail: [info@supernet.org](mailto:info@supernet.org) -- Support & Guides: [https://support.supernet.org/support/home](https://support.supernet.org/support/home) +- Organization web: [https://komodoplatform.com/](https://komodoplatform.com/) +- Forum: [https://forum.komodoplatform.com/](https://forum.komodoplatform.com/) +- Mail: [info@komodoplatform.com](mailto:info@komodoplatform.com) +- Support: [https://support.komodoplatform.com/support/home](https://support.komodoplatform.com/support/home) +- Knowledgebase & How-to: [https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages](https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages) - API references: [http://docs.supernet.org/](http://docs.supernet.org/) #Not up to date. +- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/wp-content/uploads/2018/03/2018-03-12-Komodo-White-Paper-Full.pdf) - Komodo Platform public material: [Komodo Platform public material](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0) + ## List of Komodo Platform Technologies -Delayed Proof of Work (dPoW) - Additional security layer. -zk-SNARKs - Komodo Platform's privacy technology -Jumblr - Decentralized tumbler for KMD and other cryptocurrencies -Assetchains - Easy way to fork Komodo coin -Pegged Assets - Chains that maintain a peg to fiat currencies -Peerchains - Scalability solution where sibling chains form a network of blockchains -More in depth covered [here](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0) -Also note you receive 5% APR on your holdings. -[See this article for more details](https://supernet.org/en/resources/articles/receive-free-coins-quaranteed-kmd-interest) +- Delayed Proof of Work (dPoW) - Additional security layer. +- zk-SNARKs - Komodo Platform's privacy technology +- Jumblr - Decentralized tumbler for KMD and other cryptocurrencies +- Assetchains - Easy way to fork Komodo coin +- Pegged Assets - Chains that maintain a peg to fiat currencies +- Peerchains - Scalability solution where sibling chains form a network of blockchains +- More in depth covered [here](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0) +- Also note you receive 5% APR on your holdings. +[See this article for more details](https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages/20480015/Claim+KMD+Interest+in+Agama) + ## Tech Specification -Max Supply: 200 million KMD. -Block Time: 1M 2s -Block Reward: 3KMD -Mining Algorithm: Equihash +- Max Supply: 200 million KMD. +- Block Time: 1M 2s +- Block Reward: 3KMD +- Mining Algorithm: Equihash + ## About this Project Komodo is based on Zcash and has been by our innovative consensus algorithm called dPoW which utilizes Bitcoin's hashrate to store Komodo blockchain information into the Bitcoin blockchain. Other new and native Komodo features are the privacy technology called JUMBLR or our assetchain capabilities (one click plug and play blockchain solutions). More details are available under https://komodoplatform.com/. + ## Getting started Dependencies ------------ -``` +```shell #The following packages are needed: -sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl3-gnutls-dev bsdmainutils automake +sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-openssl-dev bsdmainutils automake curl ``` Komodo @@ -54,7 +62,7 @@ dPoW branch: autobuild into GUI installers, unix, osx, windows beta branch: notary nodes, command line unix dev branch: bleeding edge, possibly wont even compile, multiple updates per hour -``` +```shell git clone https://github.com/jl777/komodo cd komodo #you might want to: git checkout ; git pull @@ -64,7 +72,6 @@ cd komodo #This can take some time. ``` - **komodo is experimental and a work-in-progress.** Use at your own risk. Deprecation Policy @@ -76,11 +83,14 @@ time after this one year period. The automatic feature is based on block height and can be explicitly disabled. -# to update an existing version, git checkout dPoW if not on that branch already +# to update an existing version, `git checkout dPoW` if not on that branch already +```shell git pull ./zcutil/fetch-params.sh ./zcutil/build.sh -j8 -To reset the blockchain, from ~/.komodo rm -rf blocks chainstate debug.log komodostate db.log +``` +To reset the blockchain, from *~/.komodo* `rm -rf blocks chainstate debug.log komodostate db.log` + Create komodo.conf ------------------ @@ -105,7 +115,7 @@ addnode=89.248.166.91 Start mining ------------ -``` +```shell #iguana documentation shows how to get the btcpubkey and wifstrs that need to be used #bitcoin also need to be installed with txindex=1 and with rpc enabled cd ~ @@ -136,59 +146,89 @@ Both komodod and komodo-cli recognize -ac_name=option so you can create fork fro ``` ======= **Zcash is unfinished and highly experimental.** Use at your own risk. + Where do I begin? ----------------- We have a guide for joining the main Zcash network: https://github.com/zcash/zcash/wiki/1.0-User-Guide + ### Need Help? * See the documentation at the [Zcash Wiki](https://github.com/zcash/zcash/wiki) for help and more information. * Ask for help on the [Zcash](https://forum.z.cash/) forum. Participation in the Zcash project is subject to a [Code of Conduct](code_of_conduct.md). + Building -------- Build Zcash along with most dependencies from source by running -./zcutil/build.sh. Currently only Linux is officially supported. +`./zcutil/build.sh`. Currently only Linux is officially supported. + License ------- For license information see the file [COPYING](COPYING). -NOTE TO EXCHANGES: + +**NOTE TO EXCHANGES:** https://bitcointalk.org/index.php?topic=1605144.msg17732151#msg17732151 There is a small chance that an outbound transaction will give an error due to mismatched values in wallet calculations. There is a -exchange option that you can run komodod with, but make sure to have the entire transaction history under the same -exchange mode. Otherwise you will get wallet conflicts. -To change modes: -a) backup all privkeys (launch komodod with -exportdir= and dumpwallet) -b) start a totally new sync including wallet.dat, launch with same exportdir -c) stop it before it gets too far and import all the privkeys from a) using komodo-cli importwallet filename + +**To change modes:** + +a) backup all privkeys (launch komodod with `-exportdir=` and `dumpwallet`) + +b) start a totally new sync including `wallet.dat`, launch with same `exportdir` + +c) stop it before it gets too far and import all the privkeys from a) using `komodo-cli importwallet filename` + d) resume sync till it gets to chaintip + For example: +```shell ./komodod -exportdir=/tmp & ./komodo-cli dumpwallet example ./komodo-cli stop mv ~/.komodo ~/.komodo.old && mkdir ~/.komodo && cp ~/.komodo.old/komodo.conf ~/.komodo.old/peers.dat ~/.komodo ./komodod -exchange -exportdir=/tmp & ./komodo-cli importwallet /tmp/example -############## JUMBLR -komodod now has jumblr_deposit and jumblr_secret RPC calls. +``` + +## JUMBLR +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: + +`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. + +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? Instead of generating 1 secret address, generate 100 and make a script file with: +```shell ./komodo-cli jumblr_secret ./komodo-cli jumblr_secret ... ./komodo-cli jumblr_secret +``` And make sure to delete all traces of this when the JUMBLR is finished. You will end up with 100 addresses that have an average of 1000 KMD each. So as long as you are careful and dont do a 10,000 KMD transaction (that will link 10 of your secret addresses together), you can appear as 100 different people each with 1000 KMD. + diff --git a/configure.ac b/configure.ac index a191d35be..7de40ff26 100644 --- a/configure.ac +++ b/configure.ac @@ -232,7 +232,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], - [build zcash-cli zcash-tx (default=yes)])], + [build zcash-cli zcash-tx wallet-utility (default=yes)])], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) @@ -805,7 +805,7 @@ AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (zcash-cli zcash-tx)]) +AC_MSG_CHECKING([whether to build utils (zcash-cli zcash-tx wallet-utility)]) AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) AC_MSG_RESULT($build_bitcoin_utils) @@ -973,7 +973,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" -AC_CONFIG_SUBDIRS([src/secp256k1 src/snark src/univalue]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/snark src/univalue src/cryptoconditions]) AC_OUTPUT 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 diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index b986aecec..0028d3f6f 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -7,19 +7,11 @@ build_darwin_OTOOL: = $(shell xcrun -f otool) build_darwin_NM: = $(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) build_darwin_SHA256SUM = shasum -a 256 -#<<<<<<< HEAD -##build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -f -o +build_darwin_DOWNLOAD = curl --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -L -f -o #darwin host on darwin builder. overrides darwin host preferences. -#darwin_CC= gcc-5 -#darwin_CXX= g++-5 -#======= -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o - -#darwin host on darwin builder. overrides darwin host preferences. -darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) -darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ -#>>>>>>> zcash/master +darwin_CC= gcc-5 +darwin_CXX= g++-5 darwin_AR:=$(shell xcrun -f ar) darwin_RANLIB:=$(shell xcrun -f ranlib) darwin_STRIP:=$(shell xcrun -f strip) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 4f1748657..70211078b 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,15 +1,9 @@ OSX_MIN_VERSION=10.8 OSX_SDK_VERSION=10.11 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk -#<<<<<<< HEAD -#LD64_VERSION=241.9 -#darwin_CC=gcc-5 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -#darwin_CXX=g++-5 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -#======= LD64_VERSION=253.9 -darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -#>>>>>>> zcash/master +darwin_CC=gcc-5 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CXX=g++-5 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 099993a62..8f3fd1b1c 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,17 +1,17 @@ + package=boost -$(package)_version=1_62_0 -$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.62.0 +$(package)_version=1_66_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.66.0/source $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=36c96b0f6155c98404091d8ceb48319a28279ca0333fba1ad8611eb90afb2ca0 -$(package)_patches=deprecated_auto_ptr.patch include_poll.patch +$(package)_sha256_hash=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9 define $(package)_set_vars $(package)_config_opts_release=variant=release $(package)_config_opts_debug=variant=debug -$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam -$(package)_config_opts+=link=static -sNO_BZIP2=1 -sNO_ZLIB=1 +$(package)_config_opts=--layout=system --user-config=user-config.jam +$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1 $(package)_config_opts_linux=threadapi=pthread runtime-link=shared -$(package)_config_opts_darwin=--toolset=gcc threadapi=pthread runtime-link=shared +$(package)_config_opts_darwin=--toolset=gcc runtime-link=shared threadapi=pthread $(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static $(package)_config_opts_x86_64_mingw32=address-model=64 $(package)_config_opts_i686_mingw32=address-model=32 @@ -25,10 +25,9 @@ $(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC endef + define $(package)_preprocess_cmds - echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam && \ - patch -p1 < $($(package)_patch_dir)/deprecated_auto_ptr.patch && \ - patch -p1 < $($(package)_patch_dir)/include_poll.patch + echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam endef define $(package)_config_cmds diff --git a/depends/packages/googletest.mk b/depends/packages/googletest.mk index b9fa3e7e8..1275593f5 100644 --- a/depends/packages/googletest.mk +++ b/depends/packages/googletest.mk @@ -14,7 +14,8 @@ endif ifeq ($(build_os),darwin) $(package)_install=ginstall define $(package)_build_cmds - $(MAKE) -C make gtest.a + $(MAKE) -C googlemock/make gmock.a && \ + $(MAKE) -C googletest/make gtest.a endef else $(package)_install=install diff --git a/depends/packages/libsodium.mk b/depends/packages/libsodium.mk index 91e6f27b7..efa5d90de 100644 --- a/depends/packages/libsodium.mk +++ b/depends/packages/libsodium.mk @@ -1,17 +1,20 @@ +ifeq ($(build_os),darwin) +package=libsodium +$(package)_version=1.0.11 +$(package)_download_path=https://supernetorg.bintray.com/misc +$(package)_file_name=libsodium-1.0.11.tar.gz +$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765 +$(package)_dependencies= +$(package)_config_opts= +else package=libsodium -#<<<<<<< HEAD -#$(package)_version=1.0.11 -#$(package)_download_path=https://supernetorg.bintray.com/misc -#$(package)_file_name=libsodium-1.0.11.tar.gz -#$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765 -#======= $(package)_version=1.0.15 $(package)_download_path=https://download.libsodium.org/libsodium/releases/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4 -#>>>>>>> zcash/master $(package)_dependencies= $(package)_config_opts= +endif define $(package)_preprocess_cmds cd $($(package)_build_subdir); ./autogen.sh diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 3c9eabc88..9174db320 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,11 +1,16 @@ rust_packages := rust librustzcash -proton_packages := proton -zcash_packages := libgmp libsodium +ifeq ($(build_os),darwin) + zcash_packages := libsnark libgmp libsodium +else + proton_packages := proton + zcash_packages := libgmp libsodium +endif + ifeq ($(host_os),linux) packages := boost openssl libevent zeromq $(zcash_packages) googletest #googlemock else - packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock + packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock endif native_packages := native_ccache diff --git a/depends/packages/proton.mk b/depends/packages/proton.mk index aa49f380f..39428f54b 100644 --- a/depends/packages/proton.mk +++ b/depends/packages/proton.mk @@ -1,6 +1,6 @@ package=proton $(package)_version=0.17.0 -$(package)_download_path=http://apache.cs.utah.edu/qpid/proton/$($(package)_version) +$(package)_download_path=https://archive.apache.org/dist/qpid/proton/$($(package)_version) $(package)_file_name=qpid-proton-$($(package)_version).tar.gz $(package)_sha256_hash=6ffd26d3d0e495bfdb5d9fefc5349954e6105ea18cc4bb191161d27742c5a01a $(package)_patches=minimal-build.patch @@ -21,4 +21,3 @@ endef define $(package)_stage_cmds cd build; $(MAKE) VERBOSE=1 DESTDIR=$($(package)_staging_prefix_dir) install endef - diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk index eb28c76d1..2e3f0b204 100644 --- a/depends/packages/rust.mk +++ b/depends/packages/rust.mk @@ -1,23 +1,16 @@ package=rust $(package)_version=1.16.0 $(package)_download_path=https://static.rust-lang.org/dist -#<<<<<<< HEAD -#ifeq ($(build_os),darwin) -#$(package)_file_name=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz -#$(package)_sha256_hash=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926 -#else ifeq ($(host_os),mingw32) -#$(package)_file_name=rust-$($(package)_version)-i686-unknown-linux-gnu.tar.gz -#$(package)_sha256_hash=b5859161ebb182d3b75fa14a5741e5de87b088146fb0ef4a30f3b2439c6179c5 -#else -#$(package)_file_name=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz -#$(package)_sha256_hash=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd -#endif -#======= -$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz -$(package)_sha256_hash_linux=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd -$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz -$(package)_sha256_hash_darwin=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926 -#>>>>>>> zcash/master +ifeq ($(build_os),darwin) +$(package)_file_name=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz +$(package)_sha256_hash=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926 +else ifeq ($(host_os),mingw32) +$(package)_file_name=rust-$($(package)_version)-i686-unknown-linux-gnu.tar.gz +$(package)_sha256_hash=b5859161ebb182d3b75fa14a5741e5de87b088146fb0ef4a30f3b2439c6179c5 +else +$(package)_file_name=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz +$(package)_sha256_hash=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd +endif define $(package)_stage_cmds ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 0ed693951..50de39f64 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -44,6 +44,9 @@ testScripts=( 'key_import_export.py' 'nodehandling.py' 'reindex.py' + 'addressindex.py' + 'timestampindex.py' + 'spentindex.py' 'decodescript.py' 'disablewallet.py' 'zcjoinsplit.py' diff --git a/qa/rpc-tests/addressindex.py b/qa/rpc-tests/addressindex.py new file mode 100644 index 000000000..11fa7ffdb --- /dev/null +++ b/qa/rpc-tests/addressindex.py @@ -0,0 +1,349 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-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. + +# +# Test addressindex generation and fetching +# + +import time +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +import binascii + +class AddressIndexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + # Nodes 0/1 are "wallet" nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-relaypriority=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-addressindex"])) + # Nodes 2/3 are used for testing + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-addressindex", "-relaypriority=0"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-addressindex"])) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(105) + self.sync_all() + + chain_height = self.nodes[1].getblockcount() + assert_equal(chain_height, 105) + assert_equal(self.nodes[1].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 0) + + # Check that balances are correct + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") + assert_equal(balance0["balance"], 0) + + # Check p2pkh and p2sh address indexes + print "Testing p2pkh and p2sh address index..." + + txid0 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 10) + self.nodes[0].generate(1) + + txidb0 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 10) + self.nodes[0].generate(1) + + txid1 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 15) + self.nodes[0].generate(1) + + txidb1 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 15) + self.nodes[0].generate(1) + + txid2 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 20) + self.nodes[0].generate(1) + + txidb2 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 20) + self.nodes[0].generate(1) + + self.sync_all() + + txids = self.nodes[1].getaddresstxids("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs") + assert_equal(len(txids), 3) + assert_equal(txids[0], txid0) + assert_equal(txids[1], txid1) + assert_equal(txids[2], txid2) + + txidsb = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") + assert_equal(len(txidsb), 3) + assert_equal(txidsb[0], txidb0) + assert_equal(txidsb[1], txidb1) + assert_equal(txidsb[2], txidb2) + + # Check that limiting by height works + print "Testing querying txids by range of block heights.." + height_txids = self.nodes[1].getaddresstxids({ + "addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"], + "start": 105, + "end": 110 + }) + assert_equal(len(height_txids), 2) + assert_equal(height_txids[0], txidb0) + assert_equal(height_txids[1], txidb1) + + # Check that multiple addresses works + multitxids = self.nodes[1].getaddresstxids({"addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs"]}) + assert_equal(len(multitxids), 6) + assert_equal(multitxids[0], txid0) + assert_equal(multitxids[1], txidb0) + assert_equal(multitxids[2], txid1) + assert_equal(multitxids[3], txidb1) + assert_equal(multitxids[4], txid2) + assert_equal(multitxids[5], txidb2) + + # Check that balances are correct + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") + assert_equal(balance0["balance"], 45 * 100000000) + + # Check that outputs with the same address will only return one txid + print "Testing for txid uniqueness..." + addressHash = "6349a418fc4578d10a372b54b45c280cc8c4382f".decode("hex") + scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL]) + unspent = self.nodes[0].listunspent() + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] + tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)] + tx.rehash() + + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + + self.nodes[0].generate(1) + self.sync_all() + + txidsmany = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") + assert_equal(len(txidsmany), 4) + assert_equal(txidsmany[3], sent_txid) + + # Check that balances are correct + print "Testing balances..." + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") + assert_equal(balance0["balance"], 45 * 100000000 + 21) + + # Check that balances are correct after spending + print "Testing balances after spending..." + privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" + address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" + addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex") + scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG]) + self.nodes[0].importprivkey(privkey2) + + unspent = self.nodes[0].listunspent() + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] + amount = unspent[0]["amount"] * 100000000 + tx.vout = [CTxOut(amount, scriptPubKey2)] + tx.rehash() + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + spending_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + self.nodes[0].generate(1) + self.sync_all() + balance1 = self.nodes[1].getaddressbalance(address2) + assert_equal(balance1["balance"], amount) + + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] + send_amount = 1 * 100000000 + 12840 + change_amount = amount - send_amount - 10000 + tx.vout = [CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey)] + tx.rehash() + + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + self.nodes[0].generate(1) + self.sync_all() + + balance2 = self.nodes[1].getaddressbalance(address2) + assert_equal(balance2["balance"], change_amount) + + # Check that deltas are returned correctly + deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 1, "end": 200}) + balance3 = 0 + for delta in deltas: + balance3 += delta["satoshis"] + assert_equal(balance3, change_amount) + assert_equal(deltas[0]["address"], address2) + assert_equal(deltas[0]["blockindex"], 1) + + # Check that entire range will be queried + deltasAll = self.nodes[1].getaddressdeltas({"addresses": [address2]}) + assert_equal(len(deltasAll), len(deltas)) + + # Check that deltas can be returned from range of block heights + deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 113, "end": 113}) + assert_equal(len(deltas), 1) + + # Check that unspent outputs can be queried + print "Testing utxos..." + utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) + assert_equal(len(utxos), 1) + assert_equal(utxos[0]["satoshis"], change_amount) + + # Check that indexes will be updated with a reorg + print "Testing reorg..." + + best_hash = self.nodes[0].getbestblockhash() + self.nodes[0].invalidateblock(best_hash) + self.nodes[1].invalidateblock(best_hash) + self.nodes[2].invalidateblock(best_hash) + self.nodes[3].invalidateblock(best_hash) + self.sync_all() + + balance4 = self.nodes[1].getaddressbalance(address2) + assert_equal(balance4, balance1) + + utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) + assert_equal(len(utxos2), 1) + assert_equal(utxos2[0]["satoshis"], amount) + + # Check sorting of utxos + self.nodes[2].generate(150) + + txidsort1 = self.nodes[2].sendtoaddress(address2, 50) + self.nodes[2].generate(1) + txidsort2 = self.nodes[2].sendtoaddress(address2, 50) + self.nodes[2].generate(1) + self.sync_all() + + utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) + assert_equal(len(utxos3), 3) + assert_equal(utxos3[0]["height"], 114) + assert_equal(utxos3[1]["height"], 264) + assert_equal(utxos3[2]["height"], 265) + + # Check mempool indexing + print "Testing mempool indexing..." + + privKey3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" + address3 = "mw4ynwhS7MmrQ27hr82kgqu7zryNDK26JB" + addressHash3 = "aa9872b5bbcdb511d89e0e11aa27da73fd2c3f50".decode("hex") + scriptPubKey3 = CScript([OP_DUP, OP_HASH160, addressHash3, OP_EQUALVERIFY, OP_CHECKSIG]) + address4 = "2N8oFVB2vThAKury4vnLquW2zVjsYjjAkYQ" + scriptPubKey4 = CScript([OP_HASH160, addressHash3, OP_EQUAL]) + unspent = self.nodes[2].listunspent() + + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] + amount = unspent[0]["amount"] * 100000000 + tx.vout = [CTxOut(amount, scriptPubKey3)] + tx.rehash() + signed_tx = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + memtxid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) + time.sleep(2) + + tx2 = CTransaction() + tx2.vin = [CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"]))] + amount = unspent[1]["amount"] * 100000000 + tx2.vout = [ + CTxOut(amount / 4, scriptPubKey3), + CTxOut(amount / 4, scriptPubKey3), + CTxOut(amount / 4, scriptPubKey4), + CTxOut(amount / 4, scriptPubKey4) + ] + tx2.rehash() + signed_tx2 = self.nodes[2].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8")) + memtxid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) + time.sleep(2) + + mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) + assert_equal(len(mempool), 3) + assert_equal(mempool[0]["txid"], memtxid1) + assert_equal(mempool[0]["address"], address3) + assert_equal(mempool[0]["index"], 0) + assert_equal(mempool[1]["txid"], memtxid2) + assert_equal(mempool[1]["index"], 0) + assert_equal(mempool[2]["txid"], memtxid2) + assert_equal(mempool[2]["index"], 1) + + self.nodes[2].generate(1); + self.sync_all(); + mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) + assert_equal(len(mempool2), 0) + + tx = CTransaction() + tx.vin = [ + CTxIn(COutPoint(int(memtxid2, 16), 0)), + CTxIn(COutPoint(int(memtxid2, 16), 1)) + ] + tx.vout = [CTxOut(amount / 2 - 10000, scriptPubKey2)] + tx.rehash() + self.nodes[2].importprivkey(privKey3) + signed_tx3 = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + memtxid3 = self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) + time.sleep(2) + + mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) + assert_equal(len(mempool3), 2) + assert_equal(mempool3[0]["prevtxid"], memtxid2) + assert_equal(mempool3[0]["prevout"], 0) + assert_equal(mempool3[1]["prevtxid"], memtxid2) + assert_equal(mempool3[1]["prevout"], 1) + + # sending and receiving to the same address + privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8" + address1 = "myAUWSHnwsQrhuMWv4Br6QsCnpB41vFwHn" + address1hash = "c192bff751af8efec15135d42bfeedf91a6f3e34".decode("hex") + address1script = CScript([OP_DUP, OP_HASH160, address1hash, OP_EQUALVERIFY, OP_CHECKSIG]) + + self.nodes[0].sendtoaddress(address1, 10) + self.nodes[0].generate(1) + self.sync_all() + + utxos = self.nodes[1].getaddressutxos({"addresses": [address1]}) + assert_equal(len(utxos), 1) + + tx = CTransaction() + tx.vin = [ + CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"])) + ] + amount = utxos[0]["satoshis"] - 1000 + tx.vout = [CTxOut(amount, address1script)] + tx.rehash() + self.nodes[0].importprivkey(privkey1) + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + mem_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + + self.sync_all() + mempool_deltas = self.nodes[2].getaddressmempool({"addresses": [address1]}) + assert_equal(len(mempool_deltas), 2) + + # Include chaininfo in results + print "Testing results with chain info..." + + deltas_with_info = self.nodes[1].getaddressdeltas({ + "addresses": [address2], + "start": 1, + "end": 200, + "chainInfo": True + }) + start_block_hash = self.nodes[1].getblockhash(1); + end_block_hash = self.nodes[1].getblockhash(200); + assert_equal(deltas_with_info["start"]["height"], 1) + assert_equal(deltas_with_info["start"]["hash"], start_block_hash) + assert_equal(deltas_with_info["end"]["height"], 200) + assert_equal(deltas_with_info["end"]["hash"], end_block_hash) + + utxos_with_info = self.nodes[1].getaddressutxos({"addresses": [address2], "chainInfo": True}) + expected_tip_block_hash = self.nodes[1].getblockhash(267); + assert_equal(utxos_with_info["height"], 267) + assert_equal(utxos_with_info["hash"], expected_tip_block_hash) + + print "Passed\n" + + +if __name__ == '__main__': + AddressIndexTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/spentindex.py b/qa/rpc-tests/spentindex.py new file mode 100644 index 000000000..ebe2b8cc2 --- /dev/null +++ b/qa/rpc-tests/spentindex.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-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. + +# +# Test addressindex generation and fetching +# + +import time +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +import binascii + +class SpentIndexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + # Nodes 0/1 are "wallet" nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-spentindex"])) + # Nodes 2/3 are used for testing + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-spentindex"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-spentindex", "-txindex"])) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(105) + self.sync_all() + + chain_height = self.nodes[1].getblockcount() + assert_equal(chain_height, 105) + + # Check that + print "Testing spent index..." + + privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" + address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" + addressHash = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex") + scriptPubKey = CScript([OP_DUP, OP_HASH160, addressHash, OP_EQUALVERIFY, OP_CHECKSIG]) + unspent = self.nodes[0].listunspent() + tx = CTransaction() + amount = unspent[0]["amount"] * 100000000 + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] + tx.vout = [CTxOut(amount, scriptPubKey)] + tx.rehash() + + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + self.nodes[0].generate(1) + self.sync_all() + + print "Testing getspentinfo method..." + + # Check that the spentinfo works standalone + info = self.nodes[1].getspentinfo({"txid": unspent[0]["txid"], "index": unspent[0]["vout"]}) + assert_equal(info["txid"], txid) + assert_equal(info["index"], 0) + assert_equal(info["height"], 106) + + print "Testing getrawtransaction method..." + + # Check that verbose raw transaction includes spent info + txVerbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) + assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentTxId"], txid) + assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentIndex"], 0) + assert_equal(txVerbose["vout"][unspent[0]["vout"]]["spentHeight"], 106) + + # Check that verbose raw transaction includes input values + txVerbose2 = self.nodes[3].getrawtransaction(txid, 1) + assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"])) + assert_equal(txVerbose2["vin"][0]["valueSat"], amount) + + # Check that verbose raw transaction includes address values and input values + privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" + address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" + addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex") + scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG]) + tx2 = CTransaction() + tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))] + tx2.vout = [CTxOut(amount, scriptPubKey2)] + tx.rehash() + self.nodes[0].importprivkey(privkey) + signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8")) + txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True) + + # Check the mempool index + self.sync_all() + txVerbose3 = self.nodes[1].getrawtransaction(txid2, 1) + assert_equal(txVerbose3["vin"][0]["address"], address2) + assert_equal(txVerbose3["vin"][0]["value"], Decimal(unspent[0]["amount"])) + assert_equal(txVerbose3["vin"][0]["valueSat"], amount) + + # Check the database index + block_hash = self.nodes[0].generate(1) + self.sync_all() + + txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1) + assert_equal(txVerbose4["vin"][0]["address"], address2) + assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"])) + assert_equal(txVerbose4["vin"][0]["valueSat"], amount) + + + # Check block deltas + print "Testing getblockdeltas..." + + block = self.nodes[3].getblockdeltas(block_hash[0]) + assert_equal(len(block["deltas"]), 2) + assert_equal(block["deltas"][0]["index"], 0) + assert_equal(len(block["deltas"][0]["inputs"]), 0) + assert_equal(len(block["deltas"][0]["outputs"]), 0) + assert_equal(block["deltas"][1]["index"], 1) + assert_equal(block["deltas"][1]["txid"], txid2) + assert_equal(block["deltas"][1]["inputs"][0]["index"], 0) + assert_equal(block["deltas"][1]["inputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") + assert_equal(block["deltas"][1]["inputs"][0]["satoshis"], amount * -1) + assert_equal(block["deltas"][1]["inputs"][0]["prevtxid"], txid) + assert_equal(block["deltas"][1]["inputs"][0]["prevout"], 0) + assert_equal(block["deltas"][1]["outputs"][0]["index"], 0) + assert_equal(block["deltas"][1]["outputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") + assert_equal(block["deltas"][1]["outputs"][0]["satoshis"], amount) + + print "Passed\n" + + +if __name__ == '__main__': + SpentIndexTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/timestampindex.py b/qa/rpc-tests/timestampindex.py new file mode 100644 index 000000000..23244159f --- /dev/null +++ b/qa/rpc-tests/timestampindex.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-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. + +# +# Test timestampindex generation and fetching +# + +import time + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + + +class TimestampIndexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + # Nodes 0/1 are "wallet" nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-timestampindex"])) + # Nodes 2/3 are used for testing + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-timestampindex"])) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + print "Mining 25 blocks..." + blockhashes = self.nodes[0].generate(25) + time.sleep(3) + print "Mining 25 blocks..." + blockhashes.extend(self.nodes[0].generate(25)) + time.sleep(3) + print "Mining 25 blocks..." + blockhashes.extend(self.nodes[0].generate(25)) + self.sync_all() + low = self.nodes[1].getblock(blockhashes[0])["time"] + high = low + 76 + + print "Checking timestamp index..." + hashes = self.nodes[1].getblockhashes(high, low) + + assert_equal(len(hashes), len(blockhashes)) + + assert_equal(hashes, blockhashes) + + print "Passed\n" + + +if __name__ == '__main__': + TimestampIndexTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/txindex.py b/qa/rpc-tests/txindex.py new file mode 100644 index 000000000..e59b6d7d9 --- /dev/null +++ b/qa/rpc-tests/txindex.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014-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. + +# +# Test txindex generation and fetching +# + +import time +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from test_framework.script import * +from test_framework.mininode import * +import binascii + +class TxIndexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self): + self.nodes = [] + # Nodes 0/1 are "wallet" nodes + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-txindex"])) + # Nodes 2/3 are used for testing + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-txindex"])) + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"])) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) + + self.is_network_split = False + self.sync_all() + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(105) + self.sync_all() + + chain_height = self.nodes[1].getblockcount() + assert_equal(chain_height, 105) + + print "Testing transaction index..." + + privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" + address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" + addressHash = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex") + scriptPubKey = CScript([OP_DUP, OP_HASH160, addressHash, OP_EQUALVERIFY, OP_CHECKSIG]) + unspent = self.nodes[0].listunspent() + tx = CTransaction() + amount = unspent[0]["amount"] * 100000000 + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] + tx.vout = [CTxOut(amount, scriptPubKey)] + tx.rehash() + + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) + txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) + self.nodes[0].generate(1) + self.sync_all() + + # Check verbose raw transaction results + verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) + assert_equal(verbose["vout"][0]["valueSat"], 5000000000); + assert_equal(verbose["vout"][0]["value"], 50); + + print "Passed\n" + + +if __name__ == '__main__': + TxIndexTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/wallet_mergetoaddress.py b/qa/rpc-tests/wallet_mergetoaddress.py index ff3534e9b..e5d5089a4 100755 --- a/qa/rpc-tests/wallet_mergetoaddress.py +++ b/qa/rpc-tests/wallet_mergetoaddress.py @@ -324,13 +324,27 @@ 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 + + # 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')) # 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 +354,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]) 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/qa/zcash/create_wallet_200k_utxos.py b/qa/zcash/create_wallet_200k_utxos.py old mode 100755 new mode 100644 diff --git a/qa/zcash/full-test-suite.sh b/qa/zcash/full-test-suite.sh new file mode 100755 index 000000000..af4fb2791 --- /dev/null +++ b/qa/zcash/full-test-suite.sh @@ -0,0 +1,201 @@ +#!/usr/bin/env python2 +# +# Execute all of the automated tests related to Zcash. +# + +import argparse +import os +import re +import subprocess +import sys + +REPOROOT = os.path.dirname( + os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) +) + +def repofile(filename): + return os.path.join(REPOROOT, filename) + + +# +# Custom test runners +# + +RE_RPATH_RUNPATH = re.compile('No RPATH.*No RUNPATH') +RE_FORTIFY_AVAILABLE = re.compile('FORTIFY_SOURCE support available.*Yes') +RE_FORTIFY_USED = re.compile('Binary compiled with FORTIFY_SOURCE support.*Yes') + +def test_rpath_runpath(filename): + output = subprocess.check_output( + [repofile('qa/zcash/checksec.sh'), '--file', repofile(filename)] + ) + if RE_RPATH_RUNPATH.search(output): + print('PASS: %s has no RPATH or RUNPATH.' % filename) + return True + else: + print('FAIL: %s has an RPATH or a RUNPATH.' % filename) + print(output) + return False + +def test_fortify_source(filename): + proc = subprocess.Popen( + [repofile('qa/zcash/checksec.sh'), '--fortify-file', repofile(filename)], + stdout=subprocess.PIPE, + ) + line1 = proc.stdout.readline() + line2 = proc.stdout.readline() + proc.terminate() + if RE_FORTIFY_AVAILABLE.search(line1) and RE_FORTIFY_USED.search(line2): + print('PASS: %s has FORTIFY_SOURCE.' % filename) + return True + else: + print('FAIL: %s is missing FORTIFY_SOURCE.' % filename) + return False + +def check_security_hardening(): + ret = True + + # PIE, RELRO, Canary, and NX are tested by make check-security. + ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0 + + ret &= test_rpath_runpath('src/zcashd') + ret &= test_rpath_runpath('src/zcash-cli') + ret &= test_rpath_runpath('src/zcash-gtest') + ret &= test_rpath_runpath('src/zcash-tx') + ret &= test_rpath_runpath('src/test/test_bitcoin') + ret &= test_rpath_runpath('src/zcash/GenerateParams') + + # NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE + # is enabled for the entire binary. See issue #915. + ret &= test_fortify_source('src/zcashd') + ret &= test_fortify_source('src/zcash-cli') + ret &= test_fortify_source('src/zcash-gtest') + ret &= test_fortify_source('src/zcash-tx') + ret &= test_fortify_source('src/test/test_bitcoin') + ret &= test_fortify_source('src/zcash/GenerateParams') + + return ret + +def ensure_no_dot_so_in_depends(): + arch_dir = os.path.join( + REPOROOT, + 'depends', + 'x86_64-unknown-linux-gnu', + ) + + exit_code = 0 + + if os.path.isdir(arch_dir): + lib_dir = os.path.join(arch_dir, 'lib') + libraries = os.listdir(lib_dir) + + for lib in libraries: + if lib.find(".so") != -1: + print lib + exit_code = 1 + else: + exit_code = 2 + print "arch-specific build dir not present: {}".format(arch_dir) + print "Did you build the ./depends tree?" + print "Are you on a currently unsupported architecture?" + + if exit_code == 0: + print "PASS." + else: + print "FAIL." + + return exit_code == 0 + +def util_test(): + return subprocess.call( + [repofile('src/test/bitcoin-util-test.py')], + cwd=repofile('src'), + env={'PYTHONPATH': repofile('src/test'), 'srcdir': repofile('src')} + ) == 0 + + +# +# Tests +# + +STAGES = [ + 'btest', + 'gtest', + 'sec-hard', + 'no-dot-so', + 'util-test', + 'secp256k1', + 'libsnark', + 'univalue', + 'rpc', +] + +STAGE_COMMANDS = { + 'btest': [repofile('src/test/test_bitcoin'), '-p'], + 'gtest': [repofile('src/zcash-gtest')], + 'sec-hard': check_security_hardening, + 'no-dot-so': ensure_no_dot_so_in_depends, + 'util-test': util_test, + 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], + 'libsnark': ['make', '-C', repofile('src'), 'libsnark-tests'], + 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], + 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], +} + + +# +# Test driver +# + +def run_stage(stage): + print('Running stage %s' % stage) + print('=' * (len(stage) + 14)) + print + + cmd = STAGE_COMMANDS[stage] + if type(cmd) == type([]): + ret = subprocess.call(cmd) == 0 + else: + ret = cmd() + + print + print('-' * (len(stage) + 15)) + print('Finished stage %s' % stage) + print + + return ret + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--list-stages', dest='list', action='store_true') + parser.add_argument('stage', nargs='*', default=STAGES, + help='One of %s'%STAGES) + args = parser.parse_args() + + # Check for list + if args.list: + for s in STAGES: + print(s) + sys.exit(0) + + # Check validity of stages + for s in args.stage: + if s not in STAGES: + print("Invalid stage '%s' (choose from %s)" % (s, STAGES)) + sys.exit(1) + + # Run the stages + passed = True + for s in args.stage: + passed &= run_stage(s) + + if not passed: + print("!!! One or more test stages failed !!!") + sys.exit(1) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/qa/zcash/performance-measurements.sh b/qa/zcash/performance-measurements.sh index 15f3077b5..3370bd20f 100755 --- a/qa/zcash/performance-measurements.sh +++ b/qa/zcash/performance-measurements.sh @@ -338,4 +338,4 @@ case "$1" in esac # Cleanup -rm -rf "$DATADIR" +rm -rf "$DATADIR" \ No newline at end of file diff --git a/qa/zcash/test-depends-sources-mirror.py b/qa/zcash/test-depends-sources-mirror.py index e09c2c238..6b612d715 100755 --- a/qa/zcash/test-depends-sources-mirror.py +++ b/qa/zcash/test-depends-sources-mirror.py @@ -40,4 +40,4 @@ for filename in get_depends_sources_list(): sys.exit(1) print "PASS." -sys.exit(0) +sys.exit(0) \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 614952fff..7355d17d2 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) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) @@ -23,6 +23,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 BITCOIN_INCLUDES += -I$(srcdir)/snark BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark BITCOIN_INCLUDES += -I$(srcdir)/univalue/include @@ -43,6 +44,7 @@ LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBVERUS_CRYPTO=crypto/libverus_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la +LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -lcurl @@ -65,6 +67,9 @@ libsnark-tests: $(wildcard snark/src/*) $(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 = \ @@ -97,13 +102,17 @@ bin_PROGRAMS = noinst_PROGRAMS = TESTS = -if BUILD_BITCOIND +#if BUILD_BITCOIND bin_PROGRAMS += komodod -endif +#endif if BUILD_BITCOIN_UTILS bin_PROGRAMS += komodo-cli komodo-tx endif +if ENABLE_WALLET + bin_PROGRAMS += wallet-utility +endif + LIBZCASH_H = \ zcash/IncrementalMerkleTree.hpp \ @@ -119,6 +128,8 @@ LIBZCASH_H = \ .PHONY: FORCE collate-libsnark check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ + addressindex.h \ + spentindex.h \ addrman.h \ alert.h \ amount.h \ @@ -132,6 +143,7 @@ BITCOIN_CORE_H = \ asyncrpcqueue.h \ base58.h \ bloom.h \ + cc/eval.h \ chain.h \ chainparams.h \ chainparamsbase.h \ @@ -188,7 +200,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 \ @@ -232,7 +244,7 @@ BITCOIN_CORE_H = \ obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ - $(abs_top_srcdir) + $(abs_top_srcdir) libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: zcashd @@ -246,6 +258,10 @@ libbitcoin_server_a_SOURCES = \ asyncrpcoperation.cpp \ asyncrpcqueue.cpp \ bloom.cpp \ + cc/eval.cpp \ + cc/importpayout.cpp \ + cc/disputepayout.cpp \ + cc/betprotocol.cpp \ chain.cpp \ checkpoints.cpp \ deprecation.cpp \ @@ -270,7 +286,7 @@ libbitcoin_server_a_SOURCES = \ rpcnet.cpp \ rpcrawtransaction.cpp \ rpcserver.cpp \ - script/sigcache.cpp \ + script/serverchecker.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ @@ -285,9 +301,9 @@ LIBBITCOIN_ZMQ=libbitcoin_zmq.a libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ - zmq/zmqabstractnotifier.cpp \ - zmq/zmqnotificationinterface.cpp \ - zmq/zmqpublishnotifier.cpp + zmq/zmqabstractnotifier.cpp \ + zmq/zmqnotificationinterface.cpp \ + zmq/zmqpublishnotifier.cpp endif if ENABLE_PROTON @@ -350,14 +366,14 @@ crypto_libbitcoin_crypto_a_SOURCES = \ if ENABLE_MINING EQUIHASH_TROMP_SOURCES = \ - pow/tromp/equi_miner.h \ - pow/tromp/equi.h \ - pow/tromp/osx_barrier.h + pow/tromp/equi_miner.h \ + pow/tromp/equi.h \ + pow/tromp/osx_barrier.h crypto_libbitcoin_crypto_a_CPPFLAGS += \ - -DEQUIHASH_TROMP_ATOMIC + -DEQUIHASH_TROMP_ATOMIC crypto_libbitcoin_crypto_a_SOURCES += \ - ${EQUIHASH_TROMP_SOURCES} + ${EQUIHASH_TROMP_SOURCES} endif # Verus hash specific library @@ -389,6 +405,7 @@ libbitcoin_common_a_SOURCES = \ protocol.cpp \ pubkey.cpp \ scheduler.cpp \ + script/cc.cpp \ script/interpreter.cpp \ script/script.cpp \ script/script_ext.cpp \ @@ -404,23 +421,23 @@ libbitcoin_common_a_SOURCES = \ libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ - support/pagelocker.cpp \ - chainparamsbase.cpp \ - clientversion.cpp \ - compat/glibc_sanity.cpp \ - compat/glibcxx_sanity.cpp \ - compat/strnlen.cpp \ - random.cpp \ - rpcprotocol.cpp \ - support/cleanse.cpp \ - sync.cpp \ - uint256.cpp \ - util.cpp \ - utilmoneystr.cpp \ - utilstrencodings.cpp \ - utiltime.cpp \ - $(BITCOIN_CORE_H) \ - $(LIBZCASH_H) + support/pagelocker.cpp \ + chainparamsbase.cpp \ + clientversion.cpp \ + compat/glibc_sanity.cpp \ + compat/glibcxx_sanity.cpp \ + compat/strnlen.cpp \ + random.cpp \ + rpcprotocol.cpp \ + support/cleanse.cpp \ + sync.cpp \ + uint256.cpp \ + util.cpp \ + utilmoneystr.cpp \ + utilstrencodings.cpp \ + utiltime.cpp \ + $(BITCOIN_CORE_H) \ + $(LIBZCASH_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp @@ -430,9 +447,9 @@ endif libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ - rpcclient.cpp \ - $(BITCOIN_CORE_H) \ - $(LIBZCASH_H) + rpcclient.cpp \ + $(BITCOIN_CORE_H) \ + $(LIBZCASH_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # @@ -458,7 +475,8 @@ komodod_LDADD = \ $(LIBSNARK) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBCRYPTOCONDITIONS) if ENABLE_ZMQ komodod_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) @@ -489,23 +507,46 @@ komodo_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) komodo_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) komodo_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +# wallet-utility binary # +if ENABLE_WALLET +wallet_utility_SOURCES = wallet-utility.cpp +wallet_utility_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +wallet_utility_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +wallet_utility_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +endif + if TARGET_WINDOWS komodo_cli_SOURCES += bitcoin-cli-res.rc endif komodo_cli_LDADD = \ - $(LIBBITCOIN_CLI) \ - $(LIBUNIVALUE) \ - $(LIBBITCOIN_UTIL) \ - $(BOOST_LIBS) \ - $(SSL_LIBS) \ - $(CRYPTO_LIBS) \ - $(EVENT_LIBS) \ - $(LIBZCASH) \ - $(LIBSNARK) \ - $(LIBBITCOIN_CRYPTO) \ - $(LIBZCASH_LIBS) -# + $(LIBBITCOIN_CLI) \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_UTIL) \ + $(BOOST_LIBS) \ + $(SSL_LIBS) \ + $(CRYPTO_LIBS) \ + $(EVENT_LIBS) \ + $(LIBZCASH) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBZCASH_LIBS) + +if ENABLE_WALLET +wallet_utility_LDADD = \ + libbitcoin_wallet.a \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBSECP256K1) \ + $(LIBBITCOIN_UTIL) \ + $(BOOST_LIBS) \ + $(BDB_LIBS) \ + $(CRYPTO_LIBS) \ + $(LIBZCASH) \ + $(LIBSNARK) \ + $(LIBZCASH_LIBS)\ + $(LIBCRYPTOCONDITIONS) +endif # zcash-tx binary # komodo_tx_SOURCES = komodo-tx.cpp @@ -527,27 +568,28 @@ komodo_tx_LDADD = \ $(LIBSNARK) \ $(LIBBITCOIN_CRYPTO) \ $(LIBVERUS_CRYPTO) \ - $(LIBZCASH_LIBS) + $(LIBZCASH_LIBS) \ + $(LIBCRYPTOCONDITIONS) komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # # zcash protocol primitives # libzcash_a_SOURCES = \ - zcash/IncrementalMerkleTree.cpp \ - zcash/NoteEncryption.cpp \ - zcash/Address.cpp \ - zcash/JoinSplit.cpp \ - zcash/Proof.cpp \ - zcash/Note.cpp \ - zcash/prf.cpp \ - zcash/util.cpp \ - zcash/circuit/commitment.tcc \ - zcash/circuit/gadget.tcc \ - zcash/circuit/merkle.tcc \ - zcash/circuit/note.tcc \ - zcash/circuit/prfs.tcc \ - zcash/circuit/utils.tcc + zcash/IncrementalMerkleTree.cpp \ + zcash/NoteEncryption.cpp \ + zcash/Address.cpp \ + zcash/JoinSplit.cpp \ + zcash/Proof.cpp \ + zcash/Note.cpp \ + zcash/prf.cpp \ + zcash/util.cpp \ + zcash/circuit/commitment.tcc \ + zcash/circuit/gadget.tcc \ + zcash/circuit/merkle.tcc \ + zcash/circuit/note.tcc \ + zcash/circuit/prfs.tcc \ + zcash/circuit/utils.tcc libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES) @@ -575,7 +617,7 @@ libzcashconsensus_la_SOURCES = \ utilstrencodings.cpp if GLIBC_BACK_COMPAT - libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp +libzcashconsensus_la_SOURCES += compat/glibc_compat.cpp endif libzcashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) @@ -623,9 +665,10 @@ endif @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(::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/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/assetchains_stop b/src/assetchains_stop new file mode 100644 index 000000000..29e1ab325 --- /dev/null +++ b/src/assetchains_stop @@ -0,0 +1,40 @@ +#!/bin/bash +args=("$@") +komodo_cli='./komodo-cli' +delay=20 + +function komodo_stop () +{ + $komodo_cli --ac_name=$1 stop +} + +#set -x + +komodo_stop REVS +komodo_stop SUPERNET +komodo_stop DEX +komodo_stop PANGEA +komodo_stop JUMBLR +komodo_stop BET +komodo_stop CRYPTO +komodo_stop HODL +komodo_stop MSHARK +komodo_stop BOTS +komodo_stop MGW +komodo_stop COQUI +komodo_stop WLC +komodo_stop KV +komodo_stop CEAL +komodo_stop MESH +komodo_stop MNZ +komodo_stop AXO +komodo_stop ETOMIC +komodo_stop BTCH +komodo_stop VOTE2018 +komodo_stop PIZZA +komodo_stop BEER +komodo_stop NINJA +komodo_stop OOT +komodo_stop BNTN +komodo_stop CHAIN +komodo_stop PRLPAY diff --git a/src/base58.cpp b/src/base58.cpp index c9c64bc58..c086cc854 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -275,6 +275,23 @@ CTxDestination CBitcoinAddress::Get() const return CNoDestination(); } +bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const +{ + if (!IsValid()) { + return false; + } else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) { + memcpy(&hashBytes, &vchData[0], 20); + type = 1; + return true; + } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { + memcpy(&hashBytes, &vchData[0], 20); + type = 2; + return true; + } + + return false; +} + bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const { if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) diff --git a/src/base58.h b/src/base58.h index 24e7abfc8..73e1c4d94 100644 --- a/src/base58.h +++ b/src/base58.h @@ -163,6 +163,7 @@ public: CTxDestination Get() const; bool GetKeyID(CKeyID &keyID) const; + bool GetIndexKey(uint160& hashBytes, int& type) const; bool IsScript() const; }; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 178f0baed..bf189e483 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -202,7 +202,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) { std::string host = GetArg("-rpcconnect", "127.0.0.1"); int port = GetArg("-rpcport", BaseParams().RPCPort()); - BITCOIND_PORT = port; + BITCOIND_RPCPORT = port; // Obtain event base raii_event_base base = obtain_event_base(); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index bf4934da4..5c12cfa2f 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -45,6 +45,8 @@ static bool fDaemon; #define KOMODO_ASSETCHAIN_MAXLEN 65 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; void komodo_passport_iteration(); +uint64_t komodo_interestsum(); +int32_t komodo_longestchain(); void WaitForShutdown(boost::thread_group* threadGroup) { @@ -56,8 +58,14 @@ void WaitForShutdown(boost::thread_group* threadGroup) if ( ASSETCHAINS_SYMBOL[0] == 0 ) { komodo_passport_iteration(); - MilliSleep(1000); - } else MilliSleep(1000); + MilliSleep(10000); + } + else + { + komodo_interestsum(); + komodo_longestchain(); + MilliSleep(20000); + } fShutdown = ShutdownRequested(); } if (threadGroup) @@ -125,7 +133,7 @@ bool AppInit(int argc, char* argv[]) sleep(1); #endif } - printf("initialized %s\n",ASSETCHAINS_SYMBOL); + printf("initialized %s at %u\n",ASSETCHAINS_SYMBOL,(uint32_t)time(NULL)); if (!boost::filesystem::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); diff --git a/src/cJSON.h b/src/cJSON.h index fb8971575..1e388137e 100644 --- a/src/cJSON.h +++ b/src/cJSON.h @@ -20,14 +20,6 @@ THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include - #ifndef cJSON__h #define cJSON__h diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp new file mode 100644 index 000000000..53b79176c --- /dev/null +++ b/src/cc/betprotocol.cpp @@ -0,0 +1,139 @@ +#include + +#include "streams.h" +#include "script/cc.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" + + +std::vector BetProtocol::PlayerConditions() +{ + std::vector subs; + for (int i=0; i result(vmResultHash.begin(), vmResultHash.begin()+32); + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result)); + return mtx; +} + + +CMutableTransaction BetProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, + int playerIdx, std::vector state) +{ + CMutableTransaction mtx; + + mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CScript())); + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); + + return mtx; +} + + +CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash) +{ + // TODO: 2/3 majority + CC* agree = CCNewThreshold(players.size(), PlayerConditions()); + + CC *import; + { + CC *importEval = CCNewEval(E_MARSHAL( + ss << EVAL_IMPORTPAYOUT << signedSessionTxHash; + )); + + CC *oneof = CCNewThreshold(1, PlayerConditions()); + + import = CCNewThreshold(2, {oneof, importEval}); + } + + return CCNewThreshold(1, {agree, import}); +} + + +CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signedSessionTxHash) +{ + CMutableTransaction mtx; + + CC *payoutCond = MakePayoutCond(signedSessionTxHash); + mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); + cc_free(payoutCond); + + return mtx; +} + + +CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector payouts, + uint256 signedStakeTxHash) +{ + CMutableTransaction mtx; + mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); + mtx.vout = payouts; + return mtx; +} + + +CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector payouts, + CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof) +{ + CMutableTransaction mtx; + mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); + mtx.vout = payouts; + CScript proofData; + proofData << OP_RETURN << E_MARSHAL(ss << 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 new file mode 100644 index 000000000..b08783b85 --- /dev/null +++ b/src/cc/betprotocol.h @@ -0,0 +1,68 @@ +#ifndef BETPROTOCOL_H +#define BETPROTOCOL_H + +#include "cc/eval.h" +#include "pubkey.h" +#include "primitives/block.h" +#include "primitives/transaction.h" +#include "cryptoconditions/include/cryptoconditions.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) {} + uint256 Exec(uint256 hash) const { return CBlock::CheckMerkleBranch(hash, branch, nIndex); } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nIndex)); + READWRITE(branch); + READWRITE(notarisationHash); + } +}; + + +class BetProtocol +{ +protected: + std::vector playerConditions(); +public: + EvalCode disputeCode; + std::vector players; + std::vector vmParams; + uint32_t waitBlocks; + + // Utility + 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 + CC* MakeDisputeCond(); + CMutableTransaction MakeSessionTx(CAmount spendFee); + 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); +}; + + + +bool GetOpReturnHash(CScript script, uint256 &hash); + + +#endif /* BETPROTOCOL_H */ diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp new file mode 100644 index 000000000..610342274 --- /dev/null +++ b/src/cc/disputepayout.cpp @@ -0,0 +1,84 @@ +#include + +#include "hash.h" +#include "chain.h" +#include "version.h" +#include "script/cc.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" + + +/* + * Crypto-Condition EVAL method that resolves a dispute of a session + * + * IN: vm - AppVM virtual machine to verify states + * IN: params - condition params + * 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 Eval::DisputePayout(AppVM &vm, std::vector params, const CTransaction &disputeTx, unsigned int nIn) +{ + if (disputeTx.vout.size() == 0) return Invalid("no-vouts"); + + // get payouts hash + uint256 payoutHash; + if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash)) + return Invalid("invalid-payout-hash"); + + // 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 + { + 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 + waitBlocks) + return Invalid("dispute-too-soon"); // Not yet + } + + // get spends + std::vector spends; + if (!GetSpendsConfirmed(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 vmState; + 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); + if (out.first > maxLength) { + maxLength = out.first; + bestPayout = resultHash; + } + // 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"); + bestPayout = resultHash; + } + } + } + + 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 new file mode 100644 index 000000000..3c53f9866 --- /dev/null +++ b/src/cc/eval.cpp @@ -0,0 +1,205 @@ +#include +#include + +#include "primitives/transaction.h" +#include "script/cc.h" +#include "cc/eval.h" +#include "main.h" +#include "chain.h" +#include "core_io.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 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; +} + + +/* + * Test the validity of an Eval node + */ +bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) +{ + 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); + } + + return Invalid("invalid-code"); +} + + +bool Eval::GetSpendsConfirmed(uint256 hash, std::vector &spends) const +{ + // NOT IMPLEMENTED + return false; +} + + +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(); +} + + +bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const +{ + auto r = mapBlockIndex.find(hash); + if (r != mapBlockIndex.end()) { + blockIdx = *r->second; + return true; + } + fprintf(stderr, "CC Eval Error: Can't get block from index\n"); + return false; +} + + +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]; + int nNotaries = GetNotaries(notaries, height, timestamp); + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + // Get notary pubkey + CTransaction tx; + uint256 hashBlock; + 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; + 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; + 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; + ss >> MoM; + ss >> MoMDepth; + } catch (...) { + return false; + } + return true; +} + + +/* + * Misc + */ + +std::string EvalToStr(EvalCode c) +{ + 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 new file mode 100644 index 000000000..f998c9f3d --- /dev/null +++ b/src/cc/eval.h @@ -0,0 +1,143 @@ +#ifndef CC_EVAL_H +#define CC_EVAL_H + +#include + +#include "chain.h" +#include "streams.h" +#include "version.h" +#include "consensus/validation.h" +#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; + + +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, std::vector params, const CTransaction &disputeTx, unsigned int nIn); + + /* + * Test an ImportPayout CC Eval condition + */ + bool ImportPayout(std::vector params, const CTransaction &importTx, unsigned int nIn); + + /* + * IO functions + */ + 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 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; + 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 + */ +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; +}; + + +/* + * Data from notarisation OP_RETURN + */ +class NotarisationData { +public: + uint256 blockHash; + uint32_t height; + uint256 txHash; // Only get this guy in asset chains not in KMD + char symbol[64]; + uint256 MoM; + uint32_t MoMDepth; + + bool Parse(CScript scriptPubKey); +}; + + +/* + * 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 SerializeF(const T f) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + f(ss); + return std::vector(ss.begin(), ss.end()); +} + +#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;}) +template +bool DeserializeF(const std::vector vIn, T f) +{ + CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); + try { + f(ss); + if (ss.eof()) return true; + } catch(...) {} + return false; +} + + +#endif /* CC_EVAL_H */ diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp new file mode 100644 index 000000000..1363eb924 --- /dev/null +++ b/src/cc/importpayout.cpp @@ -0,0 +1,76 @@ +#include + +#include "main.h" +#include "chain.h" +#include "streams.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" + + +/* + * Crypto-Condition EVAL method that verifies a payout against a transaction + * notarised on another chain. + * + * IN: params - condition params + * IN: importTx - Payout transaction on value chain (KMD) + * IN: nIn - index of input of stake + * + * importTx: Spends stakeTx with payouts from asset chain + * + * in 0: Spends Stake TX and contains ImportPayout CC + * out 0: OP_RETURN MomProof, disputeTx + * out 1-: arbitrary payouts + * + * disputeTx: 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 Eval::ImportPayout(const std::vector params, const CTransaction &importTx, unsigned int nIn) +{ + if (importTx.vout.size() == 0) return Invalid("no-vouts"); + + // load data from vout[0] + MoMProof proof; + CTransaction disputeTx; + { + std::vector vopret; + GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); + if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx)) + return Invalid("invalid-payload"); + } + + // Check disputeTx.0 shows correct payouts + { + 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"); + } + + // Check disputeTx spends sessionTx.0 + // condition ImportPayout params is session ID from other chain + { + 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 (data.MoM != proof.Exec(disputeTx.GetHash())) + return Invalid("mom-check-fail"); + } + + return Valid(); +} diff --git a/src/chain.h b/src/chain.h index d3c46f9d6..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]; void SetNull() { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9f63c6157..9ccde95ee 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -79,7 +79,7 @@ void *chainparams_commandline(void *ptr); #include "komodo_defs.h" extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; -extern uint16_t ASSETCHAINS_PORT; +extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint32_t ASSETCHAIN_INIT; extern uint32_t ASSETCHAINS_MAGIC; extern uint64_t ASSETCHAINS_SUPPLY; @@ -213,7 +213,7 @@ void CChainParams::SetCheckpointData(CChainParams::CCheckpointData checkpointDat void *chainparams_commandline(void *ptr) { CChainParams::CCheckpointData checkpointData; - while ( ASSETCHAINS_PORT == 0 ) + while ( ASSETCHAINS_P2PPORT == 0 ) { #ifdef _WIN32 boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); @@ -221,15 +221,17 @@ void *chainparams_commandline(void *ptr) sleep(1); #endif } - //fprintf(stderr,">>>>>>>> port.%u\n",ASSETCHAINS_PORT); + //fprintf(stderr,">>>>>>>> port.%u\n",ASSETCHAINS_P2PPORT); if ( ASSETCHAINS_SYMBOL[0] != 0 ) { - mainParams.SetDefaultPort(ASSETCHAINS_PORT); + mainParams.SetDefaultPort(ASSETCHAINS_P2PPORT); + if ( ASSETCHAINS_RPCPORT == 0 ) + ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1; mainParams.pchMessageStart[0] = ASSETCHAINS_MAGIC & 0xff; mainParams.pchMessageStart[1] = (ASSETCHAINS_MAGIC >> 8) & 0xff; mainParams.pchMessageStart[2] = (ASSETCHAINS_MAGIC >> 16) & 0xff; mainParams.pchMessageStart[3] = (ASSETCHAINS_MAGIC >> 24) & 0xff; - fprintf(stderr,">>>>>>>>>> %s: port.%u/%u magic.%08x %u %u coins\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT,ASSETCHAINS_PORT+1,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY); + fprintf(stderr,">>>>>>>>>> %s: p2p.%u rpc.%u magic.%08x %u %u coins\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY); if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) { diff --git a/src/clientversion.cpp b/src/clientversion.cpp index ae67e678f..9b523e582 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -48,10 +48,11 @@ const std::string CLIENT_NAME("MagicBean"); #include "build.h" #endif -//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ +//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. +#define GIT_ARCHIVE 1 #ifdef GIT_ARCHIVE -#define GIT_COMMIT_ID "$Format:%h$" -#define GIT_COMMIT_DATE "$Format:%cD$" +#define GIT_COMMIT_ID "a86845f3dc" +#define GIT_COMMIT_DATE "Wed, 21 Feb 2018 16:15:11 +0200" #endif #define RENDER_BETA_STRING(num) "-beta" DO_STRINGIZE(num) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index d2e7dec3f..c2972e598 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -17,7 +17,7 @@ static const int32_t OVERWINTER_MAX_TX_VERSION = 3; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 2000000; /** The maximum allowed number of signature check operations in a block (network rule) */ -static const unsigned int MAX_BLOCK_SIGOPS = 20000; +extern unsigned int MAX_BLOCK_SIGOPS; /** The maximum size of a transaction (network rule) */ static const unsigned int MAX_TX_SIZE = 100000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ 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/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/.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..52f12eee0 --- /dev/null +++ b/src/cryptoconditions/Makefile.am @@ -0,0 +1,91 @@ +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 +libcryptoconditions_la_LIBADD = $(CRYPTOCONDITIONS_CORE) $(LIBSECP256K1) + +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) + +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 \ + 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/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 -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."$ + +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/README.md b/src/cryptoconditions/README.md new file mode 100644 index 000000000..9ec2a6a5f --- /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 may not be particularly safe. The rest is pretty good now. + +## 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..08f00a2ca --- /dev/null +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -0,0 +1,106 @@ +#include +#include + + +#ifndef CRYPTOCONDITIONS_H +#define CRYPTOCONDITIONS_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct CC; +struct CCType; + + +enum CCTypeId { + CC_Anon = -1, + 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 { + // public key types + struct { uint8_t *publicKey, *signature; }; + // preimage + struct { uint8_t *preimage; size_t preimageLength; }; + // threshold + struct { long threshold; uint8_t size; struct CC **subconditions; }; + // prefix + struct { uint8_t *prefix; size_t prefixLength; struct CC *subcondition; + size_t maxMessageLength; }; + // eval + struct { uint8_t *code; size_t codeLength; }; + // anon + struct { uint8_t fingerprint[32]; uint32_t subtypes; unsigned long cost; + struct CCType *conditionType; }; + }; +} CC; + + + +/* + * Crypto Condition Visitor + */ +typedef struct CCVisitor { + int (*visit)(CC *cond, struct CCVisitor visitor); + const uint8_t *msg; + size_t msgLength; + void *context; +} CCVisitor; + + +/* + * Public methods + */ +int cc_isFulfilled(const CC *cond); +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 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 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); +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); +int cc_isAnon(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..114517074 --- /dev/null +++ b/src/cryptoconditions/src/anon.c @@ -0,0 +1,73 @@ + +#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; + + +CC *mkAnon(const Condition_t *asnCond) { + + CCType *realType = getTypeByAsnEnum(asnCond->present); + if (!realType) { + fprintf(stderr, "Unknown ASN type: %i", asnCond->present); + return 0; + } + CC *cond = cc_new(CC_Anon); + cond->conditionType = realType; + const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256; + memcpy(cond->fingerprint, deets->fingerprint.buf, 32); + cond->cost = deets->cost; + if (realType->getSubtypes) { + 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) { +} + + +static int anonIsFulfilled(const CC *cond) { + return 0; +} + + +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/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..42a3c88f1 --- /dev/null +++ b/src/cryptoconditions/src/asn/CryptoConditions.asn @@ -0,0 +1,113 @@ +---- + +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 { + 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, + 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)) + } + +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/EvalFulfillment.c b/src/cryptoconditions/src/asn/EvalFulfillment.c new file mode 100644 index 000000000..f43b21e1f --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFulfillment.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 "EvalFulfillment.h" + +static asn_TYPE_member_t asn_MBR_EvalFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, code), + (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, + "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 } /* code */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_EvalFulfillment_specs_1 = { + sizeof(struct EvalFulfillment), + offsetof(struct EvalFulfillment, _asn_ctx), + asn_MAP_EvalFulfillment_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_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, + 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 new file mode 100644 index 000000000..378baa367 --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFulfillment.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 _EvalFulfillment_H_ +#define _EvalFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* EvalFulfillment */ +typedef struct EvalFulfillment { + OCTET_STRING_t code; + + /* 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..9ff904aca --- /dev/null +++ b/src/cryptoconditions/src/asn/Makefile.am.sample @@ -0,0 +1,120 @@ +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 + +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 + +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..7e64ba109 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_system.h @@ -0,0 +1,128 @@ +/*- + * 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 */ + +#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..6fd54f245 --- /dev/null +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -0,0 +1,303 @@ +#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 + +#ifdef __LP64__ +#include +#else +#include // Index into CTransaction.vjoinsplit +#endif + + +struct CCType *CCTypeRegistry[] = { + &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 +}; + + +int CCTypeRegistryLength = sizeof(CCTypeRegistry) / sizeof(CCTypeRegistry[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, CCTypeRegistry[i]->name); + } else { + strcat(buf, "&subtypes="); + strcat(buf, CCTypeRegistry[i]->name); + append = 1; + } + } + } +} + + +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, cc_typeName(cond), cc_getCost(cond)); + + if (cond->type->getSubtypes) { + appendUriSubtypes(cond->type->getSubtypes(cond), out); + } + + free(fp); + free(encoded); + + return out; +} + + +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; +} + + +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) { + fprintf(stderr, "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) { + fprintf(stderr, "FULFILLMENT NOT ENCODED\n"); + return 0; + } + ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + return rc.encoded; +} + + +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 + // 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)); +} + + +Condition_t *asnConditionNew(const CC *cond) { + Condition_t *asn = calloc(1, sizeof(Condition_t)); + asnCondition(cond, asn); + return asn; +} + + +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 CCTypeRegistry[i]; + } + } + return NULL; +} + + +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(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) { + 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; +} + + +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(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); + if (rval.code != RC_OK) { + fprintf(stderr, "Failed reading condition binary\n"); + return NULL; + } + CC *cond = mkAnon(asnCond); + ASN_STRUCT_FREE(asn_DEF_Condition, asnCond); + return cond; +} + + +int cc_isAnon(const CC *cond) { + return cond->type->typeId == CC_Anon; +} + + +enum CCTypeId cc_typeId(const CC *cond) { + 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; +} + + +int cc_isFulfilled(const CC *cond) { + return cond->type->isFulfilled(cond); +} + + +char *cc_typeName(const CC *cond) { + return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name; +} + + +CC *cc_new(int typeId) { + CC *cond = calloc(1, sizeof(CC)); + cond->type = typeId == CC_Anon ? &CC_AnonType : CCTypeRegistry[typeId]; + return cond; +} + + +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 new file mode 100644 index 000000000..7ae99b226 --- /dev/null +++ b/src/cryptoconditions/src/ed25519.c @@ -0,0 +1,168 @@ +#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, + const 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, 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 = cc_new(CC_Ed25519); + 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 = cc_new(CC_Ed25519); + 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); + } +} + + +static uint32_t ed25519Subtypes(const CC *cond) { + return 0; +} + + +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 new file mode 100644 index 000000000..4a7d13276 --- /dev/null +++ b/src/cryptoconditions/src/eval.c @@ -0,0 +1,119 @@ +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/EvalFulfillment.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) { + unsigned char *hash = calloc(1, 32); + sha256(cond->code, cond->codeLength, hash); + return hash; +} + + +static unsigned long evalCost(const CC *cond) { + return 1048576; // Pretty high +} + + +static CC *evalFromJSON(const cJSON *params, char *err) { + size_t codeLength; + unsigned char *code = 0; + + if (!jsonGetBase64(params, "code", err, &code, &codeLength)) { + return NULL; + } + + CC *cond = cc_new(CC_Eval); + cond->code = code; + cond->codeLength = codeLength; + return cond; +} + + +static void evalToJSON(const CC *cond, cJSON *code) { + + // add code + unsigned char *b64 = base64_encode(cond->code, cond->codeLength); + cJSON_AddItemToObject(code, "code", cJSON_CreateString(b64)); + free(b64); +} + + +static CC *evalFromFulfillment(const Fulfillment_t *ffill) { + CC *cond = cc_new(CC_Eval); + + EvalFulfillment_t *eval = &ffill->choice.evalSha256; + + OCTET_STRING_t octets = eval->code; + cond->codeLength = octets.size; + cond->code = malloc(octets.size); + memcpy(cond->code, 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->code, cond->code, cond->codeLength); + return ffill; +} + + +int evalIsFulfilled(const CC *cond) { + return 1; +} + + +static void evalFree(CC *cond) { + free(cond->code); +} + + +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 (cond->codeLength == 5 && 0 == memcmp(cond->code, "TEST", 4)) { + return cond->code[5]; + } + 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_Eval) 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, &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..87fea161b --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/.gitignore @@ -0,0 +1,49 @@ +bench_inv +bench_ecdh +bench_sign +bench_verify +bench_schnorr_verify +bench_recover +bench_internal +tests +exhaustive_tests +gen_context +*.exe +*.so +*.a +!.gitignore + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +*.lo +*.o +*~ +src/libsecp256k1-config.h +src/libsecp256k1-config.h.in +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 new file mode 100644 index 000000000..243952924 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/.travis.yml @@ -0,0 +1,69 @@ +language: c +sudo: false +addons: + apt: + packages: libgmp-dev +compiler: + - clang + - gcc +cache: + directories: + - src/java/guava/ +env: + global: + - 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 RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes + - SCALAR=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 ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no STATICPRECOMPUTATION=no + - BUILD=distcheck + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java ECDH=yes EXPERIMENTAL=yes +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_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-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/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..c071fbe27 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/Makefile.am @@ -0,0 +1,177 @@ +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 +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_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 +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/java/org_bitcoin_Secp256k1Context.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 +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 + +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_sign bench_internal +bench_verify_SOURCES = src/bench_verify.c +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) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_internal_SOURCES = src/bench_internal.c +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 = -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 + +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 new file mode 100644 index 000000000..8cd344ea8 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/README.md @@ -0,0 +1,61 @@ +libsecp256k1 +============ + +[![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. + +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/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 new file mode 100644 index 000000000..e5fcbcb4e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/configure.ac @@ -0,0 +1,493 @@ +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) +AX_PROG_CC_FOR_BUILD + +if test "x$CFLAGS" = "x"; then + 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 +AM_PROG_AS + +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" + ]) + +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]) + +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|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[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"$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 + 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 + ;; + arm) + ;; + 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 +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) + ;; +*) + 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 + 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 + 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 + +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 + +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" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +AC_OUTPUT 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 new file mode 100644 index 000000000..3e9c098d1 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h @@ -0,0 +1,621 @@ +#ifndef SECP256K1_H +#define SECP256K1_H + +#ifdef __cplusplus +extern "C" { +#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__) +# 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 + +#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. */ +# 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 + +/** 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 (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_API secp256k1_context* secp256k1_context_create( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copies a secp256k1 context object. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + */ +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) + */ +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 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) + * 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_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); + +/** 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_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. + */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ +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, 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) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. + */ +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); + +/** Verify an ECDSA secret key. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seckey: pointer to a 32-byte secret key (cannot be NULL) + */ +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. + * + * 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_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); + +/** 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_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); + +/** 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. + * 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. + * 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_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 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_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); + +/** 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 + * 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_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 +} +#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 new file mode 100644 index 000000000..a0d006f11 --- /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-core/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/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 new file mode 100644 index 000000000..d5ebe0130 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench.h @@ -0,0 +1,66 @@ +/********************************************************************** + * 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 > 0 && 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 != NULL) { + setup(data); + } + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown != NULL) { + 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 /* 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 new file mode 100644 index 000000000..9b30c50d0 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c @@ -0,0 +1,382 @@ +/********************************************************************** + * 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_const_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +typedef struct { + 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; + +void bench_setup(void* arg) { + bench_inv *data = (bench_inv*)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); + memcpy(data->data + 32, init_y, 32); +} + +void bench_scalar_add(void* arg) { + int i; + bench_inv *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + 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); + } +} +#endif + +void bench_scalar_inverse(void* arg) { + int i; + bench_inv *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize(&data->fe_x); + } +} + +void bench_field_normalize_weak(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize_weak(&data->fe_x); + } +} + +void bench_field_mul(void* arg) { + int i; + bench_inv *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)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 *data = (bench_inv*)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(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + 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 *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); + } +} + +void bench_group_add_var(void* arg) { + int i; + 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, NULL); + } +} + +void bench_group_add_affine(void* arg) { + int i; + 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); + } +} + +void bench_group_add_affine_var(void* arg) { + int i; + 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, 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 *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + 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); + } +} + + +void bench_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 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 *data = (bench_inv*)arg; + secp256k1_hmac_sha256 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 *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; + + for (i = 0; i < 20000; i++) { + 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; + 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 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", 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 new file mode 100644 index 000000000..506fc1880 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c @@ -0,0 +1,60 @@ +/********************************************************************** + * 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 *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover; + +void bench_recover(void* arg) { + int i; + bench_recover *data = (bench_recover*)arg; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; + + for (i = 0; i < 20000; i++) { + int j; + 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] = 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 *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; + } +} + +int main(void) { + bench_recover 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..544b43963 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_sign.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/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context* ctx; + unsigned char msg[32]; + unsigned char key[32]; +} bench_sign; + +static void bench_sign_setup(void* arg) { + int i; + 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; + } +} + +static void bench_sign_run(void* arg) { + int i; + bench_sign *data = (bench_sign*)arg; + + unsigned char sig[74]; + for (i = 0; i < 20000; i++) { + size_t siglen = 74; + int j; + 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]; + data->key[j] = sig[j + 32]; + } + } +} + +int main(void) { + bench_sign data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + 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 new file mode 100644 index 000000000..418defa0a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c @@ -0,0 +1,112 @@ +/********************************************************************** + * 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" + +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif +} 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++) { + 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_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; + } + data.siglen = 72; + 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_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 new file mode 100644 index 000000000..80590c7cc --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h @@ -0,0 +1,21 @@ +/********************************************************************** + * 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_H +#define SECP256K1_ECDSA_H + +#include + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +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); + +#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 new file mode 100644 index 000000000..c3400042d --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h @@ -0,0 +1,313 @@ +/********************************************************************** + * 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 + +#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 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 secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); + +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; +} + +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*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; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; +} + +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; + 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; + 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 *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { + unsigned char c[32]; + 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(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_inverse_var(&sn, sigs); + secp256k1_scalar_mul(&u1, &sn, message); + 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; + } + +#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) + * 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 * 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 + n >= p, 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; +#endif +} + +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 rp; + secp256k1_ge r; + secp256k1_scalar 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(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, sigr, seckey); + secp256k1_scalar_add(&n, &n, message); + 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(sigs)) { + return 0; + } + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); + if (recid) { + *recid ^= 1; + } + } + return 1; +} + +#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 new file mode 100644 index 000000000..b621f1e6c --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey.h @@ -0,0 +1,25 @@ +/********************************************************************** + * 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_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 *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_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); + +#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 new file mode 100644 index 000000000..1ab9a68ec --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h @@ -0,0 +1,100 @@ +/********************************************************************** + * 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 *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 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] == 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); + } else { + return 0; + } +} + +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; + } + 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] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; + } else { + *size = 65; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + secp256k1_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +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; + } + return 1; +} + +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); + + 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 *key, const secp256k1_scalar *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 *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_scalar zero; + secp256k1_gej 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 /* SECP256K1_ECKEY_IMPL_H */ 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..6d44aba60 --- /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_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 (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_ecmult_context; + +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 *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); + +#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 new file mode 100644 index 000000000..7564b7015 --- /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_H +#define SECP256K1_ECMULT_GEN_H + +#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 (*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* 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* ctx, secp256k1_gej *r, const secp256k1_scalar *a); + +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); + +#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 new file mode 100644 index 000000000..714f02e94 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h @@ -0,0 +1,210 @@ +/********************************************************************** + * 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" +#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 *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; + } +#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); + + /* 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 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, NULL); + } + + /* compute prec. */ + { + 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, NULL); + } + /* Multiply gbase by 16. */ + for (i = 0; i < 4; i++) { + secp256k1_gej_double_var(&gbase, &gbase, NULL); + } + /* Multiply numbase by 2. */ + 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, NULL); + } + } + 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* ctx) { + return ctx->prec != NULL; +} + +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 { +#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 *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 *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)); + *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 *ctx, const unsigned char *seed32) { + secp256k1_scalar b; + secp256k1_gej gb; + secp256k1_fe s; + unsigned char nonce32[32]; + secp256k1_rfc6979_hmac_sha256 rng; + int retry; + 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); + 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. + */ + 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); /* 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); + 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); /* 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); + secp256k1_scalar_negate(&b, &b); + ctx->blind = b; + ctx->initial = gb; + secp256k1_scalar_clear(&b); + secp256k1_gej_clear(&gb); +} + +#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 new file mode 100644 index 000000000..93d3794cb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h @@ -0,0 +1,406 @@ +/********************************************************************** + * 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 + +#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 +/** 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 +#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_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_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)); \ + 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 *ctx) { + ctx->pre_g = NULL; +#ifdef USE_ENDOMORPHISM + ctx->pre_g_128 = NULL; +#endif +} + +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej 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 (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* precompute the tables with odd multiples */ + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); + +#ifdef USE_ENDOMORPHISM + { + secp256k1_gej g_128j; + int i; + + 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, NULL); + } + 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 *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 (*)[])checked_malloc(cb, 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 (*)[])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 *ctx) { + return ctx->pre_g != NULL; +} + +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *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, 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 < len) { + int now; + int word; + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { + bit++; + continue; + } + + now = w; + 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; + } +#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 *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_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar na_1, na_lam; + /* Splitted G factors. */ + secp256k1_scalar 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[256]; + 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(&na_1, &na_lam, na); + + /* build wnaf representation for na_1 and na_lam. */ + 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; + if (bits_na_lam > bits) { + bits = bits_na_lam; + } +#else + /* build wnaf representation for na. */ + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); + bits = bits_na; +#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. + * 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_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, 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; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } +#else + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, 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, NULL); +#ifdef USE_ENDOMORPHISM + if (i < bits_na_1 && (n = wnaf_na_1[i])) { + 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_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_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_zinv_var(r, r, &tmpa, &Z); + } +#else + if (i < bits_na && (n = wnaf_na[i])) { + 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_zinv_var(r, r, &tmpa, &Z); + } +#endif + } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } +} + +#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 new file mode 100644 index 000000000..bb6692ad5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field.h @@ -0,0 +1,132 @@ +/********************************************************************** + * 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_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 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 + * 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 + +#include "util.h" + +/** Normalize a field element. */ +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 *r); + +/** Normalize a field element, without constant-time guarantee. */ +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 *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 *r); + +/** Set a field element equal to a small integer. Resulting field element is normalized. */ +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 *a); + +/** Check the "oddness" of a field element. Requires the input to be normalized. */ +static int secp256k1_fe_is_odd(const secp256k1_fe *a); + +/** Compare two field elements. Requires magnitude-1 inputs. */ +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 *a, const secp256k1_fe *b); + +/** 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 *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 *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 *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 *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 *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 *r, const secp256k1_fe *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 *r, const secp256k1_fe *a); + +/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +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(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 *r, const secp256k1_fe *a); + +/** Convert a field element back from the storage type. */ +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 *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 *r, const secp256k1_fe *a, int flag); + +#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 new file mode 100644 index 000000000..727c5267f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h @@ -0,0 +1,48 @@ +/********************************************************************** + * 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_H +#define SECP256K1_FIELD_REPR_H + +#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; + +/* 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, \ + (((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 +#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; + +#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 /* 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 new file mode 100644 index 000000000..94f8132fc --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h @@ -0,0 +1,1161 @@ +/********************************************************************** + * 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 "util.h" +#include "num.h" +#include "field.h" + +#ifdef VERIFY +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); + 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); +} +#endif + +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]; + + /* 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 *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 *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 *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 *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); + 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 *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 *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 *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 *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 *a, const secp256k1_fe *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 *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; + } +#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 *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + 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 *r, const secp256k1_fe *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 *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 *r, const secp256k1_fe *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 +} + +#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 +#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] */ +} +#endif + +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); + 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 *r, const secp256k1_fe *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 *r, const secp256k1_fe *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 + 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 *r, const secp256k1_fe_storage *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 *r, const secp256k1_fe *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 *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); + 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 /* 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 new file mode 100644 index 000000000..bccd8feb4 --- /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_H +#define SECP256K1_FIELD_REPR_H + +#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; + +/* 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), \ + ((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 +#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; + +#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 /* 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 new file mode 100644 index 000000000..1fc3171f6 --- /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 /* 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 new file mode 100644 index 000000000..957c61b01 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h @@ -0,0 +1,496 @@ +/********************************************************************** + * 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 "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 *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); +} +#endif + +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 */ + 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 *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 *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 *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 *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); + 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 *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 *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 *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 *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 *a, const secp256k1_fe *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 *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; + } +#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 *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + 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 *r, const secp256k1_fe *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 *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 *r, const secp256k1_fe *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 *r, const secp256k1_fe *a, const secp256k1_fe * 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 *r, const secp256k1_fe *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 *r, const secp256k1_fe *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 + 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 *r, const secp256k1_fe_storage *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 *r, const secp256k1_fe *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 *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); + 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 /* 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 new file mode 100644 index 000000000..95a0d1791 --- /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 /* 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 new file mode 100644 index 000000000..20428648a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_impl.h @@ -0,0 +1,315 @@ +/********************************************************************** + * 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(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(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 + * { 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(&t1, a); +} + +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 + * { 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 *r, const secp256k1_fe *a) { +#if defined(USE_FIELD_INV_BUILTIN) + secp256k1_fe_inv(r, a); +#elif defined(USE_FIELD_INV_NUM) + 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, + 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]; + 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); + 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(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { + secp256k1_fe 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) { + size_t j = i--; + secp256k1_fe_mul(&r[j], &r[i], &u); + secp256k1_fe_mul(&u, &u, &a[j]); + } + + 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 new file mode 100644 index 000000000..ea1302deb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/group.h @@ -0,0 +1,144 @@ +/********************************************************************** + * 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_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 x; + secp256k1_fe y; + int infinity; /* whether this represents the point at infinity */ +} 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 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; + +#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 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))} + +#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 *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 *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 *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int secp256k1_ge_is_valid_var(const secp256k1_ge *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 *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(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 *r); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +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 *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 *r, const secp256k1_gej *a); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_gej_is_infinity(const secp256k1_gej *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 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 *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. 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_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); +#endif + +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *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 *r, const secp256k1_ge *a); + +/** Convert a group element back from the storage type. */ +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 *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 *r, const secp256k1_fe *b); + +#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 new file mode 100644 index 000000000..b31b6c12e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/group_impl.h @@ -0,0 +1,700 @@ +/********************************************************************** + * 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 "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 secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, + 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, + 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, + 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL +); + +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 *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 *a) { + return a->infinity; +} + +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 *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); + 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 *r, secp256k1_gej *a) { + secp256k1_fe 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(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 *)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 *)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_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); + } + } + free(azi); +} + +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_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); +} + +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 *r) { + r->infinity = 0; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); +} + +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, CURVE_B); + secp256k1_fe_add(&c, &x3); + 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); + 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 *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 *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 *r, const secp256k1_gej *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 *a) { + return a->infinity; +} + +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe 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, 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 *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, 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 *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); + 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 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 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); + 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, 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); + 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); + 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 *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 z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + 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); + 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, 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; + } + 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 *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); + + /** 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.) + * + * 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*Z1^2 (1) */ + secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + 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(&rr, &t); /* rr = T^2 (1) */ + 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 */ + + 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 *r, const secp256k1_fe *s) { + /* Operations: 4 mul, 1 sqr */ + 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 */ + 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 *r, const secp256k1_ge *a) { + secp256k1_fe 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 *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 *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_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 + ); + *r = *a; + secp256k1_fe_mul(&r->x, &r->x, &beta); +} +#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 new file mode 100644 index 000000000..de26e4b89 --- /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_H +#define SECP256K1_HASH_H + +#include +#include + +typedef struct { + uint32_t s[8]; + uint32_t buf[16]; /* In big endian */ + size_t bytes; +} secp256k1_sha256; + +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 inner, outer; +} secp256k1_hmac_sha256; + +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; + +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 /* 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 new file mode 100644 index 000000000..c06db9e33 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h @@ -0,0 +1,281 @@ +/********************************************************************** + * 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 *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 *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 *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 *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 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 *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +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); + memset(temp, 0, 32); + secp256k1_sha256_finalize(&hash->outer, out32); +} + + +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}; + + 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_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_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 *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + 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); + 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 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 *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + +#undef BE32 +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#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 new file mode 100644 index 000000000..1c67802fb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -0,0 +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/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 { + + 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) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(signature); + byteBuff.put(pub); + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } + } + + /** + * 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 + */ + 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 new file mode 100644 index 000000000..bcef7b32c --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include "org_bitcoin_NativeSecp256k1.h" +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" + + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + 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; + +} + +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); + +} + +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 new file mode 100644 index 000000000..fe613c9e9 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -0,0 +1,119 @@ +/* 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 +#define _Included_org_bitcoin_NativeSecp256k1 +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ctx_clone + * Signature: (J)J + */ +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 +} +#endif +#endif 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 new file mode 100644 index 000000000..49f2dd791 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num.h @@ -0,0 +1,74 @@ +/********************************************************************** + * 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_H +#define SECP256K1_NUM_H + +#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 *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 *a); + +/** Set a number to the value of a binary big-endian string. */ +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 *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 *a, const secp256k1_num *b); + +/** Test whether two number are equal (including sign). */ +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); + +/** Add two (signed) numbers. */ +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 *r, const secp256k1_num *a, const secp256k1_num *b); + +/** Multiply two (signed) numbers. */ +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 *r, const secp256k1_num *m); + +/** Right-shift the passed number by bits 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 *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 *a); + +/** Change a number's sign. */ +static void secp256k1_num_negate(secp256k1_num *r); + +#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 new file mode 100644 index 000000000..3619844bd --- /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_H +#define SECP256K1_NUM_REPR_H + +#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; + +#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 new file mode 100644 index 000000000..0ae2a8ba0 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h @@ -0,0 +1,288 @@ +/********************************************************************** + * 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 *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 *r, const secp256k1_num *a) { + *r = *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; + 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 *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 *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) { + VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); + r->data[r->limbs++] = c; + } +} + +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) { + r->limbs--; + } +} + +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *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 *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]; + 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); + (void)gn; + 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_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 *a) { + return (a->limbs > 1 || a->data[0] != 0) && a->neg; +} + +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *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 *a, const secp256k1_num *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 *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) { + 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 *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 *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 *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); + + 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 *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); + 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 *r) { + r->neg ^= 1; +} + +#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 new file mode 100644 index 000000000..c45193b03 --- /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 /* SECP256K1_NUM_IMPL_H */ 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..59304cb66 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar.h @@ -0,0 +1,106 @@ +/********************************************************************** + * 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_H +#define SECP256K1_SCALAR_H + +#include "num.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#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" +#else +#error "Please select scalar implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +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 *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 *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. */ +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 *r, unsigned int v); + +/** Convert a scalar to a byte array. */ +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 *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** 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 *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 *r, const secp256k1_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order). */ +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 *r, const secp256k1_scalar *a); + +/** Compute the complement of a scalar (modulo the group order). */ +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 *a); + +/** Check whether a scalar equals one. */ +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 *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 *r, const secp256k1_scalar *a); + +/** Get the order of the group as a number. */ +static void secp256k1_scalar_order_get_num(secp256k1_num *r); +#endif + +/** Compare two scalars. */ +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 *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(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 *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); + +#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 new file mode 100644 index 000000000..19c7495d1 --- /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_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; + +#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 /* 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 new file mode 100644 index 000000000..db1ebf94b --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h @@ -0,0 +1,949 @@ +/********************************************************************** + * 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 *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 *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 *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 *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 *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 *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 *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; + 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_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)); + 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 *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* 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 *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +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; + 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 *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 *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; +} + +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. */ +#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 *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" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%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" + "xorq %%r8, %%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" + "xorq %%r9, %%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" + "xorq %%r10, %%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" + "xorq %%r8, %%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" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%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" + "xorq %%r8, %%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" + "xorq %%r9, %%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" + "xorq %%r9, %%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" + "xorq %%r8, %%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" + "xorq %%r9, %%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 *a, const secp256k1_scalar *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 *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 *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 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); +} + +#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; + r1->d[3] = 0; + r2->d[0] = a->d[2]; + r2->d[1] = a->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; +} +#endif + +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 *r, const secp256k1_scalar *a, const secp256k1_scalar *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; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); +} + +#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 new file mode 100644 index 000000000..2c9a348e2 --- /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_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; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#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 new file mode 100644 index 000000000..4f9ed61fe --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h @@ -0,0 +1,721 @@ +/********************************************************************** + * 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 *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 *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 *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 *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 *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 *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 *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; + 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_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)); + 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 *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* 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 *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 *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; + 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 *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 *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; +} + +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. */ +#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 *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 *a, const secp256k1_scalar *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 *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 *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 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 *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]; + 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 *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 *r, const secp256k1_scalar *a, const secp256k1_scalar *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; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); +} + +#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 new file mode 100644 index 000000000..fa790570f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h @@ -0,0 +1,333 @@ +/********************************************************************** + * 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 "group.h" +#include "scalar.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#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" +#else +#error "Please select scalar implementation" +#endif + +#ifndef USE_NUM_NONE +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 *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 *r, const secp256k1_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) + int i; + *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(&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(&x6, &u13); + secp256k1_scalar_sqr(&x6, &x6); + secp256k1_scalar_mul(&x6, &x6, &u11); + + secp256k1_scalar_sqr(&x8, &x6); + secp256k1_scalar_sqr(&x8, &x8); + secp256k1_scalar_mul(&x8, &x8, &x2); + + secp256k1_scalar_sqr(&x14, &x8); + for (i = 0; i < 5; i++) { + secp256k1_scalar_sqr(&x14, &x14); + } + secp256k1_scalar_mul(&x14, &x14, &x6); + + secp256k1_scalar_sqr(&x28, &x14); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x28, &x28); + } + secp256k1_scalar_mul(&x28, &x28, &x14); + + secp256k1_scalar_sqr(&x56, &x28); + for (i = 0; i < 27; i++) { + secp256k1_scalar_sqr(&x56, &x56); + } + secp256k1_scalar_mul(&x56, &x56, &x28); + + secp256k1_scalar_sqr(&x112, &x56); + for (i = 0; i < 55; i++) { + secp256k1_scalar_sqr(&x112, &x112); + } + secp256k1_scalar_mul(&x112, &x112, &x56); + + secp256k1_scalar_sqr(&x126, &x112); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x126, &x126); + } + secp256k1_scalar_mul(&x126, &x126, &x14); + + /* 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, &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 < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + 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); + } + 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 < 6; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 3; i++) { + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + 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 < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + 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 < 6; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 10; i++) { /* 000000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + 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 */ +} + +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 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, + * 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(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 minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, + 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + ); + 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); + 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 + +#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 new file mode 100644 index 000000000..cecb1550b --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c @@ -0,0 +1,584 @@ +/********************************************************************** + * 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.* + **********************************************************************/ + +#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_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" + +#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 +}; + +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_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); + } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); + } + + return ret; +} + +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* ctx) { + if (ctx != NULL) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + + free(ctx); + } +} + +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); + 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)); +} + +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; + /* 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); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + return 1; +} + +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* 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; + 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 (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; + int ret; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + ret = !overflow && !secp256k1_scalar_is_zero(&sec); + secp256k1_scalar_clear(&sec); + return ret; +} + +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; + 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); + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(pubkey, &p); + } + secp256k1_scalar_clear(&sec); + return ret; +} + +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; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + 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* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar term; + secp256k1_scalar sec; + int ret = 0; + int overflow = 0; + 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 = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); + 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* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar term; + int ret = 0; + int overflow = 0; + 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); + 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* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar factor; + secp256k1_scalar sec; + int ret = 0; + int overflow = 0; + 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 = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); + 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* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar factor; + int ret = 0; + int overflow = 0; + 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); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +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 new file mode 100644 index 000000000..f1f9be077 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand.h @@ -0,0 +1,38 @@ +/********************************************************************** + * 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 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); + +/** 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 new file mode 100644 index 000000000..30a91e529 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h @@ -0,0 +1,110 @@ +/********************************************************************** + * 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 + +#include +#include + +#include "testrand.h" +#include "hash.h" + +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, seed16, 16); +} + +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 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_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; + 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++; + } + } +} + +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 new file mode 100644 index 000000000..f307b99d5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/tests.c @@ -0,0 +1,4536 @@ +/********************************************************************** + * 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 + +#include "secp256k1.c" +#include "include/secp256k1.h" +#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 + +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#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); + if (secp256k1_fe_set_b32(fe, b32)) { + break; + } + } while(1); +} + +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; + } + secp256k1_fe_clear(&zero); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int(&zero, n - 1); + secp256k1_fe_add(fe, &zero); + VERIFY_CHECK(fe->magnitude == n); +} + +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_rand_bits(1))) { + secp256k1_fe_normalize(&ge->y); + break; + } + } while(1); +} + +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)) { + 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 *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 *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_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 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 *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); + } + + /* 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, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try signing */ + 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, &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 *****/ + +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 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_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); + 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 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_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); + 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[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[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 rng; + unsigned char out[32]; + int i; + + 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, 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, 64); + 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); +} + +/***** 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 *num) { + if (secp256k1_rand_bits(1)) { + secp256k1_num_negate(num); + } +} + +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 *num) { + secp256k1_scalar sc; + random_scalar_order(&sc); + secp256k1_scalar_get_num(num, &sc); +} + +void test_num_negate(void) { + secp256k1_num n1; + secp256k1_num 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) { + 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 (secp256k1_rand_bits(1)) { + random_num_negate(&n1); + } + random_num_order_test(&n2); /* n2 = R2 */ + if (secp256k1_rand_bits(1)) { + 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)); + + /* 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) { + int i; + for (i = 0; i < 100*count; i++) { + test_num_negate(); + test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); + } +} +#endif + +/***** SCALAR TESTS *****/ + +void scalar_test(void) { + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; +#ifndef USE_NUM_NONE + secp256k1_num snum, s1num, s2num; + secp256k1_num 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 n; + secp256k1_scalar_set_int(&n, 0); + for (i = 0; i < 256; i += 4) { + 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++) { + 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 n; + int i = 0; + secp256k1_scalar_set_int(&n, 0); + while (i < 256) { + secp256k1_scalar t; + int j; + int now = secp256k1_rand_int(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 rnum; + secp256k1_num r2num; + secp256k1_scalar 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 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); + 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 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. */ + 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 r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; + unsigned char cone[1] = {0x01}; + 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); + 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)); + } + + { + /* 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 inv; +#ifndef USE_NUM_NONE + secp256k1_num invnum; + secp256k1_num 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)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif + } + } + + { + /* Test commutativity of add. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + secp256k1_scalar r1, r2; + secp256k1_scalar b; + int i; + /* Test add_bit. */ + int bit = secp256k1_rand_bits(8); + 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_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 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 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 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 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 r1, r2; + secp256k1_scalar_sqr(&r1, &s1); + secp256k1_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test multiplicative identity. */ + secp256k1_scalar 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 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 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 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 order; + secp256k1_scalar 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 + + { + /* 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 *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +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); + 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 *ns) { + secp256k1_fe r; + random_fe_non_zero(ns); + if (secp256k1_fe_sqrt(&r, ns)) { + secp256k1_fe_negate(ns, ns, 1); + } +} + +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 *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); +} + +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 fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_fe fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_fe fe2; + unsigned char b322[32]; + secp256k1_fe_storage 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); +} + +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 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 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); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); + secp256k1_fe_cmov(&x, &x, 1); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); + secp256k1_fe_cmov(&q, &z, 1); + 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); + 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 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 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 x[16], xi[16], xii[16]; + int i; + /* Check it's safe to call for 0 elements */ + secp256k1_fe_inv_all_var(xi, x, 0); + for (i = 0; i < count; i++) { + size_t j; + 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(xi, x, len); + for (j = 0; j < len; j++) { + CHECK(check_fe_inverse(&x[j], &xi[j])); + } + secp256k1_fe_inv_all_var(xii, xi, len); + for (j = 0; j < len; j++) { + CHECK(check_fe_equal(&x[j], &xii[j])); + } + } +} + +void run_sqr(void) { + secp256k1_fe 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 *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; + int v = secp256k1_fe_sqrt(&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 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 *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)); +} + +/* This compares jacobian points including their Z, not just their geometric meaning. */ +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) { + 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 *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 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 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 *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 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); + 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); + } + } + + /* 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 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 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) { + /* 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)) { + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); + ge_equals_gej(&ref, &resj); + /* 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); + } + + /* 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 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_rand_int(4 * runs + 1 - i); + if (swap != 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], NULL); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion with and without known z ratios. */ + { + 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++) { + /* 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) { + int i; + 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 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 xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + 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 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 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 x; + secp256k1_gej 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 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, 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, NULL); + CHECK(secp256k1_gej_is_infinity(&x2)); +} + +void test_point_times_order(const secp256k1_gej *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + 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]; + 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, NULL); + 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); + /* 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 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 p; + if (secp256k1_ge_set_xo_var(&p, &x, 1)) { + secp256k1_gej 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 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, 256, 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 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 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 x; + secp256k1_gej r; + secp256k1_ge 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 affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; + unsigned char seed32[32]; + 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); + 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 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; + 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(); + } +} + +#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]; + + 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, sigr, sigs, key, msg, &nonce, recid)); +} + +void test_ecdsa_sign_verify(void) { + 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_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, &sigr, &sigs, &pub, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &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, 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, 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, algo16, data, counter - 1); +} + +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); + 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 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, algo16, data, counter - 5); +} + +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) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char privkey2[32]; + 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]; + size_t seckeylen = 300; + + /* 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); + + /* 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(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_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_pubkey pubkey2; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Optionally tweak the keys using multiplication. */ + if (secp256k1_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_pubkey pubkey2; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Sign. */ + 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, &signature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + 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, &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 elem; + secp256k1_ge elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); + } + if (len == 65) { + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); + } else { + in[0] = secp256k1_rand_bits(1) ? 2 : 3; + } + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); + } + 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; + 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)); + 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] = secp256k1_rand_bits(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(); + } +} + +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 + }; +#endif + + int ret = 0; + + 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; + } + 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 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 = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with r of zero fails. */ + { + 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 + }; + 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); + } + + /* Verify signature with s of zero fails. */ + { + 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, + 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, + }; + 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_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; + /* 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. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + 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, &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, &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, &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. */ + 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; + msg[0] = i; + 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(&sr[i], &sr[j])); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + key[0] = i - 256; + 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(&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]; + 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, + }; + 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)); + } +} + +void run_ecdsa_edge_cases(void) { + test_ecdsa_edge_cases(); +} + +#ifdef ENABLE_OPENSSL_TESTS +EC_KEY *get_openssl_key(const unsigned char *key32) { + unsigned char privkey[300]; + size_t privkeylen; + const unsigned char* pbegin = privkey; + int compr = secp256k1_rand_bits(1); + EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + 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 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; + 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(key32); + CHECK(ec_key != NULL); + CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); + 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, &sigr, &sigs, &q, &msg2)); + + 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); +} + +void run_ecdsa_openssl(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_openssl(); + } +} +#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}; + /* 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 == NULL) || !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_rand_bits(1)) { + secp256k1_rand256(run32); + 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(); + +#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(); + run_group_decompress(); + + /* ecmult tests */ + run_wnaf(); + run_point_times_order(); + 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(); +#ifdef ENABLE_OPENSSL_TESTS + 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 new file mode 100644 index 000000000..b0441d8e3 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/util.h @@ -0,0 +1,113 @@ +/********************************************************************** + * 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 + +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); \ + 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 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(const secp256k1_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } + 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 /* SECP256K1_UTIL_H */ 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..76955f406 --- /dev/null +++ b/src/cryptoconditions/src/internal.h @@ -0,0 +1,84 @@ +#include +#include +#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 + +typedef char bool; + + +/* + * Condition Type + */ +typedef struct CCType { + int typeId; + 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, 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 + */ +struct CCType *CCTypeRegistry[32]; +int CCTypeRegistryLength; + + +/* + * Internal API + */ +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); + + +/* + * 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, 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); +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 +} +#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..13cffec1d --- /dev/null +++ b/src/cryptoconditions/src/json_rpc.c @@ -0,0 +1,331 @@ +#include "cryptoconditions.h" +#include "internal.h" +#include + +#ifdef __LP64__ +#include +#else +#include // Index into CTransaction.vjoinsplit +#endif + +static cJSON *jsonCondition(CC *cond) { + cJSON *root = cJSON_CreateObject(); + + char *uri = cc_conditionUri(cond); + cJSON_AddItemToObject(root, "uri", cJSON_CreateString(uri)); + free(uri); + + unsigned char buf[1000]; + size_t conditionBinLength = cc_conditionBinary(cond, buf); + jsonAddHex(root, "bin", buf, conditionBinLength); + + return root; +} + + +static cJSON *jsonFulfillment(CC *cond) { + uint8_t buf[1000000]; + size_t fulfillmentBinLength = cc_fulfillmentBinary(cond, buf, 1000000); + + cJSON *root = cJSON_CreateObject(); + jsonAddHex(root, "fulfillment", buf, fulfillmentBinLength); + return root; +} + + +CC *cc_conditionFromJSON(cJSON *params, 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, CCTypeRegistry[i]->name)) { + return CCTypeRegistry[i]->fromJSON(params, err); + } + } + } + strcpy(err, "cannot detect type of condition"); + return NULL; +} + + +CC *cc_conditionFromJSONString(const char *data, char *err) { + cJSON *params = cJSON_Parse(data); + CC *out = cc_conditionFromJSON(params, err); + cJSON_Delete(params); + return out; +} + + +static cJSON *jsonEncodeCondition(cJSON *params, 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, 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(char *err) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "error", cJSON_CreateString(err)); + return out; +} + + +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; + + 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); + + 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, char *err) { + size_t ffill_bin_len; + unsigned char *ffill_bin; + if (!jsonGetHex(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, char *err) { + size_t cond_bin_len; + unsigned char *cond_bin; + if (!jsonGetHex(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, 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 (!jsonGetHex(params, "privateKey", err, &sk, &skLength)) { + goto END; + } + + if (skLength != 32) { + strcpy(err, "privateKey wrong length"); + } + + size_t msgLength; + if (!jsonGetHex(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, 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 (!jsonGetHex(params, "privateKey", err, &sk, &skLength)) { + goto END; + } + + if (skLength != SECP256K1_SK_SIZE) { + strcpy(err, "privateKey wrong length"); + } + + size_t msgLength; + if (!jsonGetHex(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; +} + + +char *cc_conditionToJSONString(const CC *cond) { + assert(cond != NULL); + cJSON *params = cc_conditionToJSON(cond); + char *out = cJSON_Print(params); + cJSON_Delete(params); + return out; +} + + +static cJSON *jsonListMethods(cJSON *params, char *err); + + +typedef struct JsonMethod { + char *name; + cJSON* (*method)(cJSON *params, char *err); + 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, char *err) { + cJSON *list = cJSON_CreateArray(); + for (int i=0; ivaluestring)) { + return method.method(params, err); + } + } + + return jsonErr("invalid method"); +} + + +char *cc_jsonRPC(char* input) { + 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); + } + 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..66d432bd2 --- /dev/null +++ b/src/cryptoconditions/src/prefix.c @@ -0,0 +1,123 @@ + +#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 = cc_new(CC_Prefix); + 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 cc_typeMask(cond->subcondition) & ~(1 << CC_Prefix); +} + + +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"); + return NULL; + } + + cJSON *subcond_item = cJSON_GetObjectItem(params, "subfulfillment"); + CC *sub = cc_conditionFromJSON(subcond_item, err); + if (!sub) { + return NULL; + } + + CC *cond = cc_new(CC_Prefix); + 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); +} + + +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 new file mode 100644 index 000000000..2e3ec7c77 --- /dev/null +++ b/src/cryptoconditions/src/preimage.c @@ -0,0 +1,74 @@ + +#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, char *err) { + CC *cond = cc_new(CC_Preimage); + if (!jsonGetBase64(params, "preimage", err, &cond->preimage, &cond->preimageLength)) { + free(cond); + return NULL; + } + return cond; +} + + +static void preimageToJSON(const CC *cond, cJSON *params) { + jsonAddBase64(params, "preimage", cond->preimage, cond->preimageLength); +} + + +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 = 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); + 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); +} + + +static uint32_t preimageSubtypes(const CC *cond) { + return 0; +} + + +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 new file mode 100644 index 000000000..78b9c4e9e --- /dev/null +++ b/src/cryptoconditions/src/secp256k1.c @@ -0,0 +1,288 @@ +#define _GNU_SOURCE 1 + +#if __linux +#include +#elif defined(_WIN32) || defined(_WIN64) +#include +#endif + +#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 *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; + initVerify(); + + 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; +} + + +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)) { + // 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_Secp256k1) return 1; + CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context; + if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1; + + secp256k1_ecdsa_signature sig; + lockSign(); + int rc = secp256k1_ecdsa_sign(ec_ctx_sign, &sig, visitor.msg, signing->sk, NULL, NULL); + unlockSign(); + + 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; +} + + +/* + * 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_Prefix)) { + // No support for prefix currently, due to pending protocol decision on + // 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) { + fprintf(stderr, "Cryptoconditions couldn't derive secp256k1 pubkey\n"); + 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}; + 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) { + // Check that pk parses + initVerify(); + 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) { + sig = calloc(1, SECP256K1_SIG_SIZE); + memcpy(sig, signature, SECP256K1_SIG_SIZE); + } + + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = pk; + cond->signature = sig; + return cond; +} + + +static CC *secp256k1FromJSON(const cJSON *params, char *err) { + CC *cond = 0; + unsigned char *pk = 0, *sig = 0; + size_t pkSize, sigSize; + + if (!jsonGetHex(params, "publicKey", err, &pk, &pkSize)) 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; + } + + 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) { + jsonAddHex(params, "publicKey", cond->publicKey, SECP256K1_PK_SIZE); + if (cond->signature) { + jsonAddHex(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); + } +} + + +static uint32_t secp256k1Subtypes(const CC *cond) { + return 0; +} + + +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/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..9c1800302 --- /dev/null +++ b/src/cryptoconditions/src/threshold.c @@ -0,0 +1,229 @@ + +#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 |= cc_typeMask(cond->subconditions[i]); + } + mask &= ~(1 << CC_Threshold); + 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; isize; i++) { + if (!cc_visit(cond->subconditions[i], visitor)) { + return 0; + } + } + return 1; +} + + +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); + + // 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; +} + + +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++) { + Condition_t *asnCond = asnConditionNew(cond->subconditions[i]); + asn_set_add(&fp->subconditions2, asnCond); + } + qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditionBin); + return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp); +} + + +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; + 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; jthreshold = threshold; + cond->size = size; + cond->subconditions = subconditions; + return cond; +} + + +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(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 = subconditions[i]; + if (needed && (fulfillment = asnFulfillmentNew(sub))) { + asn_set_add(&tf->subfulfillments, fulfillment); + needed--; + } else { + asn_set_add(&tf->subconditions, asnConditionNew(sub)); + } + } + + free(subconditions); + + 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, 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 = cc_new(CC_Threshold); + 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; isize; 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); +} + + +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 new file mode 100644 index 000000000..b795932b3 --- /dev/null +++ b/src/cryptoconditions/src/utils.c @@ -0,0 +1,289 @@ +#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, 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 checkDecodeBase64(item, key, err, data, 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; + } + return checkDecodeBase64(item, key, err, data, 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); +} + + +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) { + 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/test-requirements.txt b/src/cryptoconditions/test-requirements.txt new file mode 100644 index 000000000..3e7a933b9 --- /dev/null +++ b/src/cryptoconditions/test-requirements.txt @@ -0,0 +1,3 @@ +base58==0.2.5 +secp256k1 +pytest 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/test_ed25519.py b/src/cryptoconditions/tests/test_ed25519.py new file mode 100644 index 000000000..ba97bdd9d --- /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': 'D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', + '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': 'D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', + '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': '225A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', + '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..59b0b3f24 --- /dev/null +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -0,0 +1,85 @@ +import json +import ctypes +import base64 +from .test_vectors import jsonRPC, so, decode_base64 as d64, encode_base64 as e64 + + +''' +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(b'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 + + +def test_non_canonical_secp256k1(): + cond = { + "type": "secp256k1-sha-256", + "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA", + # Signature is correct, but non canonical; validation should fail + "signature": "9C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DAC32138302B2C208E6E424DD9C702790AE10B241B89C8D0A06B01CB708334AB6E" + } + res = jsonRPC('verifyFulfillment', { + 'fulfillment': jsonRPC('encodeFulfillment', cond)['fulfillment'], + 'condition': jsonRPC('encodeCondition', cond)['bin'], + '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/cryptoconditions/tests/test_secp256k1.py b/src/cryptoconditions/tests/test_secp256k1.py new file mode 100644 index 000000000..fe3c72b67 --- /dev/null +++ b/src/cryptoconditions/tests/test_secp256k1.py @@ -0,0 +1,66 @@ +import json +import base64 +import hashlib +import secp256k1 +from .test_vectors import jsonRPC + + +key = secp256k1.PrivateKey() + + +def test_sign_secp256k1_pass_simple(): + pubkey = encode_b16(key.pubkey.serialize()) + msg = '' + res = jsonRPC('signTreeSecp256k1', { + 'condition': { + 'type': 'secp256k1-sha-256', + 'publicKey': pubkey, + }, + 'privateKey': encode_b16(key.private_key), + 'message': msg, + }) + + sig = encode_b16(key.ecdsa_serialize_compact(key.ecdsa_sign(msg.encode()))) + + 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_b16(key.pubkey.serialize()) + msg = '' + res = jsonRPC('signTreeSecp256k1', { + 'condition': { + 'type': 'secp256k1-sha-256', + 'publicKey': pubkey, + }, + 'privateKey': encode_b16(b'0' * 32), + 'message': msg, + }) + + assert res == { + "num_signed": 0, + "condition": { + "type": "secp256k1-sha-256", + "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 new file mode 100644 index 000000000..884d695be --- /dev/null +++ b/src/cryptoconditions/tests/test_vectors.py @@ -0,0 +1,152 @@ +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): + if type(data) == str: + data = data.encode() + return base64.urlsafe_b64encode(data).rstrip(b'=').decode() + + +def b16_to_b64(b16): + if type(b16) == str: + b16 = b16.encode() + 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): + 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, + 'params': params, + }) + out = so.cc_jsonRPC(req.encode()) + return json.loads(out.decode()) 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/vectors/1001_test-minimal-secp256k1.json b/src/cryptoconditions/tests/vectors/1001_test-minimal-secp256k1.json new file mode 100644 index 000000000..a85b29d91 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/1001_test-minimal-secp256k1.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "secp256k1-sha-256", + "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA", + "signature": "9C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DA3CDEC7CFD4D3DF7191BDB22638FD86F3D9A3B8CB257FCF9B54D0931C4D0195D3" + }, + "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/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 & diff --git a/src/deprecation.cpp b/src/deprecation.cpp index 9f394e720..73ff8046d 100644 --- a/src/deprecation.cpp +++ b/src/deprecation.cpp @@ -11,12 +11,13 @@ #include "chainparams.h" static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION); +extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; void EnforceNodeDeprecation(int nHeight, bool forceLogging) { // Do not enforce deprecation in regtest or on testnet std::string networkID = Params().NetworkIDString(); - if (networkID != "main") return; + if (networkID != "main" || ASSETCHAINS_SYMBOL[0] != 0 ) return; int blocksToDeprecation = DEPRECATION_HEIGHT - nHeight; bool disableDeprecation = (GetArg("-disabledeprecation", "") == CLIENT_VERSION_STR); @@ -58,4 +59,4 @@ void EnforceNodeDeprecation(int nHeight, bool forceLogging) { LogPrintf("*** %s\n", msg); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING); } -} \ No newline at end of file +} diff --git a/src/dpowassets b/src/dpowassets index bd970c357..f00ade7f6 100755 --- a/src/dpowassets +++ b/src/dpowassets @@ -2,9 +2,10 @@ set -x source pubkey.txt echo $pubkey +sleep 3 +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"KMD\",\"pubkey\":\"$pubkey\"}" - -curl --url "http://127.0.0.1:7776" --data "{\"timeout\":60000,\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"REVS\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"REVS\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SUPERNET\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"DEX\",\"pubkey\":\"$pubkey\"}" @@ -26,11 +27,11 @@ 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\":\"KMD\",\"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..ce2e7a51d 100755 --- a/src/fiat-cli +++ b/src/fiat-cli @@ -25,4 +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 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..3d1063d13 --- /dev/null +++ b/src/fiat/prlpay @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=PRLPAY $1 $2 $3 $4 $5 $6 diff --git a/src/fiat/verus b/src/fiat/verus index 78301bdaf..e0e37ab96 100644 --- a/src/fiat/verus +++ b/src/fiat/verus @@ -1,2 +1,2 @@ -./komodo-cli -ac_name=VERUSTEST -ac_algo=verushash -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=2,5,1440 -ac_decay=100000000,0,0 -ac_end=14,44,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=720 -ac_timeunlockto=1440 -addnode=65.49.54.162 "$@" - +#!/bin/bash +./komodo-cli -ac_name=VERUSTEST "$@" diff --git a/src/gtest/test_checkblock.cpp b/src/gtest/test_checkblock.cpp index e098cfdae..284cff134 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -22,6 +22,7 @@ public: MOCK_CONST_METHOD0(GetRejectReason, std::string()); }; +int32_t futureblock; TEST(CheckBlock, VersionTooLow) { auto verifier = libzcash::ProofVerifier::Strict(); @@ -30,7 +31,7 @@ TEST(CheckBlock, VersionTooLow) { MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1); - EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false)); + EXPECT_FALSE(CheckBlock(&futureblock,0,0,block, state, verifier, false, false)); } @@ -230,4 +231,4 @@ TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) { // Revert to default UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); -} \ No newline at end of file +} diff --git a/src/init.cpp b/src/init.cpp index 123e667d2..a937a035b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -70,6 +70,7 @@ using namespace std; extern void ThreadSendAlert(); +extern int32_t KOMODO_LOADINGBLOCKS; ZCJoinSplit* pzcashParams = NULL; @@ -370,7 +371,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); - + strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX)); + strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX)); + strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX)); strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); @@ -626,6 +629,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 @@ -1368,18 +1372,34 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } + // block tree db settings + int dbMaxOpenFiles = GetArg("-dbmaxopenfiles", DEFAULT_DB_MAX_OPEN_FILES); + bool dbCompression = GetBoolArg("-dbcompression", DEFAULT_DB_COMPRESSION); + + LogPrintf("Block index database configuration:\n"); + LogPrintf("* Using %d max open files\n", dbMaxOpenFiles); + LogPrintf("* Compression is %s\n", dbCompression ? "enabled" : "disabled"); + // cache size calculations int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache int64_t nBlockTreeDBCache = nTotalCache / 8; - if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", true)) - nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB + + if (GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) || GetBoolArg("-spentindex", DEFAULT_SPENTINDEX)) { + // enable 3/4 of the cache if addressindex and/or spentindex is enabled + nBlockTreeDBCache = nTotalCache * 3 / 4; + } else { + if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) { + nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB + } + } nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache nTotalCache -= nCoinDBCache; nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache LogPrintf("Cache configuration:\n"); + LogPrintf("* Max cache setting possible %.1fMiB\n", nMaxDbCache); LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); @@ -1400,7 +1420,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinscatcher; delete pblocktree; - pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinsTip = new CCoinsViewCache(pcoinscatcher); @@ -1427,7 +1447,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)) { strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); @@ -1489,6 +1509,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.h b/src/komodo.h index cc15174fb..5b2872946 100644 --- a/src/komodo.h +++ b/src/komodo.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 * @@ -54,6 +54,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char #include "komodo_jumblr.h" #include "komodo_gateway.h" #include "komodo_events.h" +#include "komodo_ccdata.h" void komodo_currentheight_set(int32_t height) { @@ -356,6 +357,7 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar if ( didinit == 0 ) { portable_mutex_init(&KOMODO_KV_mutex); + portable_mutex_init(&KOMODO_CC_mutex); didinit = 1; } if ( (sp= komodo_stateptr(symbol,dest)) == 0 ) @@ -505,10 +507,35 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar } } +int32_t komodo_validate_chain(uint256 srchash,int32_t notarized_height) +{ + static int32_t last_rewind; int32_t rewindtarget; CBlockIndex *pindex; struct komodo_state *sp; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; + if ( (sp= komodo_stateptr(symbol,dest)) == 0 ) + return(0); + if ( IsInitialBlockDownload() == 0 && ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != notarized_height) ) + { + if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < notarized_height ) + rewindtarget = sp->NOTARIZED_HEIGHT - 1; + else if ( notarized_height > 101 ) + rewindtarget = notarized_height - 101; + 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,notarized_height,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT,rewindtarget); + } + last_rewind = rewindtarget; + } + return(0); + } else return(1); +} + 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,offset,k,MoMdepth,matched,len = 0; uint256 MoM,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 ) @@ -555,6 +582,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } if ( scriptbuf[len++] == 0x6a ) { + struct komodo_ccdata ccdata; struct komodo_ccdataMoMoM MoMoMdata; + int32_t validated = 0,nameoffset,opoffset = 0; if ( (opretlen= scriptbuf[len++]) == 0x4c ) opretlen = scriptbuf[len++]; else if ( opretlen == 0x4d ) @@ -562,81 +591,149 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr opretlen = scriptbuf[len++]; opretlen += (scriptbuf[len++] << 8); } - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - 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 ) + opoffset = len; + matched = 0; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { - len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&kmdtxid); - 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 ) - { + if ( strcmp("KMD",(char *)&scriptbuf[len+32 * 2 + 4]) == 0 ) + matched = 1; + } + else + { + if ( strcmp(ASSETCHAINS_SYMBOL,(char *)&scriptbuf[len+32*2+4]) == 0 ) + matched = 1; + } + offset = 32 * (1 + matched) + 4; + nameoffset = (int32_t)strlen((char *)&scriptbuf[len+offset]); + if ( nameoffset == 2 ) + nameoffset += 2; + else nameoffset++; + memset(&ccdata,0,sizeof(ccdata)); + strncpy(ccdata.symbol,(char *)&scriptbuf[len+offset],sizeof(ccdata.symbol)); + if ( j == 1 && opretlen >= len+offset-opoffset ) + { + memset(&MoMoMdata,0,sizeof(MoMoMdata)); + if ( matched == 0 && bitweight(signedmask) >= KOMODO_MINRATIFY ) 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;*/ - if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) + if ( strcmp("PIZZA",ccdata.symbol) == 0 || strncmp("SCALE",ccdata.symbol,5) == 0 ) + notarized = 1; + if ( 0 && opretlen != 149 ) + printf("[%s].%d (%s) matched.%d i.%d j.%d notarized.%d %llx opretlen.%d len.%d offset.%d opoffset.%d\n",ASSETCHAINS_SYMBOL,height,ccdata.symbol,matched,i,j,notarized,(long long)signedmask,opretlen,len,offset,opoffset); + len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&srchash); + len += iguana_rwnum(0,&scriptbuf[len],sizeof(*notarizedheightp),(uint8_t *)notarizedheightp); + if ( matched != 0 ) + len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&desttxid); + if ( matched != 0 ) + validated = komodo_validate_chain(srchash,*notarizedheightp); + else validated = 1; + if ( notarized != 0 && validated != 0 ) { - int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; - sp->NOTARIZED_HEIGHT = *notarizedheightp; - sp->NOTARIZED_HASH = kmdtxid; - sp->NOTARIZED_DESTTXID = desttxid; - memset(&sp->MoM,0,sizeof(sp->MoM)); - sp->MoMdepth = 0; - if ( len+36 <= opretlen ) + //sp->NOTARIZED_HEIGHT = *notarizedheightp; + //sp->NOTARIZED_HASH = srchash; + //sp->NOTARIZED_DESTTXID = desttxid; + memset(&MoM,0,sizeof(MoM)); + MoMdepth = 0; + len += nameoffset; + ccdata.MoMdata.notarized_height = *notarizedheightp; + ccdata.MoMdata.height = height; + ccdata.MoMdata.txi = i; + //printf("nameoffset.%d len.%d + 36 %d vs opretlen.%d\n",nameoffset,len,len+36,opretlen); + if ( len+36-opoffset <= opretlen ) { - len += iguana_rwbignum(0,&scriptbuf[len+nameoffset],32,(uint8_t *)&sp->MoM); - len += iguana_rwnum(0,&scriptbuf[len+nameoffset],sizeof(sp->MoMdepth),(uint8_t *)&sp->MoMdepth); - if ( sp->MoM == zero || sp->MoMdepth > 1440 || sp->MoMdepth < 0 ) + len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&MoM); + len += iguana_rwnum(0,&scriptbuf[len],sizeof(MoMdepth),(uint8_t *)&MoMdepth); + ccdata.MoMdata.MoM = MoM; + ccdata.MoMdata.MoMdepth = MoMdepth; + if ( len+sizeof(ccdata.CCid)-opoffset <= opretlen ) { - memset(&sp->MoM,0,sizeof(sp->MoM)); - sp->MoMdepth = 0; + len += iguana_rwnum(0,&scriptbuf[len],sizeof(ccdata.CCid),(uint8_t *)&ccdata.CCid); + ccdata.len = sizeof(ccdata.CCid); + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + // MoMoM, depth, numpairs, (notarization ht, MoMoM offset) + if ( len+48-opoffset <= opretlen && strcmp(ccdata.symbol,ASSETCHAINS_SYMBOL) == 0 ) + { + len += iguana_rwnum(0,&scriptbuf[len],sizeof(uint32_t),(uint8_t *)&MoMoMdata.kmdstarti); + len += iguana_rwnum(0,&scriptbuf[len],sizeof(uint32_t),(uint8_t *)&MoMoMdata.kmdendi); + len += iguana_rwbignum(0,&scriptbuf[len],sizeof(MoMoMdata.MoMoM),(uint8_t *)&MoMoMdata.MoMoM); + len += iguana_rwnum(0,&scriptbuf[len],sizeof(uint32_t),(uint8_t *)&MoMoMdata.MoMoMdepth); + len += iguana_rwnum(0,&scriptbuf[len],sizeof(uint32_t),(uint8_t *)&MoMoMdata.numpairs); + MoMoMdata.len += sizeof(MoMoMdata.MoMoM) + sizeof(uint32_t)*4; + if ( len+MoMoMdata.numpairs*8-opoffset == opretlen ) + { + MoMoMdata.pairs = (struct komodo_ccdatapair *)calloc(MoMoMdata.numpairs,sizeof(*MoMoMdata.pairs)); + for (k=0; k *notarizedheightp || MoMdepth < 0 ) + { + memset(&MoM,0,sizeof(MoM)); + MoMdepth = 0; } else { - //printf("VALID %s MoM.%s [%d]\n",ASSETCHAINS_SYMBOL,sp->MoM.ToString().c_str(),sp->MoMdepth); + komodo_rwccdata(ASSETCHAINS_SYMBOL,1,&ccdata,&MoMoMdata); + if ( matched != 0 ) + printf("[%s] matched.%d VALID (%s) MoM.%s [%d]\n",ASSETCHAINS_SYMBOL,matched,ccdata.symbol,MoM.ToString().c_str(),MoMdepth); } + if ( MoMoMdata.pairs != 0 ) + free(MoMoMdata.pairs); + memset(&ccdata,0,sizeof(ccdata)); + memset(&MoMoMdata,0,sizeof(MoMoMdata)); } - 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); - if ( ASSETCHAINS_SYMBOL[0] == 0 ) + else if ( ASSETCHAINS_SYMBOL[0] == 0 && matched != 0 && notarized != 0 && validated != 0 ) + komodo_rwccdata((char *)"KMD",1,&ccdata,0); + if ( matched != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height ) { - if ( signedfp == 0 ) + sp->NOTARIZED_HEIGHT = *notarizedheightp; + sp->NOTARIZED_HASH = srchash; + sp->NOTARIZED_DESTTXID = desttxid; + sp->MoM = MoM; + sp->MoMdepth = MoMdepth; + komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth); + 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,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 ) { - char fname[512]; - komodo_statefname(fname,ASSETCHAINS_SYMBOL,(char *)"signedmasks"); - if ( (signedfp= fopen(fname,"rb+")) == 0 ) - signedfp = fopen(fname,"wb"); - else fseek(signedfp,0,SEEK_END); - } - if ( signedfp != 0 ) - { - fwrite(&height,1,sizeof(height),signedfp); - fwrite(&signedmask,1,sizeof(signedmask),signedfp); - fflush(signedfp); - } - if ( opretlen > len && scriptbuf[len] == 'A' ) - { - //for (i=0; i len && scriptbuf[len] == 'A' ) + { + //for (i=0; i= 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 ( opretlen != 149 && height > 600000 && matched != 0 ) + printf("%s validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s len.%d opretlen.%d\n",ccdata.symbol,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(),len,opretlen); } - else if ( i == 0 && j == 1 && opretlen == 149 ) + else if ( matched != 0 && i == 0 && j == 1 && opretlen == 149 ) { if ( notaryid >= 0 && notaryid < 64 ) komodo_paxpricefeed(height,&scriptbuf[len],opretlen); } - else + else if ( matched != 0 ) { //int32_t k; for (k=0; knHeight); @@ -711,7 +808,11 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) else { if ( pindex->nHeight != hwmheight ) + { printf("%s hwmheight.%d vs pindex->nHeight.%d t.%u reorg.%d\n",ASSETCHAINS_SYMBOL,hwmheight,pindex->nHeight,(uint32_t)pindex->nTime,hwmheight-pindex->nHeight); + komodo_purge_ccdata((int32_t)pindex->nHeight); + hwmheight = pindex->nHeight; + } komodo_event_rewind(sp,symbol,pindex->nHeight); komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0,zero,0); } diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index edd4d6569..e091a447e 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; @@ -557,20 +557,27 @@ 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,char *destaddr) { - CTransaction tx; - uint256 hashBlock; + CTxDestination address; CTransaction tx; uint256 hashBlock; + *valuep = 0; if (!GetTransaction(hash, tx, #ifndef KOMODO_ZCASH Params().GetConsensus(), #endif hashBlock, true)) { - //printf("null GetTransaction\n"); - return(tx.nLockTime); + fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); + return(0); } - 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; + if (ExtractDestination(tx.vout[n].scriptPubKey, address)) + strcpy(destaddr,CBitcoinAddress(address).ToString().c_str()); + } + return(tx.nLockTime); } void komodo_disconnect(CBlockIndex *pindex,CBlock& block) @@ -585,7 +592,6 @@ void komodo_disconnect(CBlockIndex *pindex,CBlock& block) } else printf("komodo_disconnect: ht.%d cant get komodo_state.(%s)\n",pindex->nHeight,ASSETCHAINS_SYMBOL); } - int32_t komodo_is_notarytx(const CTransaction& tx) { uint8_t *ptr; static uint8_t crypto777[33]; @@ -644,7 +650,7 @@ int32_t komodo_block2height(CBlock *block) } if ( height != height2 ) { - fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch); + //fprintf(stderr,"block2height height.%d vs height2.%d, match.%d mismatch.%d\n",height,height2,match,mismatch); mismatch++; if ( height2 >= 0 ) height = height2; @@ -652,22 +658,28 @@ int32_t komodo_block2height(CBlock *block) return(height); } -void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) +int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block) { int32_t n; - memset(pubkey33,0,33); - if ( block.vtx[0].vout.size() > 0 ) + if ( KOMODO_LOADINGBLOCKS == 0 ) + memset(pubkey33,0xff,33); + else memset(pubkey33,0,33); + 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); + return(1); + } } + return(0); } int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex) @@ -715,67 +727,74 @@ uint32_t komodo_heightstamp(int32_t height) return(0); } +/*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; uint8_t pubkeys[64][33]; - //komodo_init(height); + int32_t num,i; CBlock block; memset(pubkey33,0,33); if ( pindex != 0 ) { - if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 ) - { - 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_block2pubkey33(pubkey33,&block); } } -/*void komodo_connectpindex(CBlockIndex *pindex) +/*int8_t komodo_minerid(int32_t height,uint8_t *destpubkey33) { - 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]; + 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); + if ( destpubkey33 != 0 ) + memcpy(destpubkey33,pindex->pubkey33,33); return(pindex->notaryid); } - if ( pubkey33 != 0 ) - komodo_index2pubkey33(pubkey33,pindex,height); + 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 ) { @@ -784,33 +803,33 @@ int8_t komodo_minerid(int32_t height,uint8_t *pubkey33) return(i); } } + fprintf(stderr,"komodo_minerid height.%d null pindex\n",height); return(komodo_electednotary(&numnotaries,pubkey33,height,timestamp)); -} +}*/ -int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height) +int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height) { - int32_t i,j,duplicate; CBlockIndex *pindex; uint8_t pubkey33[33]; + int32_t i,j,n,duplicate; CBlock block; CBlockIndex *pindex; uint8_t notarypubs33[64][33]; memset(mids,-1,sizeof(*mids)*66); + n = komodo_notaries(notarypubs33,height,0); for (i=duplicate=0; i<66; i++) { if ( (pindex= komodo_chainactive(height-i)) != 0 ) { - if ( pindex->notaryid >= 0 && (pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3) ) + blocktimes[i] = pindex->nTime; + if ( komodo_blockload(block,pindex) == 0 ) { - memcpy(pubkeys[i],pindex->pubkey33,33); - mids[i] = pindex->notaryid; - (*nonzpkeysp)++; - } - else - { - komodo_index2pubkey33(pubkey33,pindex,height-i); - memcpy(pubkeys[i],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++; } @@ -820,52 +839,96 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non else return(0); } -int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // deprecate +int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) { - /*int32_t i,n=0; - for (i=0; i= 225000 ) - komodo_chosennotary(¬aryid,height,pubkey33,timestamp); - if ( height >= 34000 && notaryid >= 0 ) + int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33]; + komodo_chosennotary(¬aryid,height,pubkey33,blocktimes[0]); + if ( height >= 82000 ) { - 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,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); - if ( height > 225000 ) - return(-1); + if ( mids[i] == notaryid ) + { + if ( height > 792000 ) + { + 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); + return(-1); + } else break; + } } + if ( blocktime != 0 && blocktimes[1] != 0 && blocktime < blocktimes[1]+57 ) + { + if ( height > 807000 ) + return(-2); + } + return(1); + } else return(0); + } + else + { + if ( height >= 34000 && notaryid >= 0 ) + { + if ( height < 79693 ) + limit = 64; + else if ( height < 82000 ) + limit = 8; + else limit = 66; + for (i=1; i 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); } -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; @@ -900,7 +963,7 @@ int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 has fprintf(stderr,"[%s] nHeight.%d == NOTARIZED_HEIGHT.%d, diff hash\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); return(-1); } - } 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 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); @@ -972,7 +1035,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ cmptime -= 16000; if ( (int64_t)tx.nLockTime < cmptime-3600 ) { - if ( tx.nLockTime != 1477258935 || dispflag != 0 ) + if ( tx.nLockTime != 1477258935 && dispflag != 0 ) { fprintf(stderr,"komodo_validate_interest.%d reject.%d [%d] locktime %u cmp2.%u\n",dispflag,txheight,(int32_t)(tx.nLockTime - (cmptime-3600)),(uint32_t)tx.nLockTime,cmptime); } @@ -984,3 +1047,313 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ } return(0); } + +/* + komodo_checkPOW (fast) is called early in the process and should only refer to data immediately available. it is a filter to prevent bad blocks from going into the local DB. The more blocks we can filter out at this stage, the less junk in the local DB that will just get purged later on. + + komodo_checkPOW (slow) is called right before connecting blocks so all prior blocks can be assumed to be there and all checks must pass + + commission must be in coinbase.vout[1] and must be >= 10000 sats + PoS stake must be without txfee and in the last tx in the block at vout[0] + PoW mining on PoS chain must solve a harder diff that adjusts, but never less than KOMODO_POWMINMULT + */ +#define KOMODO_POWMINMULT 16 + +uint64_t komodo_commission(const CBlock *pblock) +{ + int32_t i,j,n=0,txn_count; uint64_t commission,total = 0; + txn_count = pblock->vtx.size(); + for (i=0; ivtx[i].vout.size(); + for (j=0; jvtx[i].vout[j].nValue; + } + } + //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); + commission = ((total * ASSETCHAINS_COMMISSION) / COIN); + if ( commission < 10000 ) + commission = 0; + return(commission); +} + +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; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; + uint64_t value,coinage,supply = komodo_current_supply(nHeight); + txtime = komodo_txtime(&value,txid,vout,address); + if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) + return(0); + if ( (minage= nHeight*3) > 6000 ) + minage = 6000; + if ( blocktime < prevtime+57 ) + blocktime = prevtime+57; + 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)); + 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); + for (iter=0; 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 ) + { + winner = 1; + if ( validateflag == 0 ) + { + blocktime += iter; + blocktime += segid * 2; + } + 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 diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(int32_t)diff); + break; + } + } + //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); + 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," 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 ) + return(blocktime); + return(blocktime * winner); +} + +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,diff,val; + *percPoSp = percPoS = 0; + if ( height < 3 ) + return(target); + 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 + { + fprintf(stderr,"1"); + sum += hashval; + n++; + } + else + { + percPoS++; + fprintf(stderr,"0"); + } + if ( (i % 10) == 9 ) + fprintf(stderr," %d, ",percPoS); + } + } + fprintf(stderr," -> %d%% percPoS ht.%d\n",percPoS,height); + *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(percPoS * percPoS)) / arith_uint256((goalperc) * (goalperc)); + /*if ( height > 1165 ) + { + if ( height > 1180 ) + { + if ( height > 1230 ) + bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256((goalperc) * (goalperc)); + else bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc); + } + else bnTarget = (ave * arith_uint256(goalperc * goalperc)) / arith_uint256(2 * (percPoS + goalperc) * (percPoS + goalperc)); + } else bnTarget = (ave * arith_uint256(goalperc)) / arith_uint256(percPoS + goalperc);*/ + if ( 1 ) + { + 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); + if ( 1 ) + { + 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_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget) +{ + CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible,isPoS = 0; uint64_t value; CTxDestination voutaddress; + txn_count = pblock->vtx.size(); + if ( txn_count > 1 ) + { + if ( prevtime == 0 ) + { + if ( (previndex= mapBlockIndex[pblock->hashPrevBlock]) != 0 ) + prevtime = (uint32_t)previndex->nTime; + } + txid = pblock->vtx[txn_count-1].vin[0].prevout.hash; + vout = pblock->vtx[txn_count-1].vin[0].prevout.n; + if ( prevtime != 0 ) + { + eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime,(char *)""); + if ( eligible == 0 || eligible > pblock->nTime ) + { + fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime)); + } else isPoS = 1; + } + else if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx + { + txtime = komodo_txtime(&value,txid,vout,destaddr); + if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) + { + strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); + if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[txn_count-1].vout[0].nValue == value ) + isPoS = 1; // close enough for a pre-filter + else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue)); + } else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height); + } else return(-1); + } + return(isPoS); +} + +int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) +{ + uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev; + if ( !CheckEquihashSolution(pblock, Params()) ) + { + fprintf(stderr,"komodo_checkPOW slowflag.%d ht.%d CheckEquihashSolution failed\n",slowflag,height); + return(-1); + } + hash = pblock->GetHash(); + bnTarget.SetCompact(pblock->nBits,&fNegative,&fOverflow); + bhash = UintToArith256(hash); + possible = komodo_block2pubkey33(pubkey33,pblock); + //fprintf(stderr,"height.%d slowflag.%d possible.%d cmp.%d\n",height,slowflag,possible,bhash > bnTarget); + if ( height == 0 ) + { + if ( slowflag != 0 ) + return(0); + if ( (pprev= mapBlockIndex[pblock->hashPrevBlock]) != 0 ) + height = pprev->nHeight + 1; + if ( height == 0 ) + return(0); + } + if ( (ASSETCHAINS_SYMBOL[0] != 0 || height > 792000) && bhash > bnTarget ) + { + failed = 1; + if ( height > 0 && ASSETCHAINS_SYMBOL[0] == 0 ) // for the fast case + { + if ( (n= komodo_notaries(pubkeys,height,pblock->nTime)) > 0 ) + { + for (i=0; i= 2 ) // must PoS or have at least 16x better PoW + { + if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget)) == 0 ) + { + if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! + return(-1); + else + { + if ( slowflag != 0 ) + bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); + else bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT)); // lower bound + if ( bhash > bnTarget ) + { + for (i=31; i>=16; i--) + fprintf(stderr,"%02x",((uint8_t *)&bhash)[i]); + fprintf(stderr," > "); + for (i=31; i>=16; 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); + } + } + } else if ( is_PoSblock < 0 ) + return(-1); + } + if ( failed == 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 ) + { + checktoshis = komodo_commission(pblock); + if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) + return(-1); + else if ( checktoshis != 0 ) + { + script = (uint8_t *)pblock->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 ( pblock->vtx[0].vout[1].nValue != checktoshis ) + { + fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue)); + return(-1); + } + } + } + //fprintf(stderr,"komodo_checkPOW possible.%d slowflag.%d ht.%d notaryid.%d failed.%d\n",possible,slowflag,height,notaryid,failed); + if ( failed != 0 && possible == 0 && notaryid < 0 ) + return(-1); + else return(0); +} + diff --git a/src/komodo_cJSON.c b/src/komodo_cJSON.c index ca2c6517c..8569b7802 100755 --- a/src/komodo_cJSON.c +++ b/src/komodo_cJSON.c @@ -56,7 +56,7 @@ static int32_t cJSON_strcasecmp(const char *s1,const char *s2) // the following written by jl777 /****************************************************************************** - * 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 * diff --git a/src/komodo_ccdata.h b/src/komodo_ccdata.h new file mode 100644 index 000000000..058e38cee --- /dev/null +++ b/src/komodo_ccdata.h @@ -0,0 +1,295 @@ +/****************************************************************************** + * 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 * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#ifndef H_KOMODOCCDATA_H +#define H_KOMODOCCDATA_H + +struct komodo_ccdata *CC_data; +int32_t CC_firstheight; + +bits256 iguana_merkle(bits256 *tree,int32_t txn_count) +{ + int32_t i,n=0,prev; uint8_t serialized[sizeof(bits256) * 2]; + if ( txn_count == 1 ) + return(tree[0]); + prev = 0; + while ( txn_count > 1 ) + { + if ( (txn_count & 1) != 0 ) + tree[prev + txn_count] = tree[prev + txn_count-1], txn_count++; + n += txn_count; + for (i=0; i> 1)] = bits256_doublesha256(0,serialized,sizeof(serialized)); + } + prev = n; + txn_count >>= 1; + } + return(tree[n]); +} + +uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth) +{ + static uint256 zero; bits256 MoM,*tree; CBlockIndex *pindex; int32_t i; + if ( MoMdepth >= height ) + return(zero); + tree = (bits256 *)calloc(MoMdepth * 3,sizeof(*tree)); + for (i=0; ihashMerkleRoot,sizeof(bits256)); + else + { + free(tree); + return(zero); + } + } + MoM = iguana_merkle(tree,MoMdepth); + free(tree); + return(*(uint256 *)&MoM); +} + +struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi) +{ + struct komodo_ccdata_entry *allMoMs=0; bits256 *tree,tmp; struct komodo_ccdata *ccdata,*tmpptr; int32_t i,num,max; + num = max = 0; + portable_mutex_lock(&KOMODO_CC_mutex); + DL_FOREACH_SAFE(CC_data,ccdata,tmpptr) + { + if ( ccdata->MoMdata.height <= kmdendi && ccdata->MoMdata.height >= kmdstarti ) + { + if ( num >= max ) + { + max += 100; + allMoMs = (struct komodo_ccdata_entry *)realloc(allMoMs,max * sizeof(*allMoMs)); + } + allMoMs[num].MoM = ccdata->MoMdata.MoM; + allMoMs[num].notarized_height = ccdata->MoMdata.notarized_height; + allMoMs[num].kmdheight = ccdata->MoMdata.height; + allMoMs[num].txi = ccdata->MoMdata.txi; + strcpy(allMoMs[num].symbol,ccdata->symbol); + num++; + } + if ( ccdata->MoMdata.height < kmdstarti ) + break; + } + portable_mutex_unlock(&KOMODO_CC_mutex); + if ( (*nump= num) > 0 ) + { + tree = (bits256 *)calloc(sizeof(bits256),num*3); + for (i=0; i= 0) { + if ( mdata->numpairs >= maxpairs ) + { + maxpairs += 100; + mdata->pairs = (struct komodo_ccdatapair *)realloc(mdata->pairs,sizeof(*mdata->pairs)*maxpairs); + //fprintf(stderr,"pairs reallocated to %p num.%d\n",mdata->pairs,mdata->numpairs); + } + } else { + fprintf(stderr,"komodo_addpair.maxpairs %d must be >= 0\n",(int32_t)maxpairs); + return(-1); + } + mdata->pairs[mdata->numpairs].notarized_height = notarized_height; + mdata->pairs[mdata->numpairs].MoMoMoffset = offset; + mdata->numpairs++; + return(maxpairs); +} + +int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height) +{ + uint8_t hexdata[8192]; struct komodo_ccdata *ccdata,*tmpptr; int32_t len,maxpairs,i,retval=-1,depth,starti,endi,CCid=0; struct komodo_ccdata_entry *allMoMs; + starti = endi = depth = len = maxpairs = 0; + hexstr[0] = 0; + if ( sizeof(hexdata)*2+1 > hexsize ) + { + fprintf(stderr,"hexsize.%d too small for %d\n",hexsize,(int32_t)sizeof(hexdata)); + return(-1); + } + memset(mdata,0,sizeof(*mdata)); + portable_mutex_lock(&KOMODO_CC_mutex); + DL_FOREACH_SAFE(CC_data,ccdata,tmpptr) + { + if ( ccdata->MoMdata.height < kmdheight ) + { + //fprintf(stderr,"%s notarized.%d kmd.%d\n",ccdata->symbol,ccdata->MoMdata.notarized_height,ccdata->MoMdata.height); + if ( strcmp(ccdata->symbol,symbol) == 0 ) + { + if ( endi == 0 ) + { + endi = ccdata->MoMdata.height; + CCid = ccdata->CCid; + } + if ( (mdata->numpairs == 1 && notarized_height == 0) || ccdata->MoMdata.notarized_height <= notarized_height ) + { + starti = ccdata->MoMdata.height + 1; + if ( notarized_height == 0 ) + notarized_height = ccdata->MoMdata.notarized_height; + break; + } + } + starti = ccdata->MoMdata.height; + } + } + portable_mutex_unlock(&KOMODO_CC_mutex); + mdata->kmdstarti = starti; + mdata->kmdendi = endi; + if ( starti != 0 && endi != 0 && endi >= starti ) + { + if ( (allMoMs= komodo_allMoMs(&depth,&mdata->MoMoM,starti,endi)) != 0 ) + { + mdata->MoMoMdepth = depth; + for (i=0; inumpairs > 0 ) + { + len += iguana_rwnum(1,&hexdata[len],sizeof(CCid),(uint8_t *)&CCid); + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->kmdstarti); + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->kmdendi); + len += iguana_rwbignum(1,&hexdata[len],sizeof(mdata->MoMoM),(uint8_t *)&mdata->MoMoM); + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->MoMoMdepth); + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->numpairs); + for (i=0; inumpairs; i++) + { + if ( len + sizeof(uint32_t)*2 > sizeof(hexdata) ) + { + fprintf(stderr,"%s %d %d i.%d of %d exceeds hexdata.%d\n",symbol,kmdheight,notarized_height,i,mdata->numpairs,(int32_t)sizeof(hexdata)); + break; + } + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->pairs[i].notarized_height); + len += iguana_rwnum(1,&hexdata[len],sizeof(uint32_t),(uint8_t *)&mdata->pairs[i].MoMoMoffset); + } + if ( i == mdata->numpairs && len*2+1 < hexsize ) + { + init_hexbytes_noT(hexstr,hexdata,len); + //fprintf(stderr,"hexstr.(%s)\n",hexstr); + retval = 0; + } else fprintf(stderr,"%s %d %d too much hexdata[%d] for hexstr[%d]\n",symbol,kmdheight,notarized_height,len,hexsize); + } + free(allMoMs); + } + } + return(retval); +} + +void komodo_purge_ccdata(int32_t height) +{ + struct komodo_ccdata *ccdata,*tmpptr; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + { + portable_mutex_lock(&KOMODO_CC_mutex); + DL_FOREACH_SAFE(CC_data,ccdata,tmpptr) + { + if ( ccdata->MoMdata.height >= height ) + { + printf("PURGE %s notarized.%d\n",ccdata->symbol,ccdata->MoMdata.notarized_height); + DL_DELETE(CC_data,ccdata); + free(ccdata); + } else break; + } + portable_mutex_unlock(&KOMODO_CC_mutex); + } + else + { + // purge notarized data + } +} + +// this is just a demo of ccdata processing to create example data for the MoMoM and allMoMs calls +int32_t komodo_rwccdata(char *thischain,int32_t rwflag,struct komodo_ccdata *ccdata,struct komodo_ccdataMoMoM *MoMoMdata) +{ + uint256 hash,zero; bits256 tmp; int32_t i,nonz; struct komodo_ccdata *ptr; struct notarized_checkpoint *np; + return(0); // disable this path as libscott method is much better + if ( rwflag == 0 ) + { + // load from disk + } + else + { + // write to disk + } + if ( ccdata->MoMdata.height > 0 && (CC_firstheight == 0 || ccdata->MoMdata.height < CC_firstheight) ) + CC_firstheight = ccdata->MoMdata.height; + for (nonz=i=0; i<32; i++) + { + if ( (tmp.bytes[i]= ((uint8_t *)&ccdata->MoMdata.MoM)[31-i]) != 0 ) + nonz++; + } + if ( nonz == 0 ) + return(0); + memcpy(&hash,&tmp,sizeof(hash)); + //fprintf(stderr,"[%s] ccdata.%s id.%d notarized_ht.%d MoM.%s height.%d/t%d\n",ASSETCHAINS_SYMBOL,ccdata->symbol,ccdata->CCid,ccdata->MoMdata.notarized_height,hash.ToString().c_str(),ccdata->MoMdata.height,ccdata->MoMdata.txi); + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + { + if ( CC_data != 0 && (CC_data->MoMdata.height > ccdata->MoMdata.height || (CC_data->MoMdata.height == ccdata->MoMdata.height && CC_data->MoMdata.txi >= ccdata->MoMdata.txi)) ) + { + printf("out of order detected? SKIP CC_data ht.%d/txi.%d vs ht.%d/txi.%d\n",CC_data->MoMdata.height,CC_data->MoMdata.txi,ccdata->MoMdata.height,ccdata->MoMdata.txi); + } + else + { + ptr = (struct komodo_ccdata *)calloc(1,sizeof(*ptr)); + *ptr = *ccdata; + portable_mutex_lock(&KOMODO_CC_mutex); + DL_PREPEND(CC_data,ptr); + portable_mutex_unlock(&KOMODO_CC_mutex); + } + } + else + { + if ( MoMoMdata != 0 && MoMoMdata->pairs != 0 ) + { + for (i=0; inumpairs; i++) + { + if ( (np= komodo_npptr(MoMoMdata->pairs[i].notarized_height)) != 0 ) + { + memset(&zero,0,sizeof(zero)); + if ( memcmp(&np->MoMoM,&zero,sizeof(np->MoMoM)) == 0 ) + { + np->MoMoM = MoMoMdata->MoMoM; + np->MoMoMdepth = MoMoMdata->MoMoMdepth; + np->MoMoMoffset = MoMoMdata->MoMoMoffset; + np->kmdstarti = MoMoMdata->kmdstarti; + np->kmdendi = MoMoMdata->kmdendi; + } + else if ( memcmp(&np->MoMoM,&MoMoMdata->MoMoM,sizeof(np->MoMoM)) != 0 || np->MoMoMdepth != MoMoMdata->MoMoMdepth || np->MoMoMoffset != MoMoMdata->MoMoMoffset || np->kmdstarti != MoMoMdata->kmdstarti || np->kmdendi != MoMoMdata->kmdendi ) + { + fprintf(stderr,"preexisting MoMoM mismatch: %s (%d %d %d %d) vs %s (%d %d %d %d)\n",np->MoMoM.ToString().c_str(),np->MoMoMdepth,np->MoMoMoffset,np->kmdstarti,np->kmdendi,MoMoMdata->MoMoM.ToString().c_str(),MoMoMdata->MoMoMdepth,MoMoMdata->MoMoMoffset,MoMoMdata->kmdstarti,MoMoMdata->kmdendi); + } + } + } + } + } + return(1); +} + +#endif diff --git a/src/komodo_curve25519.h b/src/komodo_curve25519.h index a7283e265..90d9a7e00 100644 --- a/src/komodo_curve25519.h +++ b/src/komodo_curve25519.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 * diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 78859e00d..52377f0b6 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -6,5 +6,6 @@ #define KOMODO_ELECTION_GAP 2000 #define ROUNDROBIN_DELAY 61 #define KOMODO_ASSETCHAIN_MAXLEN 65 +#define KOMODO_LIMITED_NETWORKSIZE 4 #endif diff --git a/src/komodo_events.h b/src/komodo_events.h index 315a78686..53e72ae95 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); @@ -39,23 +39,24 @@ 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 ) + static uint32_t counter; int32_t verified=0; char *coin; struct komodo_event_notarized N; + coin = (ASSETCHAINS_SYMBOL[0] == 0) ? (char *)"KMD" : ASSETCHAINS_SYMBOL; + if ( (ASSETCHAINS_SYMBOL[0] == 0 && height > 814000) && NOTARY_PUBKEY33[0] != 0 && (verified= komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid)) < 0 ) { - if ( height > 50000 || ASSETCHAINS_SYMBOL[0] != 0 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && height > 814000 && counter++ < 10 ) 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 ( strcmp(symbol,coin) == 0 ) { - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr,"validated [%s] ht.%d notarized %d\n",ASSETCHAINS_SYMBOL,height,notarizedheight); + if ( NOTARY_PUBKEY33[0] != 0 && verified != 0 ) + fprintf(stderr,"validated [%s] ht.%d notarized %d\n",coin,height,notarizedheight); memset(&N,0,sizeof(N)); N.blockhash = notarized_hash; N.desttxid = notarized_desttxid; 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 +78,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 +179,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 +189,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 diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c8fc03980..7eb5d9ab8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.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 * @@ -650,7 +650,7 @@ int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max) void komodo_passport_iteration(); -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; @@ -707,9 +707,11 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above { if ( overflow != 0 || total > COIN/10 ) { - //fprintf(stderr,">>>>>>>> <<<<<<<<<< ht.%d illegal nonz output %.8f n.%d\n",height,dstr(block.vtx[0].vout[1].nValue),n); if ( height >= activation ) + { + fprintf(stderr,">>>>>>>> <<<<<<<<<< ht.%d illegal nonz output %.8f n.%d\n",height,dstr(block.vtx[0].vout[1].nValue),n); return(-1); + } } else if ( block.nBits == KOMODO_MINDIFF_NBITS && total > 0 ) // to deal with fee stealing { @@ -725,333 +727,6 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } return(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 ) - return(-1); - total = 0; - for (i=1; i= 235300 ) - return(-1); - strcpy(symbol,(char *)"KMD"); - if ( komodo_isrealtime(&ht) == 0 || KOMODO_PASSPORT_INITDONE == 0 ) // init time already in DB - return(0); - } - else - { - strcpy(symbol,ASSETCHAINS_SYMBOL); - opcode = 'I'; - if ( (baseid= komodo_baseid(symbol)) < 0 ) - { - if ( block.vtx[0].vout.size() != 1 ) - { - printf("%s has more than one coinbase?\n",symbol); - return(-1); - } - return(0); - } - while ( KOMODO_PASSPORT_INITDONE == 0 ) - komodo_passport_iteration(); - komodo_passport_iteration(); - // grandfathering preexisting - if ( height < 777 ) - return(0); - if ( baseid == USD ) // 6820 in balance calcs - { - if ( height <= 6821 || height <= 2000 || height == 2968 || height == 2960 || height == 2649 || height == 3275 || height == 3282 || height == 3328 || height == 3468 ) - return(0); - } - else if ( baseid == EUR ) - { - if ( height < 1200 || height == 1408 || height == 1111 || height == 1094 || height == 1092 || height == 1080 || height == 1053 || height == 1005 || height == 822 || height == 821 || height == 810 || height == 797 || height == 790 || height == 787 || height == 785 || height == 1313 || height == 1288 || height == 1263 || height == 1262 || height <= 211 || height == 210 || height == 188 || height == 185 || height == 182 || height == 181 || height == 171 || height == 170 || height == 169 || height == 168 || height == 167 || height == 166 || height == 165 || height == 164 || height == 163 || height == 162 ) - return(0); - } - else if ( baseid == JPY ) - { - if ( height == 1038 || height == 1039 || height == 1040 || height == 1041 || height == 1014 || height == 998 || height == 973 || height == 139 || height == 971 || height == 141 || height == 816 || height == 814 || height == 803 || height == 142 || height == 782 || height == 145 || height == 181 || height == 186 || height == 192 || height == 190 || height == 189 || height == 255 || height == 218 || height == 233 || height == 259 || height == 278 || height == 361 || height == 367 || height == 733 || height == 688 || height == 468 ) - return(0); - } - else if ( baseid == GBP ) - { - if ( height == 1025 || height == 1026 || height == 1027 || height == 1028 || height == 997 || height == 970 || height == 953 || height == 951 || height == 803 || height == 800 || height == 786 || height == 123 || height == 771 || height == 137 || height == 139 || height == 140 || height == 146 || height == 194 || height == 200 || height == 202 || height == 203 || height == 205 || height == 210 || height == 216 || height == 271 || height == 233 || height == 294 ) - return(0); - } - else if ( baseid == AUD ) - { - if ( height == 1012 || height == 1013 || height == 1014 || height == 985 || height == 958 || height == 936 || height == 933 || height == 790 || height == 788 || height == 778 || height == 124 || height == 777 || height == 122 || height == 140 || height == 142 || height == 143 || height == 186 || height == 196 || height == 198 || height == 201 || height == 210 || height == 192 ) - return(0); - } - else if ( baseid == CAD ) - { - if ( height < 1000 || height == 836 || height == 781 || height == 779 || height == 798 || height == 794 || height == 1181 || height == 1179 || height == 1159 || height == 1134 || height == 1132 || height == 121 || height == 970 || height == 119 || height == 299 || height == 302 || height == 303 || height == 306 || height == 308 || height == 355 || height == 362 || height == 367 || height == 363 || height == 364 || height == 380 || height == 373 || height == 390 || height == 437 || height == 777 ) - return(0); - } - else if ( baseid == CHF ) - { - if ( height == 987 || height == 988 || height == 989 || height == 960 || height == 931 || height == 914 || height == 122 || height == 912 || height == 141 || height == 780 || height == 145 || height == 777 || height == 151 || height == 775 || height == 765 || height == 195 || height == 764 || height == 737 || height == 194 || height == 193 || height == 198 || height == 207 || height == 216 || height == 227 || height == 256 || height == 260 || height == 276 || height == 289 || height == 292 || height == 349 ) - return(0); - } - else if ( baseid == NZD ) - { - if ( height < 1000 || height == 787 || height == 786 || height == 784 || height == 785 || height == 777 || height == 1113 || height == 1083 || height == 1067 || height == 265 || height == 1064 || height == 920 || height == 913 || height == 124 || height == 911 || height == 903 || height == 900 || height == 879 || height == 122 || height == 266 || height == 269 || height == 270 || height == 278 || height == 307 || height == 318 || height == 322 || height == 335 || height == 395 || height == 406 || height == 314 ) - return(0); - } - else if ( baseid == CNY ) - { - if ( height == 987 || height == 988 || height == 989 || height == 982 || height == 957 || height == 931 || height == 119 || height == 929 || height == 134 || height == 782 || height == 137 || height == 775 || height == 143 || height == 772 || height == 186 || height == 763 || height == 761 || height == 734 || height == 183 || height == 190 || height == 192 || height == 211 || height == 203 || height == 226 || height == 263 || height == 264 || height == 277 || height == 342 || height == 613 || height == 525 ) - return(0); - } - else if ( baseid == RUB ) - { - if ( height == 819 || height == 812 || height == 810 || height == 802 || height == 801 || height == 1074 || height == 1040 || height == 1014 || height == 163 || height == 1013 || height == 877 || height == 867 || height == 863 || height == 834 || height == 158 || height == 126 || height == 106 || height == 105 || height == 174 || height == 175 || height == 176 || height == 177 || height == 181 || height == 183 || height == 184 || height == 187 ) - return(0); - } - else if ( baseid == MXN ) - { - if ( height == 1079 || height == 1080 || height == 1081 || height == 1069 || height == 1048 || height == 1028 || height == 121 || height == 1027 || height == 146 || height == 894 || height == 891 || height == 148 || height == 882 || height == 879 || height == 151 || height == 856 || height == 158 || height == 822 || height == 197 || height == 203 || height == 207 || height == 209 || height == 213 || height == 217 || height == 218 || height == 226 || height == 283 || height == 302 || height == 319 || height == 318 || height == 569 ) - return(0); - } - else if ( baseid == BRL ) - { - if ( height == 1003 || height == 1004 || height == 1005 || height == 972 || height == 943 || height == 922 || height == 118 || height == 920 || height == 145 || height == 787 || height == 783 || height == 147 || height == 781 || height == 774 || height == 148 || height == 771 || height == 154 || height == 751 || height == 156 || height == 188 || height == 193 || height == 195 || height == 199 || height == 203 || height == 225 || height == 230 || height == 262 || height == 266 || height == 284 || height == 300 || height == 640 ) - return(0); - } - else if ( baseid == INR ) - { - if ( height == 998 || height == 999 || height == 1000 || height == 788 || height == 786 || height == 775 || height == 753 || height == 125 || height == 153 || height == 155 || height == 159 || height == 204 || height == 206 || height == 211 || height == 217 || height == 220 || height == 229 || height == 265 || height == 292 || height == 300 ) - return(0); - } - else if ( baseid == PLN ) - { - if ( height == 1029 || height == 1030 || height == 1031 || height == 1009 || height == 984 || height == 960 || height == 959 || height == 798 || height == 794 || height == 792 || height == 782 || height == 775 || height == 755 || height == 122 || height == 120 || height == 158 || height == 160 || height == 163 || height == 225 || height == 217 || height == 219 || height == 229 || height == 234 || height == 286 || height == 231 || height == 292 ) - return(0); - } - else if ( baseid == HKD ) - { - if ( height == 1013 || height == 1014 || height == 1015 || height == 1002 || height == 979 || height == 947 || height == 123 || height == 946 || height == 153 || height == 811 || height == 808 || height == 806 || height == 155 || height == 795 || height == 157 || height == 773 || height == 205 || height == 208 || height == 210 || height == 211 || height == 215 || height == 221 || height == 231 || height == 255 || height == 273 || height == 293 || height == 310 || height == 654 ) - return(0); - } - else if ( baseid == TRY ) - { - if ( height == 1022 || height == 1023 || height == 1051 || height == 991 || height == 974 || height == 949 || height == 141 || height == 948 || height == 783 || height == 153 || height == 781 || height == 779 || height == 776 || height == 768 || height == 765 || height == 121 || height == 142 || height == 144 || height == 143 || height == 149 || height == 204 || height == 210 || height == 216 || height == 229 || height == 280 || height == 145 ) - return(0); - } - else if ( baseid == NOK ) - { - if ( height == 987 || height == 988 || height == 989 || height == 962 || height == 911 || height == 907 || height == 125 || height == 765 || height == 150 || height == 762 || height == 760 || height == 753 || height == 152 || height == 751 || height == 151 || height == 154 || height == 160 || height == 195 || height == 203 || height == 207 || height == 211 || height == 220 || height == 236 || height == 253 || height == 278 || height == 283 ) - return(0); - } - else if ( baseid == ZAR ) - { - if ( height == 979 || height == 980 || height == 981 || height == 956 || height == 937 || height == 906 || height == 905 || height == 122 || height == 756 || height == 754 || height == 752 || height == 749 || height == 742 || height == 739 || height == 120 || height == 151 || height == 153 || height == 157 || height == 159 || height == 206 || height == 213 || height == 216 || height == 222 || height == 277 || height == 287 || height == 215 ) - return(0); - } - else if ( baseid == SEK ) - { - if ( height == 960 || height == 961 || height == 962 || height == 943 || height == 925 || height == 896 || height == 147 || height == 894 || height == 759 || height == 751 || height == 749 || height == 742 || height == 740 || height == 716 || height == 123 || height == 148 || height == 150 || height == 151 || height == 157 || height == 199 || height == 200 || height == 201 || height == 206 || height == 256 || height == 257 || height == 268 ) - return(0); - } - else if ( baseid == CZK ) - { - if ( height < 1000 || height == 1084 || height == 1085 || height == 1086 || height == 778 || height == 1079 || height == 1054 || height == 1032 || height == 121 || height == 1030 || height == 182 || height == 876 || height == 873 || height == 871 || height == 184 || height == 862 || height == 185 || height == 861 || height == 186 || height == 838 || height == 238 || height == 242 || height == 246 || height == 248 || height == 250 || height == 251 || height == 256 || height == 282 || height == 322 || height == 343 || height == 433 || height == 323 || height == 276 ) - return(0); - } - else if ( baseid == HUF ) - { - if ( height < 2200 || height == 1531 || height == 1528 || height == 1530 || height == 1451 || height == 1448 || height == 1442 || height == 1418 || height == 1407 || height == 1406 || height == 1392 || height == 1391 || height == 1387 || height == 1383 || height == 1335 || height == 1337 || height == 1338 || height == 1649 || height == 2378 || height == 2376 || height == 2371 || height == 1330 || height == 2326 || height == 1344 || height == 2305 || height == 2304 || height == 2171 || height == 2168 || height == 2166 || height == 2156 || height == 2135 || height == 1343 || height == 1342 || height == 1341 || height == 1340 || height == 1339 || height == 1336 || height == 1334 || height == 1333 || height == 1346 || height == 1400 || height == 1525 || height == 1509 ) - return(0); - } - else if ( baseid == DKK ) - { - if ( height == 1241 || height == 945 || height == 898 || height == 894 || height == 892 || height == 866 || height == 857 || height == 853 || height == 834 || height == 812 || height == 792 || height == 784 || height == 778 || height == 783 || height == 1214 || height == 1186 || height == 1158 || height == 126 || height == 1156 || height == 329 || height == 1021 || height == 1016 || height == 1014 || height == 333 || height == 1003 || height == 1002 || height == 978 || height == 332 || height == 337 || height == 381 || height == 390 || height == 386 || height == 401 || height == 389 || height == 396 || height == 428 || height == 473 || height == 490 || height == 493 ) - return(0); - } - else if ( baseid == ILS ) - { - if ( height == 1017 || height == 1018 || height == 1019 || height == 1010 || height == 985 || height == 954 || height == 120 || height == 952 || height == 143 || height == 819 || height == 817 || height == 808 || height == 145 || height == 786 || height == 155 || height == 753 || height == 151 || height == 149 || height == 199 || height == 193 || height == 201 || height == 209 || height == 284 || height == 305 || height == 676 || height == 702 || height == 406 ) - return(0); - } - else if ( baseid == MYR ) - { - if ( height == 1020 || height == 1021 || height == 1022 || height == 1015 || height == 984 || height == 950 || height == 949 || height == 823 || height == 820 || height == 818 || height == 812 || height == 809 || height == 126 || height == 789 || height == 144 || height == 746 || height == 146 || height == 147 || height == 148 || height == 150 || height == 205 || height == 210 || height == 215 || height == 219 || height == 222 || height == 290 || height == 242 || height == 312 ) - return(0); - } - else if ( baseid == PHP ) - { - if ( height == 859 || height == 817 || height == 812 || height == 811 || height == 792 || height == 779 || height == 778 || height == 781 || height == 1154 || height == 1114 || height == 1077 || height == 1076 || height == 931 || height == 927 || height == 925 || height == 918 || height == 891 || height == 127 || height == 125 || height == 272 || height == 275 || height == 276 || height == 278 || height == 328 || height == 330 || height == 335 || height == 344 || height == 315 ) - return(0); - } - else if ( baseid == KRW ) - { - if ( height == 1021 || height == 1022 || height == 1023 || height == 1010 || height == 950 || height == 916 || height == 138 || height == 914 || height == 140 || height == 785 || height == 782 || height == 781 || height == 142 || height == 775 || height == 148 || height == 772 || height == 751 || height == 147 || height == 146 || height == 159 || height == 175 || height == 181 || height == 184 || height == 186 || height == 188 || height == 196 || height == 209 || height == 238 ) - return(0); - } - else if ( baseid == RON ) - { - if ( height == 1008 || height == 1009 || height == 1010 || height == 1003 || height == 973 || height == 940 || height == 939 || height == 806 || height == 802 || height == 800 || height == 793 || height == 789 || height == 768 || height == 123 || height == 141 || height == 143 || height == 144 || height == 150 || height == 197 || height == 200 || height == 202 || height == 217 || height == 240 || height == 276 ) - return(0); - } - else if ( baseid == SGD ) - { - if ( height == 1016 || height == 1017 || height == 1018 || height == 1010 || height == 984 || height == 951 || height == 950 || height == 801 || height == 798 || height == 792 || height == 788 || height == 122 || height == 769 || height == 120 || height == 158 || height == 160 || height == 164 || height == 169 || height == 229 || height == 234 || height == 246 || height == 297 || height == 299 || height == 316 || height == 233 ) - return(0); - } - else if ( baseid == THB ) - { - if ( height == 977 || height == 978 || height == 968 || height == 933 || height == 898 || height == 897 || height == 788 || height == 786 || height == 779 || height == 777 || height == 757 || height == 119 || height == 140 || height == 142 || height == 146 || height == 152 || height == 196 || height == 200 || height == 214 || height == 260 || height == 263 ) - return(0); - } - else if ( baseid == BGN ) - { - if ( height == 1044 || height == 1045 || height == 1046 || height == 1030 || height == 995 || height == 960 || height == 959 || height == 830 || height == 822 || height == 819 || height == 810 || height == 809 || height == 781 || height == 124 || height == 122 || height == 189 || height == 193 || height == 200 || height == 194 || height == 250 || height == 256 || height == 260 || height == 280 ) - return(0); - } - else if ( baseid == HRK ) - { - if ( height == 1027 || height == 1028 || height == 1029 || height == 1022 || height == 999 || height == 969 || height == 967 || height == 832 || height == 829 || height == 827 || height == 817 || height == 792 || height == 754 || height == 125 || height == 123 || height == 184 || height == 186 || height == 187 || height == 227 || height == 230 || height == 235 || height == 240 || height == 242 || height == 261 || height == 336 ) - return(0); - } - else if ( baseid == IDR ) - { - if ( height == 836 || height == 1036 || height == 837 || height == 720 || height == 715 || height == 714 || height == 696 || height == 695 || height == 694 || height == 693 || height == 119 || height == 689 || height == 120 || height == 669 || height == 123 || height == 662 || height == 122 || height == 634 || height == 121 || height == 609 || height == 124 || height == 174 || height == 603 || height == 595 || height == 166 || height == 176 || height == 589 || height == 172 || height == 587 || height == 179 || height == 239 || height == 175 || height == 245 || height == 260 ) - return(0); - } - } - if ( script[offset] == opcode && opretlen < block.vtx[0].vout[n-1].scriptPubKey.size() ) - { - if ( (num= komodo_issued_opreturn(base,txids,vouts,values,srcvalues,kmdheights,otherheights,baseids,rmd160s,&script[offset],opretlen,opcode == 'X')) > 0 ) - { - for (i=1; iRTmask & (1LL << 32)) == 0 ) - { - if ( rtflag == 0 ) - printf("[%s] skip checkdeposit.%s not RT %llx\n",ASSETCHAINS_SYMBOL,CURRENCIES[baseids[i-1]],(long long)sp->RTmask); - sleep(60); - rtflag = 1; - //matched++; - //continue; - } - if ( rtflag != 0 ) - printf("[%s] %s reached RT\n",ASSETCHAINS_SYMBOL,CURRENCIES[baseids[i-1]]); - } - if ( (pax= komodo_paxfinds(txids[i-1],vouts[i-1])) != 0 ) // finds... make sure right one - { - pax->type = opcode; - if ( opcode == 'I' && (pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,symbol) != 0 || available < pax->fiatoshis) ) - { - printf("checkdeposit.[%s.%d]: skip %s %.8f when avail %.8f deposited %.8f, issued %.8f withdrawn %.8f approved %.8f redeemed %.8f\n",ASSETCHAINS_SYMBOL,height,symbol,dstr(pax->fiatoshis),dstr(available),dstr(deposited),dstr(issued),dstr(withdrawn),dstr(approved),dstr(redeemed)); - return(-1); - } - if ( pax->fiatoshis == block.vtx[0].vout[i].nValue ) - { - matched++; - if ( pax->marked != 0 && height >= 80820 ) - { - printf(">>>>>>>>>>> %c errs.%d i.%d match %.8f vs %.8f paxmarked.%d kht.%d ht.%d [%s].%d\n",opcode,errs,i,dstr(opcode == 'I' ? pax->fiatoshis : pax->komodoshis),dstr(block.vtx[0].vout[i].nValue),pax->marked,pax->height,pax->otherheight,ASSETCHAINS_SYMBOL,height); - } - else - { - } - if ( strcmp(ASSETCHAINS_SYMBOL,CURRENCIES[baseids[i-1]]) == 0 ) - { - //check deposit validates AUD.1047 [3] 0.14585530 -> 0.01000000 (0.14585530 0.01000000 0.01000000) - char destaddr[64],coinaddr[64]; uint8_t pubkey33[33]; - checktoshis = PAX_fiatdest(&seed,0,destaddr,pubkey33,coinaddr,pax->height,CURRENCIES[baseids[i-1]],pax->fiatoshis); - //checktoshis = komodo_paxprice(&seed,pax->height,CURRENCIES[baseids[i-1]],(char *)"KMD",(uint64_t)pax->komodoshis); - if ( komodo_paxcmp(CURRENCIES[baseids[i-1]],pax->height,pax->komodoshis,checktoshis,seed) < 0 ) - { - printf("paxcmp FAIL when check deposit validates %s.%d [%d] %.8f -> %.8f (%.8f %.8f %.8f)\n",CURRENCIES[baseids[i-1]],height,i,dstr(srcvalues[i-1]),dstr(values[i-1]),dstr(pax->komodoshis),dstr(pax->fiatoshis),dstr(block.vtx[0].vout[i].nValue)); - return(-1); - } //else printf("check deposit validates %s.%d [%d] %.8f -> %.8f (%.8f %.8f %.8f)\n",CURRENCIES[baseids[i-1]],height,i,dstr(srcvalues[i-1]),dstr(values[i-1]),dstr(pax->komodoshis),dstr(pax->fiatoshis),dstr(block.vtx[0].vout[i].nValue)); - } - } - else if ( strcmp(ASSETCHAINS_SYMBOL,CURRENCIES[baseids[i-1]]) == 0 ) - { - for (j=0; j<32; j++) - printf("%02x",((uint8_t *)&txids[i-1])[j]); - printf(" cant paxfind %c txid [%d]\n",opcode,height); - printf(">>>>>>>>>>> %c errs.%d i.%d match %.8f vs %.8f pax.%p [%s] ht.%d\n",opcode,errs,i,dstr(opcode == 'I' ? pax->fiatoshis : pax->komodoshis),dstr(block.vtx[0].vout[i].nValue),pax,ASSETCHAINS_SYMBOL,height); - return(-1); - } - } - else //if ( kmdheights[i-1] > 0 && otherheights[i-1] > 0 ) - { - hash = block.GetHash(); - for (j=0; j= activation ) - return(-1); - } - } - 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)); - // 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 - } - else - { - if ( height > 0 && (height < chainActive.Tip()->nHeight || (height >= chainActive.Tip()->nHeight && komodo_isrealtime(&ht) != 0)) && matched != num ) - { - printf("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)); - return(-1); - } - } - } - else - { - for (i=0; i= activation ) - return(-1); - } - //printf("opretlen.%d num.%d\n",opretlen,num); - } - else - { - for (i=0; i lastinterest ) + { + komodo_interestsum(); + komodo_longestchain(); + lastinterest = komodo_chainactive_timestamp(); + } refsp = komodo_stateptr(symbol,dest); if ( ASSETCHAINS_SYMBOL[0] == 0 ) { @@ -1786,12 +1469,12 @@ void komodo_passport_iteration() if ( sp != 0 && isrealtime == 0 ) refsp->RTbufs[0][2] = 0; } - komodo_paxtotal(); + //komodo_paxtotal(); // calls komodo_isrealtime(), which calls komodo_longestchain() refsp->RTmask |= RTmask; if ( expired == 0 && KOMODO_PASSPORT_INITDONE == 0 ) { KOMODO_PASSPORT_INITDONE = 1; - printf("done PASSPORT %s refid.%d\n",ASSETCHAINS_SYMBOL,refid); + printf("READY for %s RPC calls at %u! done PASSPORT %s refid.%d\n",ASSETCHAINS_SYMBOL,(uint32_t)time(NULL),ASSETCHAINS_SYMBOL,refid); } } diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 9179594ac..d57005ec9 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.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 * @@ -15,14 +15,14 @@ #include "komodo_defs.h" +void komodo_prefetch(FILE *fp); 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); -void komodo_assetchain_pubkeys(char *jsonstr); int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_isrealtime(int32_t *kmdheightp); uint64_t komodo_paxtotal(); @@ -46,16 +46,14 @@ struct komodo_state KOMODO_STATES[34]; int COINBASE_MATURITY = _COINBASE_MATURITY;//100; int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND; -int32_t KOMODO_LASTMINED,prevKOMODO_LASTMINED,JUMBLR_PAUSE,ASSETCHAINS_CC; +int32_t KOMODO_LASTMINED,prevKOMODO_LASTMINED,JUMBLR_PAUSE = 1; std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY; uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33]; -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; -uint16_t ASSETCHAINS_PORT; -uint32_t ASSETCHAIN_INIT; +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096]; +uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; +uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC; uint32_t ASSETCHAINS_MAGIC = 2387029918; -uint64_t ASSETCHAINS_SUPPLY = 10; -uint64_t ASSETCHAINS_COMMISSION; int64_t ASSETCHAINS_GENESISTXVAL = 5000000000; // consensus variables for coinbase timelock control and timelock transaction support @@ -80,9 +78,166 @@ uint32_t ASSETCHAINS_NONCESHIFT[] = {32,40}; uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,512}; uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH; +uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; +uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10; + uint32_t KOMODO_INITDONE; -char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_PORT = 7771; +char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771; uint64_t PENDING_KOMODO_TX; +extern int32_t KOMODO_LOADINGBLOCKS; +unsigned int MAX_BLOCK_SIGOPS = 20000; struct komodo_kv *KOMODO_KV; -pthread_mutex_t KOMODO_KV_mutex; +pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex; + +#define MAX_CURRENCIES 32 +char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies + "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", + "KMD" }; + +int32_t komodo_baseid(char *origbase) +{ + int32_t i; char base[64]; + for (i=0; origbase[i]!=0&&i= 0 && baseid < 32 ) + cur_money = ASSETCHAINS_SUPPLY + nHeight * ASSETCHAINS_REWARD[0] / SATOSHIDEN; + else + { + // figure out max_money by adding up supply to a maximum of 10,000,000 blocks + cur_money = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff) + ASSETCHAINS_GENESISTXVAL; + if ( ASSETCHAINS_LASTERA == 0 && ASSETCHAINS_REWARD[0] == 0 ) + { + cur_money = ASSETCHAINS_SUPPLY + (nHeight * 10000) / SATOSHIDEN; + } + else + { + for ( int j = 0; j <= ASSETCHAINS_LASTERA; j++ ) + { + // if any condition means we have no more rewards, break + if (j != 0 && (nHeight <= ASSETCHAINS_ENDSUBSIDY[j - 1] || (ASSETCHAINS_ENDSUBSIDY[j - 1] == 0 && + (ASSETCHAINS_REWARD[j] == 0 && (j == ASSETCHAINS_LASTERA || ASSETCHAINS_DECAY[j] != SATOSHIDEN))))) + break; + + // add rewards from this era, up to nHeight + int64_t reward = ASSETCHAINS_REWARD[j]; + if ( reward > 0 ) + { + uint64_t lastEnd = j == 0 ? 0 : ASSETCHAINS_ENDSUBSIDY[j - 1]; + uint64_t curEnd = ASSETCHAINS_ENDSUBSIDY[j] == 0 ? nHeight : nHeight > ASSETCHAINS_ENDSUBSIDY[j] ? ASSETCHAINS_ENDSUBSIDY[j] : nHeight; + uint64_t period = ASSETCHAINS_HALVING[j]; + uint32_t nSteps = (curEnd - lastEnd) / period; + uint32_t modulo = (curEnd - lastEnd) % period; + uint64_t decay = ASSETCHAINS_DECAY[j]; + + // if exactly SATOSHIDEN, linear decay to zero or to next era, same as: + // (next_era_reward + (starting reward - next_era_reward) / 2) * num_blocks + if ( decay == SATOSHIDEN ) + { + int64_t lowestSubsidy, subsidyDifference, stepDifference, stepTriangle; + int64_t denominator, modulo; + int32_t sign = 1; + + if ( j == ASSETCHAINS_LASTERA ) + { + subsidyDifference = reward; + lowestSubsidy = 0; + } + else + { + // Ex: -ac_eras=3 -ac_reward=0,384,24 -ac_end=1440,260640,0 -ac_halving=1,1440,2103840 -ac_decay 100000000,97750000,0 + subsidyDifference = reward - ASSETCHAINS_REWARD[j + 1]; + if (subsidyDifference < 0) + { + sign = -1; + subsidyDifference *= sign; + lowestSubsidy = reward; + } + else + { + lowestSubsidy = ASSETCHAINS_REWARD[j + 1]; + } + } + + // if we have not finished the current era, we need to caluclate a total as if we are at the end, with the current + // subsidy. we will calculate the total of a linear era as follows. Each item represents an area calculation: + // a) the rectangle from 0 to the lowest reward in the era * the number of blocks + // b) the rectangle of the remainder of blocks from the lowest point of the era to the highest point of the era if any remainder + // c) the minor triangle from the start of transition from the lowest point to the start of transition to the highest point + // d) one halving triangle (half area of one full step) + // + // we also need: + // e) number of steps = (n - erastart) / halving interval + // + // the total supply from era start up to height is: + // a + b + c + (d * e) + + // calculate amount in one step's triangular protrusion over minor triangle's hypotenuse + denominator = nSteps * period; + + // difference of one step vs. total + stepDifference = (period * subsidyDifference) / denominator; + + // area == coin holding of one step triangle, protruding from minor triangle's hypotenuse + stepTriangle = (period * stepDifference) >> 1; + + // sign is negative if slope is positive (start is less than end) + if (sign < 0) + { + // use steps minus one for our calculations, and add the potentially partial rectangle + // at the end + cur_money += stepTriangle * (nSteps - 1); + cur_money += stepTriangle * (nSteps - 1) * (nSteps - 1); + + // difference times number of steps is height of rectangle above lowest subsidy + cur_money += modulo * stepDifference * nSteps; + } + else + { + // if negative slope, the minor triangle is the full number of steps, as the highest + // level step is full. lowest subsidy is just the lowest so far + lowestSubsidy = reward - (stepDifference * nSteps); + + // add the step triangles, one per step + cur_money += stepTriangle * nSteps; + + // add the minor triangle + cur_money += stepTriangle * nSteps * nSteps; + } + + // add more for the base rectangle if lowest subsidy is not 0 + cur_money += lowestSubsidy * (curEnd - lastEnd); + } + else + { + for ( int k = lastEnd; k < curEnd; k += period ) + { + cur_money += period * reward; + // if zero, we do straight halving + reward = decay ? (reward * decay) / SATOSHIDEN : reward >> 1; + } + cur_money += modulo * reward; + } + } + } + } + } + return((int64_t)(cur_money + (cur_money * ASSETCHAINS_COMMISSION) / SATOSHIDEN)); +} + diff --git a/src/komodo_interest.h b/src/komodo_interest.h index 07b12cfe1..23ed985ca 100644 --- a/src/komodo_interest.h +++ b/src/komodo_interest.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 * diff --git a/src/komodo_jumblr.h b/src/komodo_jumblr.h index 951ed9de0..f36bb441a 100755 --- a/src/komodo_jumblr.h +++ b/src/komodo_jumblr.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 * @@ -83,7 +83,7 @@ char *jumblr_importaddress(char *address) { char params[1024]; sprintf(params,"[\"%s\", \"%s\", false]",address,address); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"importaddress",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"importaddress",params,BITCOIND_RPCPORT)); } char *jumblr_validateaddress(char *addr) @@ -91,7 +91,7 @@ char *jumblr_validateaddress(char *addr) char params[1024]; sprintf(params,"[\"%s\"]",addr); printf("validateaddress.%s\n",params); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"validateaddress",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"validateaddress",params,BITCOIND_RPCPORT)); } int32_t Jumblr_secretaddrfind(char *searchaddr) @@ -222,28 +222,28 @@ char *jumblr_zgetnewaddress() { char params[1024]; sprintf(params,"[]"); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getnewaddress",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getnewaddress",params,BITCOIND_RPCPORT)); } char *jumblr_zlistoperationids() { char params[1024]; sprintf(params,"[]"); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listoperationids",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listoperationids",params,BITCOIND_RPCPORT)); } char *jumblr_zgetoperationresult(char *opid) { char params[1024]; sprintf(params,"[[\"%s\"]]",opid); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationresult",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationresult",params,BITCOIND_RPCPORT)); } char *jumblr_zgetoperationstatus(char *opid) { char params[1024]; sprintf(params,"[[\"%s\"]]",opid); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationstatus",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getoperationstatus",params,BITCOIND_RPCPORT)); } char *jumblr_sendt_to_z(char *taddr,char *zaddr,double amount) @@ -253,7 +253,7 @@ char *jumblr_sendt_to_z(char *taddr,char *zaddr,double amount) return(clonestr((char *)"{\"error\":\"illegal address in t to z\"}")); sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",taddr,zaddr,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE); printf("t -> z: %s\n",params); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_RPCPORT)); } char *jumblr_sendz_to_z(char *zaddrS,char *zaddrD,double amount) @@ -264,7 +264,7 @@ char *jumblr_sendz_to_z(char *zaddrS,char *zaddrD,double amount) //sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddrS,zaddrD,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE); sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddrS,zaddrD,amount-fee-JUMBLR_TXFEE,JUMBLR_TXFEE); printf("z -> z: %s\n",params); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_RPCPORT)); } char *jumblr_sendz_to_t(char *zaddr,char *taddr,double amount) @@ -274,56 +274,56 @@ char *jumblr_sendz_to_t(char *zaddr,char *taddr,double amount) return(clonestr((char *)"{\"error\":\"illegal address in z to t\"}")); sprintf(params,"[\"%s\", [{\"address\":\"%s\",\"amount\":%.8f}, {\"address\":\"%s\",\"amount\":%.8f}], 1, %.8f]",zaddr,taddr,amount-fee-JUMBLR_TXFEE,JUMBLR_ADDR,fee,JUMBLR_TXFEE); printf("z -> t: %s\n",params); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_sendmany",params,BITCOIND_RPCPORT)); } char *jumblr_zlistaddresses() { char params[1024]; sprintf(params,"[]"); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listaddresses",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listaddresses",params,BITCOIND_RPCPORT)); } char *jumblr_zlistreceivedbyaddress(char *addr) { char params[1024]; sprintf(params,"[\"%s\", 1]",addr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listreceivedbyaddress",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_listreceivedbyaddress",params,BITCOIND_RPCPORT)); } char *jumblr_getreceivedbyaddress(char *addr) { char params[1024]; sprintf(params,"[\"%s\", 1]",addr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"getreceivedbyaddress",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"getreceivedbyaddress",params,BITCOIND_RPCPORT)); } char *jumblr_importprivkey(char *wifstr) { char params[1024]; sprintf(params,"[\"%s\", \"\", false]",wifstr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"importprivkey",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"importprivkey",params,BITCOIND_RPCPORT)); } char *jumblr_zgetbalance(char *addr) { char params[1024]; sprintf(params,"[\"%s\", 1]",addr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getbalance",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"z_getbalance",params,BITCOIND_RPCPORT)); } char *jumblr_listunspent(char *coinaddr) { char params[1024]; sprintf(params,"[1, 99999999, [\"%s\"]]",coinaddr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"listunspent",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"listunspent",params,BITCOIND_RPCPORT)); } char *jumblr_gettransaction(char *txidstr) { char params[1024]; sprintf(params,"[\"%s\", 1]",txidstr); - return(jumblr_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,BITCOIND_PORT)); + return(jumblr_issuemethod(KMDUSERPASS,(char *)"getrawtransaction",params,BITCOIND_RPCPORT)); } int32_t jumblr_numvins(bits256 txid) diff --git a/src/komodo_kv.h b/src/komodo_kv.h index 453608cc1..58d550414 100644 --- a/src/komodo_kv.h +++ b/src/komodo_kv.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 * @@ -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 ) { @@ -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; // jl777 used to or in KVPROTECTED 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 diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 4689e38ed..25a03f83b 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.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 * @@ -13,6 +13,7 @@ * * ******************************************************************************/ + #include "komodo_defs.h" #include "komodo_cJSON.h" @@ -126,112 +127,115 @@ 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 ((814000 / 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" }, // 10 + {"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" }, // 20 + {"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" }, // 30 + {"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" }, // 40 + {"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" }, // 50 + {"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" }, // 60 + {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, + {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, + {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, }; int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp) { - static uint8_t elected_pubkeys0[64][33],elected_pubkeys1[64][33],did0,did1; + static uint8_t elected_pubkeys0[64][33],elected_pubkeys1[64][33],did0,did1; static int32_t n0,n1; 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) ) { if ( did0 == 0 ) { - n = (int32_t)(sizeof(Notaries_elected0)/sizeof(*Notaries_elected0)); - for (i=0; i= KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP ) @@ -379,43 +383,75 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33, } //struct komodo_state *komodo_stateptr(char *symbol,char *dest); -int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp) -{ - char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; - if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) - { - *hashp = sp->NOTARIZED_HASH; - *txidp = sp->NOTARIZED_DESTTXID; - return(sp->NOTARIZED_HEIGHT); - } - else - { - memset(hashp,0,sizeof(*hashp)); - memset(txidp,0,sizeof(*txidp)); - return(0); - } -} -int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height) +struct notarized_checkpoint *komodo_npptr(int32_t height) { - int32_t i; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; struct notarized_checkpoint *np = 0; - np = 0; + 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 ) - { - *notarized_htp = np->notarized_height; - *MoMp = np->MoM; - *kmdtxidp = np->notarized_desttxid; - return(np->MoMdepth); - } + return(np); } } - *notarized_htp = 0; + return(0); +} + +int32_t komodo_prevMoMheight() +{ + static uint256 zero; + 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->MoM != zero ) + return(np->notarized_height); + } + } + return(0); +} + +int32_t komodo_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *txidp) +{ + char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; + if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) + { + *hashp = sp->NOTARIZED_HASH; + *txidp = sp->NOTARIZED_DESTTXID; + *prevMoMheightp = komodo_prevMoMheight(); + return(sp->NOTARIZED_HEIGHT); + } + else + { + *prevMoMheightp = 0; + memset(hashp,0,sizeof(*hashp)); + memset(txidp,0,sizeof(*txidp)); + 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; + if ( (np= komodo_npptr(height)) != 0 ) + { + *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 = *MoMoMoffsetp = *MoMoMdepthp = *kmdstartip = *kmdendip = 0; memset(MoMp,0,sizeof(*MoMp)); + memset(MoMoMp,0,sizeof(*MoMoMp)); memset(kmdtxidp,0,sizeof(*kmdtxidp)); return(0); } @@ -525,50 +561,4 @@ void komodo_init(int32_t height) didinit = 1; komodo_stateupdate(0,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,zero,0); } - /*else if ( 0 && height == KOMODO_MAINNET_START ) - { - n = (int32_t)(sizeof(Notaries_elected)/sizeof(*Notaries_elected)); - for (k=0; k 0 ) - { - for (i=0; i +#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,uint64_t commission,uint8_t staked,int32_t cc) +{ + uint8_t extrabuf[4096],*extraptr=0; int32_t extralen=0; uint64_t val; + 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 || commission != 0 || cc != 0 || staked != 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)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); + val = commission | (((uint64_t)staked & 0xff) << 32) | (((uint64_t)cc & 0xffffff) << 40); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); + } + return(komodo_port(name,supply,&ASSETCHAINS_MAGIC,extraptr,extralen)); +} + +int main(int argc, char * argv[]) +{ + uint16_t rpcport; int32_t i,j,offset=0,num = 1; uint64_t supply=10,commission=0,endsubsidy,reward,halving,decay; uint8_t *allocated=0,staked=0; uint32_t cc = 1; + endsubsidy = reward = halving = decay = 0; + if ( argc < 2 ) + { + // staked, commission and cc hardcoded + 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 ( 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,commission,staked,cc); + printf("./komodod -ac_name=%s -ac_cc=%u -ac_supply=%llu -ac_end=%llu -ac_reward=%llu -ac_halving=%llu -ac_decay=%llu & # rpcport %u\n",argv[offset + 1],cc,(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= 0 ) @@ -1307,7 +1289,7 @@ void iguana_initQ(queue_t *Q,char *name) free(item); } -uint16_t komodo_userpass(char *username,char *password,FILE *fp) +uint16_t _komodo_userpass(char *username,char *password,FILE *fp) { char *rpcuser,*rpcpassword,*str,line[8192]; uint16_t port = 0; rpcuser = rpcpassword = 0; @@ -1324,7 +1306,7 @@ uint16_t komodo_userpass(char *username,char *password,FILE *fp) else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) { port = atoi(parse_conf_line(str,(char *)"rpcport")); - //printf("rpcport.%u in file\n",port); + //fprintf(stderr,"rpcport.%u in file\n",port); } } if ( rpcuser != 0 && rpcpassword != 0 ) @@ -1377,11 +1359,11 @@ void komodo_statefname(char *fname,char *symbol,char *str) //printf("test.(%s) -> [%s] statename.(%s) %s\n",test,ASSETCHAINS_SYMBOL,symbol,fname); } -void komodo_configfile(char *symbol,uint16_t port) +void komodo_configfile(char *symbol,uint16_t rpcport) { static char myusername[512],mypassword[8192]; FILE *fp; uint16_t kmdport; uint8_t buf2[33]; char fname[512],buf[128],username[512],password[8192]; uint32_t crc,r,r2,i; - if ( symbol != 0 && port != 0 ) + if ( symbol != 0 && rpcport != 0 ) { r = (uint32_t)time(NULL); r2 = OS_milliseconds(); @@ -1398,7 +1380,7 @@ void komodo_configfile(char *symbol,uint16_t port) sprintf(&password[i*2],"%02x",buf2[i]); password[i*2] = 0; sprintf(buf,"%s.conf",symbol); - BITCOIND_PORT = port; + BITCOIND_RPCPORT = rpcport; #ifdef _WIN32 sprintf(fname,"%s\\%s",GetDataDir(false).string().c_str(),buf); #else @@ -1409,7 +1391,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\nrpcallowip=127.0.0.1\n",crc,password,port); + fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=256\nrpcallowip=127.0.0.1\n",crc,password,rpcport); fclose(fp); printf("Created (%s)\n",fname); } else printf("Couldnt create (%s)\n",fname); @@ -1417,7 +1399,7 @@ void komodo_configfile(char *symbol,uint16_t port) } else { - komodo_userpass(myusername,mypassword,fp); + _komodo_userpass(myusername,mypassword,fp); mapArgs["-rpcpassword"] = mypassword; mapArgs["-rpcusername"] = myusername; //fprintf(stderr,"myusername.(%s)\n",myusername); @@ -1440,7 +1422,7 @@ void komodo_configfile(char *symbol,uint16_t port) #endif if ( (fp= fopen(fname,"rb")) != 0 ) { - if ( (kmdport= komodo_userpass(username,password,fp)) != 0 ) + if ( (kmdport= _komodo_userpass(username,password,fp)) != 0 ) KMD_PORT = kmdport; sprintf(KMDUSERPASS,"%s:%s",username,password); fclose(fp); @@ -1464,10 +1446,11 @@ uint16_t komodo_userpass(char *userpass,char *symbol) komodo_statefname(fname,symbol,confname); if ( (fp= fopen(fname,"rb")) != 0 ) { - port = komodo_userpass(username,password,fp); + port = _komodo_userpass(username,password,fp); sprintf(userpass,"%s:%s",username,password); + if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) + strcpy(ASSETCHAINS_USERPASS,userpass); fclose(fp); - return((int32_t)strlen(userpass)); } return(port); } @@ -1519,7 +1502,7 @@ uint16_t komodo_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extr printf("ports\n"); }*/ -char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7778\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":1,\\\"VALIDATE\\\":1,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\"}\""; +char *iguanafmtstr = (char *)"curl --url \"http://127.0.0.1:7776\" --data \"{\\\"conf\\\":\\\"%s.conf\\\",\\\"path\\\":\\\"${HOME#\"/\"}/.komodo/%s\\\",\\\"unitval\\\":\\\"20\\\",\\\"zcash\\\":1,\\\"RELAY\\\":-1,\\\"VALIDATE\\\":0,\\\"prefetchlag\\\":-1,\\\"poll\\\":100,\\\"active\\\":1,\\\"agent\\\":\\\"iguana\\\",\\\"method\\\":\\\"addcoin\\\",\\\"startpend\\\":4,\\\"endpend\\\":4,\\\"services\\\":129,\\\"maxpeers\\\":8,\\\"newcoin\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"hasheaders\\\":1,\\\"useaddmultisig\\\":0,\\\"netmagic\\\":\\\"%s\\\",\\\"p2p\\\":%u,\\\"rpc\\\":%u,\\\"pubval\\\":60,\\\"p2shval\\\":85,\\\"wifval\\\":188,\\\"txfee_satoshis\\\":\\\"10000\\\",\\\"isPoS\\\":0,\\\"minoutput\\\":10000,\\\"minconfirms\\\":2,\\\"genesishash\\\":\\\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\\\",\\\"protover\\\":170002,\\\"genesisblock\\\":\\\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\\\",\\\"debug\\\":0,\\\"seedipaddr\\\":\\\"%s\\\"}\""; int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp) @@ -1544,65 +1527,7 @@ char *argv0names[] = int64_t komodo_max_money() { - uint64_t max_money; - int32_t baseid; - - if ( ( baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) - max_money = komodo_maxallowed(baseid); - else - { - // figure out max_money by adding up supply to a maximum of 10,000,000 blocks - max_money = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff) + ASSETCHAINS_GENESISTXVAL; - if ( ASSETCHAINS_LASTERA == 0 && ASSETCHAINS_REWARD[0] == 0 ) - { - max_money += 10000 * 10000000LL; - return((int64_t)max_money); - } - - for ( int j = 0; j <= ASSETCHAINS_LASTERA && (j == 0 || ASSETCHAINS_ENDSUBSIDY[j - 1] != 0); j++ ) - { - uint64_t reward = ASSETCHAINS_REWARD[j]; - if ( reward > 0 ) - { - uint64_t lastEnd = j == 0 ? 0 : ASSETCHAINS_ENDSUBSIDY[j - 1]; - uint64_t curEnd = ASSETCHAINS_ENDSUBSIDY[j] == 0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY[j]; - uint64_t period = ASSETCHAINS_HALVING[j]; - uint64_t nextReward, decay = ASSETCHAINS_DECAY[j]; - - // if exactly SATOSHIDEN, linear decay to zero or next era, same as: - // (next_era_reward + (starting reward - next_era_reward) / 2) * num_blocks - if ( decay == SATOSHIDEN ) - { - if ( j < ASSETCHAINS_LASTERA ) - { - nextReward = ASSETCHAINS_REWARD[j + 1]; - } - else - nextReward = 0; - - // it can go either up or down if linear, swap to prevent underflow - if ( nextReward > reward ) - { - uint64_t tmp = reward; - reward = nextReward; - nextReward = tmp; - } - // must divide, not shift, since reward - nextReward can be negative - max_money += (nextReward + ((reward - nextReward + 1) / 2)) * (curEnd - lastEnd); - } - else - { - for ( int k = 0; k < curEnd; k += period ) - { - max_money += period * reward; - // if zero, we do straight halving - reward = decay ? (reward * decay) / SATOSHIDEN : reward >> 1; - } - } - } - } - } - return((int64_t)max_money); + return komodo_current_supply(10000000); } uint64_t komodo_ac_block_subsidy(int nHeight) @@ -1629,7 +1554,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) } if ( curEra <= ASSETCHAINS_LASTERA ) { - int nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; + int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; subsidy = (int64_t)ASSETCHAINS_REWARD[curEra]; if ( subsidy || (curEra != ASSETCHAINS_LASTERA && ASSETCHAINS_REWARD[curEra + 1] != 0) ) { @@ -1683,7 +1608,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) 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; uint16_t port; 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"); @@ -1708,7 +1633,7 @@ void komodo_args(char *argv0) } } } - ASSETCHAINS_CC = GetArg("-ac_cc",0); // keep it outside the assetchains hashing so KMD can do it and we dont have two identical chains other than -ac_cc + ASSETCHAINS_CC = GetArg("-ac_cc",0); if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 ) { printf("KOMODO_REWIND %d\n",KOMODO_REWIND); @@ -1770,9 +1695,12 @@ void komodo_args(char *argv0) } } + MAX_BLOCK_SIGOPS = 60000; ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10); ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); + if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 ) + ASSETCHAINS_STAKED = 100; if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 ) decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); @@ -1819,7 +1747,8 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ALGO),(void *)&ASSETCHAINS_ALGO); } - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_COMMISSION),(void *)&ASSETCHAINS_COMMISSION); + val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffffff) << 40); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); } addn = GetArg("-seednode",""); @@ -1830,8 +1759,7 @@ void komodo_args(char *argv0) MAX_MONEY = komodo_max_money(); //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); - + ASSETCHAINS_P2PPORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) { fprintf(stderr,"waiting for datadir\n"); @@ -1846,10 +1774,14 @@ void komodo_args(char *argv0) { int32_t komodo_baseid(char *origbase); extern int COINBASE_MATURITY; - komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT + 1); + if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 ) + ASSETCHAINS_RPCPORT = port; + else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1); COINBASE_MATURITY = 1; - LogPrintf("ASSETCHAINS_PORT %s %u\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT); + //fprintf(stderr,"ASSETCHAINS_RPCPORT (%s) %u\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_RPCPORT); } + if ( ASSETCHAINS_RPCPORT == 0 ) + ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1; //ASSETCHAINS_NOTARIES = GetArg("-ac_notaries",""); //komodo_assetchain_pubkeys((char *)ASSETCHAINS_NOTARIES.c_str()); iguana_rwnum(1,magic,sizeof(ASSETCHAINS_MAGIC),(void *)&ASSETCHAINS_MAGIC); @@ -1857,10 +1789,10 @@ void komodo_args(char *argv0) sprintf(&magicstr[i<<1],"%02x",magic[i]); magicstr[8] = 0; #ifndef FROM_CLI - sprintf(fname,"gen%s",ASSETCHAINS_SYMBOL); + sprintf(fname,"%s_7776",ASSETCHAINS_SYMBOL); if ( (fp= fopen(fname,"wb")) != 0 ) { - fprintf(fp,iguanafmtstr,name.c_str(),name.c_str(),name.c_str(),name.c_str(),magicstr,ASSETCHAINS_PORT,ASSETCHAINS_PORT+1,"78.47.196.146"); + fprintf(fp,iguanafmtstr,name.c_str(),name.c_str(),name.c_str(),name.c_str(),magicstr,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,"78.47.196.146"); fclose(fp); //printf("created (%s)\n",fname); } else printf("error creating (%s)\n",fname); @@ -1869,7 +1801,8 @@ void komodo_args(char *argv0) else { char fname[512],username[512],password[4096]; int32_t iter; FILE *fp; - ASSETCHAINS_PORT = 8777; + ASSETCHAINS_P2PPORT = 7770; + ASSETCHAINS_RPCPORT = 7771; for (iter=0; iter<2; iter++) { strcpy(fname,GetDataDir().string().c_str()); @@ -1894,7 +1827,7 @@ void komodo_args(char *argv0) #endif if ( (fp= fopen(fname,"rb")) != 0 ) { - komodo_userpass(username,password,fp); + _komodo_userpass(username,password,fp); sprintf(iter == 0 ? KMDUSERPASS : BTCUSERPASS,"%s:%s",username,password); fclose(fp); //printf("KOMODO.(%s) -> userpass.(%s)\n",fname,KMDUSERPASS); @@ -1903,8 +1836,11 @@ void komodo_args(char *argv0) break; } } - BITCOIND_PORT = GetArg("-rpcport", BaseParams().RPCPort()); - //fprintf(stderr,"%s chain params initialized\n",ASSETCHAINS_SYMBOL); + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT); + //fprintf(stderr,"(%s) port.%u chain params initialized\n",ASSETCHAINS_SYMBOL,BITCOIND_RPCPORT); + } else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort()); } void komodo_nameset(char *symbol,char *dest,char *source) @@ -1937,3 +1873,24 @@ struct komodo_state *komodo_stateptr(char *symbol,char *dest) komodo_nameset(symbol,dest,ASSETCHAINS_SYMBOL); return(komodo_stateptrget(symbol)); } + +void komodo_prefetch(FILE *fp) +{ + long fsize,fpos; int32_t incr = 16*1024*1024; + fpos = ftell(fp); + fseek(fp,0,SEEK_END); + fsize = ftell(fp); + if ( fsize > incr ) + { + char *ignore = (char *)malloc(incr); + if ( ignore != 0 ) + { + rewind(fp); + while ( fread(ignore,1,incr,fp) == incr ) // prefetch + fprintf(stderr,"."); + free(ignore); + } + } + fseek(fp,fpos,SEEK_SET); +} + diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index b5d024abb..3f1abbe14 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -27,14 +27,14 @@ void HandleError(const leveldb::Status& status) throw leveldb_error("Unknown database error"); } -static leveldb::Options GetOptions(size_t nCacheSize) +static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles) { leveldb::Options options; options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously options.filter_policy = leveldb::NewBloomFilterPolicy(10); - options.compression = leveldb::kNoCompression; - options.max_open_files = 64; + options.compression = compression ? leveldb::kSnappyCompression : leveldb::kNoCompression; + options.max_open_files = maxOpenFiles; if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error // on corruption in later versions. @@ -43,14 +43,14 @@ static leveldb::Options GetOptions(size_t nCacheSize) return options; } -CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe) +CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles) { penv = NULL; readoptions.verify_checksums = true; iteroptions.verify_checksums = true; iteroptions.fill_cache = false; syncoptions.sync = true; - options = GetOptions(nCacheSize); + options = GetOptions(nCacheSize, compression, maxOpenFiles); options.create_if_missing = true; if (fMemory) { penv = leveldb::NewMemEnv(leveldb::Env::Default()); diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h index 639f736a5..2a6e345f1 100644 --- a/src/leveldbwrapper.h +++ b/src/leveldbwrapper.h @@ -86,7 +86,7 @@ private: leveldb::DB* pdb; public: - CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); + CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = false, int maxOpenFiles = 64); ~CLevelDBWrapper(); template diff --git a/src/main.cpp b/src/main.cpp index 926a42ffd..cc8e8995c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,6 +53,10 @@ using namespace std; CCriticalSection cs_main; extern uint8_t NOTARY_PUBKEY33[33]; +extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN; +int32_t KOMODO_NEWBLOCKS; +int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block); +void komodo_broadcast(CBlock *pblock,int32_t limit); BlockMap mapBlockIndex; CChain chainActive; @@ -65,6 +69,9 @@ bool fExperimentalMode = false; bool fImporting = false; bool fReindex = false; bool fTxIndex = false; +bool fAddressIndex = false; +bool fTimestampIndex = false; +bool fSpentIndex = false; bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = true; @@ -104,30 +111,30 @@ const string strMessageMagic = "Komodo Signed Message:\n"; // Internal stuff namespace { - + struct CBlockIndexWorkComparator { bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { // First sort by most total work, ... if (pa->nChainWork > pb->nChainWork) return false; if (pa->nChainWork < pb->nChainWork) return true; - + // ... then by earliest time received, ... if (pa->nSequenceId < pb->nSequenceId) return false; if (pa->nSequenceId > pb->nSequenceId) return true; - + // Use pointer address as tie breaker (should only happen with blocks // loaded from disk, as those all have id 0). if (pa < pb) return false; if (pa > pb) return true; - + // Identical blocks. return false; } }; - + CBlockIndex *pindexBestInvalid; - + /** * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be @@ -137,10 +144,10 @@ namespace { /** Number of nodes with fSyncStarted. */ int nSyncStarted = 0; /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. - * Pruned nodes may have entries where B is missing data. - */ + * Pruned nodes may have entries where B is missing data. + */ multimap mapBlocksUnlinked; - + CCriticalSection cs_LastBlockFile; std::vector vinfoBlockFile; int nLastBlockFile = 0; @@ -149,7 +156,7 @@ namespace { * or if we allocate more file space when we're in prune mode */ bool fCheckForPruning = false; - + /** * Every received block is assigned a unique and increasing identifier, so we * know which one to give priority in case of a fork. @@ -157,14 +164,14 @@ namespace { CCriticalSection cs_nBlockSequenceId; /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ uint32_t nBlockSequenceId = 1; - + /** * Sources of received blocks, saved to be able to send them reject * messages or ban them when processing happens afterwards. Protected by * cs_main. */ map mapBlockSource; - + /** * Filter for transactions that were recently rejected by * AcceptToMemoryPool. These are not rerequested until the chain tip @@ -187,7 +194,7 @@ namespace { */ boost::scoped_ptr recentRejects; uint256 hashRecentRejectsChainTip; - + /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; @@ -197,16 +204,16 @@ namespace { int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer) }; map::iterator> > mapBlocksInFlight; - + /** Number of blocks in flight with validated headers. */ int nQueuedValidatedHeaders = 0; - + /** Number of preferable block download peers. */ int nPreferredDownload = 0; - + /** Dirty block index entries. */ set setDirtyBlockIndex; - + /** Dirty block file entries. */ set setDirtyFileInfo; } // anon namespace @@ -217,306 +224,306 @@ namespace { // namespace { - -struct CBlockReject { - unsigned char chRejectCode; - string strRejectReason; - uint256 hashBlock; -}; - -/** - * Maintain validation-specific state about nodes, protected by cs_main, instead - * by CNode's own locks. This simplifies asynchronous operation, where - * processing of incoming data is done after the ProcessMessage call returns, - * and we're no longer holding the node's locks. - */ -struct CNodeState { - //! The peer's address - CService address; - //! Whether we have a fully established connection. - bool fCurrentlyConnected; - //! Accumulated misbehaviour score for this peer. - int nMisbehavior; - //! Whether this peer should be disconnected and banned (unless whitelisted). - bool fShouldBan; - //! String name of this peer (debugging/logging purposes). - std::string name; - //! List of asynchronously-determined block rejections to notify this peer about. - std::vector rejects; - //! The best known block we know this peer has announced. - CBlockIndex *pindexBestKnownBlock; - //! The hash of the last unknown block this peer has announced. - uint256 hashLastUnknownBlock; - //! The last full block we both have. - CBlockIndex *pindexLastCommonBlock; - //! Whether we've started headers synchronization with this peer. - bool fSyncStarted; - //! Since when we're stalling block download progress (in microseconds), or 0. - int64_t nStallingSince; - list vBlocksInFlight; - int nBlocksInFlight; - int nBlocksInFlightValidHeaders; - //! Whether we consider this a preferred download peer. - bool fPreferredDownload; - - CNodeState() { - fCurrentlyConnected = false; - nMisbehavior = 0; - fShouldBan = false; - pindexBestKnownBlock = NULL; - hashLastUnknownBlock.SetNull(); - pindexLastCommonBlock = NULL; - fSyncStarted = false; - nStallingSince = 0; - nBlocksInFlight = 0; - nBlocksInFlightValidHeaders = 0; - fPreferredDownload = false; - } -}; - -/** Map maintaining per-node state. Requires cs_main. */ -map mapNodeState; - -// Requires cs_main. -CNodeState *State(NodeId pnode) { - map::iterator it = mapNodeState.find(pnode); - if (it == mapNodeState.end()) - return NULL; - return &it->second; -} - -int GetHeight() -{ - LOCK(cs_main); - return chainActive.Height(); -} - -void UpdatePreferredDownload(CNode* node, CNodeState* state) -{ - nPreferredDownload -= state->fPreferredDownload; - - // Whether this node should be marked as a preferred download node. - state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; - - nPreferredDownload += state->fPreferredDownload; -} - -// Returns time at which to timeout block request (nTime in microseconds) -int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) -{ - return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); -} - -void InitializeNode(NodeId nodeid, const CNode *pnode) { - LOCK(cs_main); - CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; - state.name = pnode->addrName; - state.address = pnode->addr; -} - -void FinalizeNode(NodeId nodeid) { - LOCK(cs_main); - CNodeState *state = State(nodeid); - - if (state->fSyncStarted) - nSyncStarted--; - - if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { - AddressCurrentlyConnected(state->address); - } - - BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) - mapBlocksInFlight.erase(entry.hash); - EraseOrphansFor(nodeid); - nPreferredDownload -= state->fPreferredDownload; - - mapNodeState.erase(nodeid); -} -void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) -{ -/* int expired = pool.Expire(GetTime() - age); - if (expired != 0) - LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); + struct CBlockReject { + unsigned char chRejectCode; + string strRejectReason; + uint256 hashBlock; + }; - std::vector vNoSpendsRemaining; - pool.TrimToSize(limit, &vNoSpendsRemaining); - BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) - pcoinsTip->Uncache(removed);*/ -} - -// Requires cs_main. -// Returns a bool indicating whether we requested this block. -bool MarkBlockAsReceived(const uint256& hash) { - map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); - if (itInFlight != mapBlocksInFlight.end()) { - CNodeState *state = State(itInFlight->second.first); - nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; - state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; - state->vBlocksInFlight.erase(itInFlight->second.second); - state->nBlocksInFlight--; - state->nStallingSince = 0; - mapBlocksInFlight.erase(itInFlight); - return true; - } - return false; -} - -// Requires cs_main. -void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - // Make sure it's not listed somewhere already. - MarkBlockAsReceived(hash); - - int64_t nNow = GetTimeMicros(); - QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; - nQueuedValidatedHeaders += newentry.fValidatedHeaders; - list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); - state->nBlocksInFlight++; - state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; - mapBlocksInFlight[hash] = std::make_pair(nodeid, it); -} - -/** Check whether the last unknown block a peer advertized is not yet known. */ -void ProcessBlockAvailability(NodeId nodeid) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - if (!state->hashLastUnknownBlock.IsNull()) { - BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); - if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) - { - if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) - state->pindexBestKnownBlock = itOld->second; - state->hashLastUnknownBlock.SetNull(); + /** + * Maintain validation-specific state about nodes, protected by cs_main, instead + * by CNode's own locks. This simplifies asynchronous operation, where + * processing of incoming data is done after the ProcessMessage call returns, + * and we're no longer holding the node's locks. + */ + struct CNodeState { + //! The peer's address + CService address; + //! Whether we have a fully established connection. + bool fCurrentlyConnected; + //! Accumulated misbehaviour score for this peer. + int nMisbehavior; + //! Whether this peer should be disconnected and banned (unless whitelisted). + bool fShouldBan; + //! String name of this peer (debugging/logging purposes). + std::string name; + //! List of asynchronously-determined block rejections to notify this peer about. + std::vector rejects; + //! The best known block we know this peer has announced. + CBlockIndex *pindexBestKnownBlock; + //! The hash of the last unknown block this peer has announced. + uint256 hashLastUnknownBlock; + //! The last full block we both have. + CBlockIndex *pindexLastCommonBlock; + //! Whether we've started headers synchronization with this peer. + bool fSyncStarted; + //! Since when we're stalling block download progress (in microseconds), or 0. + int64_t nStallingSince; + list vBlocksInFlight; + int nBlocksInFlight; + int nBlocksInFlightValidHeaders; + //! Whether we consider this a preferred download peer. + bool fPreferredDownload; + + CNodeState() { + fCurrentlyConnected = false; + nMisbehavior = 0; + fShouldBan = false; + pindexBestKnownBlock = NULL; + hashLastUnknownBlock.SetNull(); + pindexLastCommonBlock = NULL; + fSyncStarted = false; + nStallingSince = 0; + nBlocksInFlight = 0; + nBlocksInFlightValidHeaders = 0; + fPreferredDownload = false; } + }; + + /** Map maintaining per-node state. Requires cs_main. */ + map mapNodeState; + + // Requires cs_main. + CNodeState *State(NodeId pnode) { + map::iterator it = mapNodeState.find(pnode); + if (it == mapNodeState.end()) + return NULL; + return &it->second; } -} - -/** Update tracking information about which blocks a peer is assumed to have. */ -void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - /*ProcessBlockAvailability(nodeid); - - BlockMap::iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { - // An actually better block was announced. - if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) - state->pindexBestKnownBlock = it->second; - } else*/ + + int GetHeight() { - // An unknown block was announced; just assume that the latest one is the best one. - state->hashLastUnknownBlock = hash; + LOCK(cs_main); + return chainActive.Height(); } -} - -/** Find the last common ancestor two blocks have. - * Both pa and pb must be non-NULL. */ -CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { - if (pa->nHeight > pb->nHeight) { - pa = pa->GetAncestor(pb->nHeight); - } else if (pb->nHeight > pa->nHeight) { - pb = pb->GetAncestor(pa->nHeight); + + void UpdatePreferredDownload(CNode* node, CNodeState* state) + { + nPreferredDownload -= state->fPreferredDownload; + + // Whether this node should be marked as a preferred download node. + state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; + + nPreferredDownload += state->fPreferredDownload; } - - while (pa != pb && pa && pb) { - pa = pa->pprev; - pb = pb->pprev; + + // Returns time at which to timeout block request (nTime in microseconds) + int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) + { + return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); } - - // Eventually all chain branches meet at the genesis block. - assert(pa == pb); - return pa; -} - -/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has - * at most count entries. */ -void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller) { - if (count == 0) - return; - - vBlocks.reserve(vBlocks.size() + count); - CNodeState *state = State(nodeid); - assert(state != NULL); - - // Make sure pindexBestKnownBlock is up to date, we'll need it. - ProcessBlockAvailability(nodeid); - - if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { - // This peer has nothing interesting. - return; + + void InitializeNode(NodeId nodeid, const CNode *pnode) { + LOCK(cs_main); + CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; + state.name = pnode->addrName; + state.address = pnode->addr; } - - if (state->pindexLastCommonBlock == NULL) { - // Bootstrap quickly by guessing a parent of our best tip is the forking point. - // Guessing wrong in either direction is not a problem. - state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; - } - - // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor - // of its current tip anymore. Go back enough to fix that. - state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); - if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) - return; - - std::vector vToFetch; - CBlockIndex *pindexWalk = state->pindexLastCommonBlock; - // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last - // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to - // download that next block if the window were 1 larger. - int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW; - int nMaxHeight = std::min(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1); - NodeId waitingfor = -1; - while (pindexWalk->nHeight < nMaxHeight) { - // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards - // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive - // as iterating over ~100 CBlockIndex* entries anyway. - int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max(count - vBlocks.size(), 128)); - vToFetch.resize(nToFetch); - pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch); - vToFetch[nToFetch - 1] = pindexWalk; - for (unsigned int i = nToFetch - 1; i > 0; i--) { - vToFetch[i - 1] = vToFetch[i]->pprev; + + void FinalizeNode(NodeId nodeid) { + LOCK(cs_main); + CNodeState *state = State(nodeid); + + if (state->fSyncStarted) + nSyncStarted--; + + if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { + AddressCurrentlyConnected(state->address); } - - // Iterate over those blocks in vToFetch (in forward direction), adding the ones that - // are not yet downloaded and not in flight to vBlocks. In the meantime, update - // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's - // already part of our chain (and therefore don't need it even if pruned). - BOOST_FOREACH(CBlockIndex* pindex, vToFetch) { - if (!pindex->IsValid(BLOCK_VALID_TREE)) { - // We consider the chain that this peer is on invalid. - return; + + BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) + mapBlocksInFlight.erase(entry.hash); + EraseOrphansFor(nodeid); + nPreferredDownload -= state->fPreferredDownload; + + mapNodeState.erase(nodeid); + } + + void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) + { + /* int expired = pool.Expire(GetTime() - age); + if (expired != 0) + LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); + + std::vector vNoSpendsRemaining; + pool.TrimToSize(limit, &vNoSpendsRemaining); + BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) + pcoinsTip->Uncache(removed);*/ + } + + // Requires cs_main. + // Returns a bool indicating whether we requested this block. + bool MarkBlockAsReceived(const uint256& hash) { + map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); + if (itInFlight != mapBlocksInFlight.end()) { + CNodeState *state = State(itInFlight->second.first); + nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; + state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; + state->vBlocksInFlight.erase(itInFlight->second.second); + state->nBlocksInFlight--; + state->nStallingSince = 0; + mapBlocksInFlight.erase(itInFlight); + return true; + } + return false; + } + + // Requires cs_main. + void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + // Make sure it's not listed somewhere already. + MarkBlockAsReceived(hash); + + int64_t nNow = GetTimeMicros(); + QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; + nQueuedValidatedHeaders += newentry.fValidatedHeaders; + list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); + state->nBlocksInFlight++; + state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; + mapBlocksInFlight[hash] = std::make_pair(nodeid, it); + } + + /** Check whether the last unknown block a peer advertized is not yet known. */ + void ProcessBlockAvailability(NodeId nodeid) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + if (!state->hashLastUnknownBlock.IsNull()) { + BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); + if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) + { + if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = itOld->second; + state->hashLastUnknownBlock.SetNull(); } - if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { - if (pindex->nChainTx) - state->pindexLastCommonBlock = pindex; - } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { - // The block is not already downloaded, and not yet in flight. - if (pindex->nHeight > nWindowEnd) { - // We reached the end of the window. - if (vBlocks.size() == 0 && waitingfor != nodeid) { - // We aren't able to fetch anything, but we would be if the download window was one larger. - nodeStaller = waitingfor; + } + } + + /** Update tracking information about which blocks a peer is assumed to have. */ + void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + /*ProcessBlockAvailability(nodeid); + + BlockMap::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { + // An actually better block was announced. + if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = it->second; + } else*/ + { + // An unknown block was announced; just assume that the latest one is the best one. + state->hashLastUnknownBlock = hash; + } + } + + /** Find the last common ancestor two blocks have. + * Both pa and pb must be non-NULL. */ + CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { + if (pa->nHeight > pb->nHeight) { + pa = pa->GetAncestor(pb->nHeight); + } else if (pb->nHeight > pa->nHeight) { + pb = pb->GetAncestor(pa->nHeight); + } + + while (pa != pb && pa && pb) { + pa = pa->pprev; + pb = pb->pprev; + } + + // Eventually all chain branches meet at the genesis block. + assert(pa == pb); + return pa; + } + + /** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has + * at most count entries. */ + void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller) { + if (count == 0) + return; + + vBlocks.reserve(vBlocks.size() + count); + CNodeState *state = State(nodeid); + assert(state != NULL); + + // Make sure pindexBestKnownBlock is up to date, we'll need it. + ProcessBlockAvailability(nodeid); + + if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { + // This peer has nothing interesting. + return; + } + + if (state->pindexLastCommonBlock == NULL) { + // Bootstrap quickly by guessing a parent of our best tip is the forking point. + // Guessing wrong in either direction is not a problem. + state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; + } + + // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor + // of its current tip anymore. Go back enough to fix that. + state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); + if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) + return; + + std::vector vToFetch; + CBlockIndex *pindexWalk = state->pindexLastCommonBlock; + // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last + // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to + // download that next block if the window were 1 larger. + int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW; + int nMaxHeight = std::min(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1); + NodeId waitingfor = -1; + while (pindexWalk->nHeight < nMaxHeight) { + // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards + // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive + // as iterating over ~100 CBlockIndex* entries anyway. + int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max(count - vBlocks.size(), 128)); + vToFetch.resize(nToFetch); + pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch); + vToFetch[nToFetch - 1] = pindexWalk; + for (unsigned int i = nToFetch - 1; i > 0; i--) { + vToFetch[i - 1] = vToFetch[i]->pprev; + } + + // Iterate over those blocks in vToFetch (in forward direction), adding the ones that + // are not yet downloaded and not in flight to vBlocks. In the meantime, update + // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's + // already part of our chain (and therefore don't need it even if pruned). + BOOST_FOREACH(CBlockIndex* pindex, vToFetch) { + if (!pindex->IsValid(BLOCK_VALID_TREE)) { + // We consider the chain that this peer is on invalid. + return; + } + if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { + if (pindex->nChainTx) + state->pindexLastCommonBlock = pindex; + } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { + // The block is not already downloaded, and not yet in flight. + if (pindex->nHeight > nWindowEnd) { + // We reached the end of the window. + if (vBlocks.size() == 0 && waitingfor != nodeid) { + // We aren't able to fetch anything, but we would be if the download window was one larger. + nodeStaller = waitingfor; + } + return; } - return; + vBlocks.push_back(pindex); + if (vBlocks.size() == count) { + return; + } + } else if (waitingfor == -1) { + // This is the first already-in-flight block. + waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first; } - vBlocks.push_back(pindex); - if (vBlocks.size() == count) { - return; - } - } else if (waitingfor == -1) { - // This is the first already-in-flight block. - waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first; } } } -} - + } // anon namespace bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { @@ -562,7 +569,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(); } } @@ -588,7 +595,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) return false; - + // Ignore big transactions, to avoid a // send-big-orphans memory exhaustion attack. If a peer has a legitimate // large transaction with a missing parent then we assume @@ -602,12 +609,12 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); return false; } - + mapOrphanTransactions[hash].tx = tx; mapOrphanTransactions[hash].fromPeer = peer; BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); - + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); + LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); return true; @@ -657,8 +664,8 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); - EraseOrphanTx(it->first); - ++nEvicted; + EraseOrphanTx(it->first); + ++nEvicted; } return nEvicted; } @@ -667,7 +674,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) { bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); - + if (isOverwinter) { // Overwinter standard rules apply if (tx.nVersion > CTransaction::OVERWINTER_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::OVERWINTER_MIN_CURRENT_VERSION) { @@ -681,7 +688,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) return false; } } - + BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed @@ -700,7 +707,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) return false; } } - + unsigned int v=0,nDataOut = 0; txnouttype whichType; BOOST_FOREACH(const CTxOut& txout, tx.vout) @@ -726,13 +733,13 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) } v++; } - + // only one OP_RETURN txout is permitted if (nDataOut > 1) { reason = "multi-op-return"; return false; } - + return true; } @@ -769,7 +776,7 @@ bool IsExpiredTx(const CTransaction &tx, int nBlockHeight) bool CheckFinalTx(const CTransaction &tx, int flags) { AssertLockHeld(cs_main); - + // By convention a negative value for flags indicates that the // current network-enforced consensus rules should be used. In // a future soft-fork scenario that would mean checking which @@ -777,7 +784,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // appropriate flags. At the present time no soft-forks are // scheduled, so no flags are set. flags = std::max(flags, 0); - + // CheckFinalTx() uses chainActive.Height()+1 to evaluate // nLockTime because when IsFinalTx() is called within // CBlock::AcceptBlock(), the height of the block *being* @@ -785,15 +792,15 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // transaction can be part of the *next* block, we need to call // IsFinalTx() with one more than chainActive.Height(). const int nBlockHeight = chainActive.Height() + 1; - + // Timestamps on the other hand don't get any special treatment, // because we can't know what timestamp the next block will have, // and there aren't timestamp applications where it matters. // However this changes once median past time-locks are enforced: const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? chainActive.Tip()->GetMedianTimePast() - : GetAdjustedTime(); - + ? chainActive.Tip()->GetMedianTimePast() + : GetAdjustedTime(); + return IsFinalTx(tx, nBlockHeight, nBlockTime); } @@ -810,11 +817,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally - + for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); - + vector > vSolutions; txnouttype whichType; // get the scriptPubKey corresponding to this input: @@ -824,7 +831,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); if (nArgsExpected < 0) return false; - + // Transactions with extra stuff in their scriptSigs are // non-standard. Note that this EvalScript() call will // be quick, because if there are any operations @@ -834,7 +841,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, vector > stack; if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId)) return false; - + if (whichType == TX_SCRIPTHASH) { if (stack.empty()) @@ -857,11 +864,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, return (sigops <= MAX_P2SH_SIGOPS); } } - + if (stack.size() != (unsigned int)nArgsExpected) return false; } - + return true; } @@ -883,7 +890,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in { if (tx.IsCoinBase()) return 0; - + unsigned int nSigOps = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) { @@ -939,7 +946,7 @@ bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeigh /** * Check a transaction contextually against a set of consensus rules valid at a given block height. - * + * * Notes: * 1. AcceptToMemoryPool calls CheckTransaction and this function. * 2. ProcessNewBlock calls AcceptBlock, which calls CheckBlock (which calls CheckTransaction) @@ -949,39 +956,39 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, { bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); bool isSprout = !isOverwinter; - + // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond if (isSprout && tx.fOverwintered) { return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter is not active yet"), REJECT_INVALID, "tx-overwinter-not-active"); } - + // If Overwinter rules apply: if (isOverwinter) { // Reject transactions with valid version but missing overwinter flag if (tx.nVersion >= OVERWINTER_MIN_TX_VERSION && !tx.fOverwintered) { return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter flag must be set"), - REJECT_INVALID, "tx-overwinter-flag-not-set"); + REJECT_INVALID, "tx-overwinter-flag-not-set"); } - + // Reject transactions with invalid version if (tx.fOverwintered && tx.nVersion > OVERWINTER_MAX_TX_VERSION ) { return state.DoS(100, error("CheckTransaction(): overwinter version too high"), - REJECT_INVALID, "bad-tx-overwinter-version-too-high"); + REJECT_INVALID, "bad-tx-overwinter-version-too-high"); } - + // Reject transactions intended for Sprout if (!tx.fOverwintered) { return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"), - REJECT_INVALID, "tx-overwinter-active"); + REJECT_INVALID, "tx-overwinter-active"); } - + // Check that all transactions are unexpired if (IsExpiredTx(tx, nHeight)) { return state.DoS(dosLevel, error("ContextualCheckTransaction(): transaction is expired"), REJECT_INVALID, "tx-overwinter-expired"); } } - + if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) { auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); // Empty output script. @@ -991,11 +998,11 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); } catch (std::logic_error ex) { return state.DoS(100, error("CheckTransaction(): error computing signature hash"), - REJECT_INVALID, "error-computing-signature-hash"); + REJECT_INVALID, "error-computing-signature-hash"); } - + BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); - + // We rely on libsodium to check that the signature is canonical. // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 if (crypto_sign_verify_detached(&tx.joinSplitSig[0], @@ -1003,7 +1010,7 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, tx.joinSplitPubKey.begin() ) != 0) { return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), - REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); + REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); } } @@ -1036,11 +1043,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, } } } - // Don't count coinbase transactions because mining skews the count + // Don't count coinbase transactions because mining skews the count if (!tx.IsCoinBase()) { transactionsValidated.increment(); } - + if (!CheckTransactionWithoutProofVerification(tx, state)) { return false; } else { @@ -1048,7 +1055,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), - REJECT_INVALID, "bad-txns-joinsplit-verification-failed"); + REJECT_INVALID, "bad-txns-joinsplit-verification-failed"); } } return true; @@ -1058,7 +1065,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state) { // Basic checks that don't depend on any context - + /** * Previously: * 1. The consensus rule below was: @@ -1088,18 +1095,18 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio else if (tx.fOverwintered) { if (tx.nVersion < OVERWINTER_MIN_TX_VERSION) { return state.DoS(100, error("CheckTransaction(): overwinter version too low"), - REJECT_INVALID, "bad-tx-overwinter-version-too-low"); + REJECT_INVALID, "bad-tx-overwinter-version-too-low"); } if (tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) { return state.DoS(100, error("CheckTransaction(): unknown tx version group id"), - REJECT_INVALID, "bad-tx-version-group-id"); + REJECT_INVALID, "bad-tx-version-group-id"); } if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { return state.DoS(100, error("CheckTransaction(): expiry height is too high"), - REJECT_INVALID, "bad-tx-expiry-height-too-high"); + REJECT_INVALID, "bad-tx-expiry-height-too-high"); } } - + // Transactions can contain empty `vin` and `vout` so long as // `vjoinsplit` is non-empty. if (tx.vin.empty() && tx.vjoinsplit.empty()) @@ -1108,13 +1115,13 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio if (tx.vout.empty() && tx.vjoinsplit.empty()) return state.DoS(10, error("CheckTransaction(): vout empty"), REJECT_INVALID, "bad-txns-vout-empty"); - + // Size limits BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE > MAX_TX_SIZE); // sanity if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE) return state.DoS(100, error("CheckTransaction(): size limits failed"), REJECT_INVALID, "bad-txns-oversize"); - + // Check for negative or overflow output values CAmount nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) @@ -1132,7 +1139,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio return state.DoS(100, error("CheckTransaction(): txout total out of range"), REJECT_INVALID, "bad-txns-txouttotal-toolarge"); } - + // Ensure that joinsplit values are well-formed BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) { @@ -1140,34 +1147,34 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old negative"), REJECT_INVALID, "bad-txns-vpub_old-negative"); } - + if (joinsplit.vpub_new < 0) { return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new negative"), REJECT_INVALID, "bad-txns-vpub_new-negative"); } - + if (joinsplit.vpub_old > MAX_MONEY) { return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old too high"), REJECT_INVALID, "bad-txns-vpub_old-toolarge"); } - + if (joinsplit.vpub_new > MAX_MONEY) { return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new too high"), REJECT_INVALID, "bad-txns-vpub_new-toolarge"); } - + if (joinsplit.vpub_new != 0 && joinsplit.vpub_old != 0) { return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new and joinsplit.vpub_old both nonzero"), REJECT_INVALID, "bad-txns-vpubs-both-nonzero"); } - + nValueOut += joinsplit.vpub_old; if (!MoneyRange(nValueOut)) { return state.DoS(100, error("CheckTransaction(): txout total out of range"), REJECT_INVALID, "bad-txns-txouttotal-toolarge"); } } - + // Ensure input values do not exceed MAX_MONEY // We have not resolved the txin values at this stage, // but we do know what the joinsplits claim to add @@ -1177,15 +1184,15 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio for (std::vector::const_iterator it(tx.vjoinsplit.begin()); it != tx.vjoinsplit.end(); ++it) { nValueIn += it->vpub_new; - + if (!MoneyRange(it->vpub_new) || !MoneyRange(nValueIn)) { return state.DoS(100, error("CheckTransaction(): txin total out of range"), REJECT_INVALID, "bad-txns-txintotal-toolarge"); } } } - - + + // Check for duplicate inputs set vInOutPoints; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -1195,7 +1202,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio REJECT_INVALID, "bad-txns-inputs-duplicate"); vInOutPoints.insert(txin.prevout); } - + // Check for duplicate joinsplit nullifiers in this transaction set vJoinSplitNullifiers; BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) @@ -1204,19 +1211,19 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio { if (vJoinSplitNullifiers.count(nf)) return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"), - REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate"); - + REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate"); + vJoinSplitNullifiers.insert(nf); } } - + if (tx.IsCoinBase()) { // There should be no joinsplits in a coinbase transaction if (tx.vjoinsplit.size() > 0) return state.DoS(100, error("CheckTransaction(): coinbase has joinsplits"), REJECT_INVALID, "bad-cb-has-joinsplits"); - + if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) return state.DoS(100, error("CheckTransaction(): coinbase script size"), REJECT_INVALID, "bad-cb-length"); @@ -1224,11 +1231,11 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio else { BOOST_FOREACH(const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull()) - return state.DoS(10, error("CheckTransaction(): prevout is null"), - REJECT_INVALID, "bad-txns-prevout-null"); + if (txin.prevout.IsNull()) + return state.DoS(10, error("CheckTransaction(): prevout is null"), + REJECT_INVALID, "bad-txns-prevout-null"); } - + return true; } @@ -1244,9 +1251,9 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF if (dPriorityDelta > 0 || nFeeDelta > 0) return 0; } - + CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes); - + if (fAllowFree) { // There is a free transaction area in blocks created by most miners, @@ -1256,7 +1263,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)) nMinFee = 0; } - + if (!MoneyRange(nMinFee)) nMinFee = MAX_MONEY; return nMinFee; @@ -1290,11 +1297,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return error("AcceptToMemoryPool: komodo_validate_interest failed"); } if (!CheckTransaction(tx, state, verifier)) + { + return error("AcceptToMemoryPool: CheckTransaction failed"); - + } // DoS level set to 10 to be more forgiving. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. - if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) { + if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) + { return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); } @@ -1335,10 +1345,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa COutPoint outpoint = tx.vin[i].prevout; if (pool.mapNextTx.count(outpoint)) { - static uint32_t counter; + //static uint32_t counter; // Disable replacement feature for now //if ( counter++ < 100 ) - fprintf(stderr,"Disable replacement feature for now\n"); + //fprintf(stderr,"Disable replacement feature for now\n"); return false; } } @@ -1354,7 +1364,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } } - + { CCoinsView dummy; CCoinsViewCache view(&dummy); @@ -1425,7 +1435,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa fprintf(stderr,"accept failure.4\n"); return state.DoS(0, error("AcceptToMemoryPool: too many sigops %s, %d > %d", hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); } - + CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); @@ -1457,7 +1467,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CAmount txMinFee = GetMinRelayFee(tx, nSize, true); if (fLimitFree && nFees < txMinFee) { - fprintf(stderr,"accept failure.5\n"); + //fprintf(stderr,"accept failure.5\n"); return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee"); } } @@ -1528,6 +1538,16 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if ( komodo_is_notarytx(tx) == 0 ) KOMODO_ON_DEMAND++; pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + + // Add memory address index + if (fAddressIndex) { + pool.addAddressIndex(entry, view); + } + + // Add memory spent index + if (fSpentIndex) { + pool.addSpentIndex(entry, view); + } } SyncWithWallets(tx, NULL); @@ -1535,18 +1555,67 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return true; } +bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector > &hashes) +{ + if (!fTimestampIndex) + return error("Timestamp index not enabled"); + + if (!pblocktree->ReadTimestampIndex(high, low, fActiveOnly, hashes)) + return error("Unable to get hashes for timestamps"); + + return true; +} + +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) +{ + if (!fSpentIndex) + return false; + + if (mempool.getSpentIndex(key, value)) + return true; + + if (!pblocktree->ReadSpentIndex(key, value)) + return false; + + return true; +} + +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, int start, int end) +{ + if (!fAddressIndex) + return error("address index not enabled"); + + if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end)) + return error("unable to get txids for address"); + + return true; +} + +bool GetAddressUnspent(uint160 addressHash, int type, + std::vector > &unspentOutputs) +{ + if (!fAddressIndex) + return error("address index not enabled"); + + if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs)) + return error("unable to get txids for address"); + + return true; +} + /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { CBlockIndex *pindexSlow = NULL; - + LOCK(cs_main); - + if (mempool.lookup(hash, txOut)) { return true; } - + if (fTxIndex) { CDiskTxPos postx; if (pblocktree->ReadTxIndex(hash, postx)) { @@ -1567,7 +1636,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return true; } } - + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it int nHeight = -1; { @@ -1579,10 +1648,10 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (nHeight > 0) pindexSlow = chainActive[nHeight]; } - + if (pindexSlow) { CBlock block; - if (ReadBlockFromDisk(block, pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow,1)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1592,23 +1661,23 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock } } } - + return false; } /*char *komodo_getspendscript(uint256 hash,int32_t n) -{ - CTransaction tx; uint256 hashBlock; - if ( !GetTransaction(hash,tx,hashBlock,true) ) - { - printf("null GetTransaction\n"); - return(0); - } - if ( n >= 0 && n < tx.vout.size() ) - return((char *)tx.vout[n].scriptPubKey.ToString().c_str()); - else printf("getspendscript illegal n.%d\n",n); - return(0); -}*/ + { + CTransaction tx; uint256 hashBlock; + if ( !GetTransaction(hash,tx,hashBlock,true) ) + { + printf("null GetTransaction\n"); + return(0); + } + if ( n >= 0 && n < tx.vout.size() ) + return((char *)tx.vout[n].scriptPubKey.ToString().c_str()); + else printf("getspendscript illegal n.%d\n",n); + return(0); + }*/ ////////////////////////////////////////////////////////////////////////////// @@ -1622,34 +1691,34 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::M CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) return error("WriteBlockToDisk: OpenBlockFile failed"); - + // Write index header unsigned int nSize = fileout.GetSerializeSize(block); fileout << FLATDATA(messageStart) << nSize; - + // Write block long fileOutPos = ftell(fileout.Get()); if (fileOutPos < 0) return error("WriteBlockToDisk: ftell failed"); pos.nPos = (unsigned int)fileOutPos; fileout << block; - + return true; } -bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos) +bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos,bool checkPOW) { uint8_t pubkey33[33]; block.SetNull(); - + // Open history file to read CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); if (filein.IsNull()) { //fprintf(stderr,"readblockfromdisk err A\n"); - return false;//error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); + return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); } - + // Read block try { filein >> block; @@ -1659,34 +1728,38 @@ 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); - if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()))) + if ( 0 && checkPOW != 0 ) { - int32_t i; for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - fprintf(stderr," warning unexpected diff at ht.%d\n",height); - - return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + komodo_block2pubkey33(pubkey33,(CBlock *)&block); + if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus(),block.nTime))) + { + int32_t i; for (i=0; i<33; i++) + fprintf(stderr,"%02x",pubkey33[i]); + fprintf(stderr," warning unexpected diff at ht.%d\n",height); + + return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + } } return true; } -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW) { if ( pindex == 0 ) return false; - if (!ReadBlockFromDisk(pindex->nHeight,block, pindex->GetBlockPos())) + if (!ReadBlockFromDisk(pindex->nHeight,block, pindex->GetBlockPos(),checkPOW)) return false; if (block.GetHash() != pindex->GetBlockHash()) return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", - pindex->ToString(), pindex->GetBlockPos().ToString()); + pindex->ToString(), pindex->GetBlockPos().ToString()); return true; } //uint64_t komodo_moneysupply(int32_t height); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +extern uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS]; extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; +extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { @@ -1706,27 +1779,27 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) else return(komodo_ac_block_subsidy(nHeight)); } -/* - // Mining slow start - // The subsidy is ramped up linearly, skipping the middle payout of - // MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start. - if (nHeight < consensusParams.nSubsidySlowStartInterval / 2) { - nSubsidy /= consensusParams.nSubsidySlowStartInterval; - nSubsidy *= nHeight; - return nSubsidy; - } else if (nHeight < consensusParams.nSubsidySlowStartInterval) { - nSubsidy /= consensusParams.nSubsidySlowStartInterval; - nSubsidy *= (nHeight+1); - return nSubsidy; - } - - assert(nHeight > consensusParams.SubsidySlowStartShift()); - int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;*/ + /* + // Mining slow start + // The subsidy is ramped up linearly, skipping the middle payout of + // MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start. + if (nHeight < consensusParams.nSubsidySlowStartInterval / 2) { + nSubsidy /= consensusParams.nSubsidySlowStartInterval; + nSubsidy *= nHeight; + return nSubsidy; + } else if (nHeight < consensusParams.nSubsidySlowStartInterval) { + nSubsidy /= consensusParams.nSubsidySlowStartInterval; + nSubsidy *= (nHeight+1); + return nSubsidy; + } + + assert(nHeight > consensusParams.SubsidySlowStartShift()); + int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;*/ // Force block reward to zero when right shift is undefined. //int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; //if (halvings >= 64) // return 0; - + // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years. //nSubsidy >>= halvings; //return nSubsidy; @@ -1758,8 +1831,8 @@ bool IsInitialBlockDownload() else if ( pindexBestHeader != 0 && pindexBestHeader->nHeight > ptr->nHeight ) ptr = pindexBestHeader; //if ( ASSETCHAINS_SYMBOL[0] == 0 ) - state = ((chainActive.Height() < ptr->nHeight - 24*60) || - ptr->GetBlockTime() < (GetTime() - chainParams.MaxTipAge())); + state = ((chainActive.Height() < ptr->nHeight - 24*60) || + ptr->GetBlockTime() < (GetTime() - chainParams.MaxTipAge())); //else state = (chainActive.Height() < ptr->nHeight - 24*60); //fprintf(stderr,"state.%d ht.%d vs %d, t.%u %u\n",state,(int32_t)chainActive.Height(),(uint32_t)ptr->nHeight,(int32_t)ptr->GetBlockTime(),(uint32_t)(GetTime() - chainParams.MaxTipAge())); if (!state) @@ -1780,25 +1853,25 @@ void CheckForkWarningConditions() // (we assume we don't get stuck on a fork before the last checkpoint) if (IsInitialBlockDownload()) return; - + // If our best fork is no longer within 288 blocks (+/- 12 hours if no one mines it) // of our head, drop it if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 288) pindexBestForkTip = NULL; - + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) { if (!fLargeWorkForkFound && pindexBestForkBase) { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); + pindexBestForkBase->phashBlock->ToString() + std::string("'"); CAlert::Notify(warning, true); } if (pindexBestForkTip && pindexBestForkBase) { LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, - pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), - pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); + pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), + pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); fLargeWorkForkFound = true; } else @@ -1830,7 +1903,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) break; pfork = pfork->pprev; } - + // We define a condition where we should warn the user about as a fork of at least 7 blocks // with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network @@ -1839,13 +1912,13 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // We define it this way because it allows us to only store the highest fork tip (+ base) which meets // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - chainActive.Height() - pindexNewForkTip->nHeight < 72) + pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && + chainActive.Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; pindexBestForkBase = pfork; } - + CheckForkWarningConditions(); } @@ -1854,13 +1927,13 @@ void Misbehaving(NodeId pnode, int howmuch) { if (howmuch == 0) return; - + CNodeState *state = State(pnode); if (state == NULL) return; - + state->nMisbehavior += howmuch; - int banscore = GetArg("-banscore", 100); + int banscore = GetArg("-banscore", 101); if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) { LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); @@ -1873,16 +1946,16 @@ void static InvalidChainFound(CBlockIndex* pindexNew) { if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) pindexBestInvalid = pindexNew; - + LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, - pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, - log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", - pindexNew->GetBlockTime())); + pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, + log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", + pindexNew->GetBlockTime())); CBlockIndex *tip = chainActive.Tip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, - tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); + tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); CheckForkWarningConditions(); } @@ -1913,7 +1986,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund BOOST_FOREACH(const CTxIn &txin, tx.vin) { CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); unsigned nPos = txin.prevout.n; - + if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull()) assert(false); // mark an outpoint spent, and construct undo information @@ -1943,7 +2016,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; @@ -1957,17 +2030,17 @@ int GetSpendHeight(const CCoinsViewCache& inputs) } namespace Consensus { -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams) -{ + bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams) + { // This doesn't trigger the DoS code on purpose; if it did, it would make it easier // for an attacker to attempt to split the network. if (!inputs.HaveInputs(tx)) return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString())); - + // are the JoinSplit's requirements met? if (!inputs.HaveJoinSplitRequirements(tx)) return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString())); - + CAmount nValueIn = 0; CAmount nFees = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) @@ -1975,26 +2048,26 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins const COutPoint &prevout = tx.vin[i].prevout; const CCoins *coins = inputs.AccessCoins(prevout.hash); assert(coins); - + if (coins->IsCoinBase()) { // Ensure that coinbases are matured if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { return state.Invalid( - error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), - REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); + error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), + REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); } - + // Ensure that coinbases cannot be spent to transparent outputs // Disabled on regtest if (fCoinbaseEnforcedProtectionEnabled && consensusParams.fCoinbaseMustBeProtected && !tx.vout.empty()) { return state.Invalid( - error("CheckInputs(): tried to spend coinbase with transparent outputs"), - REJECT_INVALID, "bad-txns-coinbase-spend-has-transparent-outputs"); + error("CheckInputs(): tried to spend coinbase with transparent outputs"), + REJECT_INVALID, "bad-txns-coinbase-spend-has-transparent-outputs"); } } - + // Check for negative or overflow input values nValueIn += coins->vout[prevout.n].nValue; #ifdef KOMODO_ENABLE_INTEREST @@ -2005,7 +2078,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins int64_t interest; int32_t txheight; uint32_t locktime; if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue,(int32_t)nSpendHeight-1)) != 0 ) { -//fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime); + //fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime); nValueIn += interest; } } @@ -2014,14 +2087,14 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) return state.DoS(100, error("CheckInputs(): txin values out of range"), REJECT_INVALID, "bad-txns-inputvalues-outofrange"); - + } - + nValueIn += tx.GetJoinSplitValueIn(); if (!MoneyRange(nValueIn)) return state.DoS(100, error("CheckInputs(): vpub_old values out of range"), REJECT_INVALID, "bad-txns-inputvalues-outofrange"); - + if (nValueIn < tx.GetValueOut()) { fprintf(stderr,"spentheight.%d valuein %s vs %s error\n",nSpendHeight,FormatMoney(nValueIn).c_str(), FormatMoney(tx.GetValueOut()).c_str()); @@ -2037,35 +2110,35 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins if (!MoneyRange(nFees)) return state.DoS(100, error("CheckInputs(): nFees out of range"), REJECT_INVALID, "bad-txns-fee-outofrange"); - return true; -} + return true; + } }// namespace Consensus bool ContextualCheckInputs( - const CTransaction& tx, - CValidationState &state, - const CCoinsViewCache &inputs, - bool fScriptChecks, - unsigned int flags, - bool cacheStore, - PrecomputedTransactionData& txdata, - const Consensus::Params& consensusParams, - uint32_t consensusBranchId, - std::vector *pvChecks) + const CTransaction& tx, + CValidationState &state, + const CCoinsViewCache &inputs, + bool fScriptChecks, + unsigned int flags, + bool cacheStore, + PrecomputedTransactionData& txdata, + const Consensus::Params& consensusParams, + uint32_t consensusBranchId, + std::vector *pvChecks) { if (!tx.IsCoinBase()) { if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), consensusParams)) { return false; } - + if (pvChecks) pvChecks->reserve(tx.vin.size()); - + // The first loop above does all the inexpensive checks. // Only if ALL inputs pass do we perform expensive ECDSA signature checks. // Helps prevent CPU exhaustion attacks. - + // Skip ECDSA signature verification when connecting blocks // before the last block chain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. @@ -2074,7 +2147,7 @@ bool ContextualCheckInputs( const COutPoint &prevout = tx.vin[i].prevout; const CCoins* coins = inputs.AccessCoins(prevout.hash); assert(coins); - + // Verify signature CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata); if (pvChecks) { @@ -2089,7 +2162,7 @@ bool ContextualCheckInputs( // avoid splitting the network between upgraded and // non-upgraded nodes. CScriptCheck check2(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata); + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata); if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } @@ -2105,123 +2178,122 @@ bool ContextualCheckInputs( } } } - + return true; } /*bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) -{ - if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) { - fprintf(stderr,"ContextualCheckInputs failure.0\n"); - return false; - } - - if (!tx.IsCoinBase()) - { - // While checking, GetBestBlock() refers to the parent block. - // This is also true for mempool checks. - CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; - int nSpendHeight = pindexPrev->nHeight + 1; - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const COutPoint &prevout = tx.vin[i].prevout; - const CCoins *coins = inputs.AccessCoins(prevout.hash); - // Assertion is okay because NonContextualCheckInputs ensures the inputs - // are available. - assert(coins); - - // If prev is coinbase, check that it's matured - if (coins->IsCoinBase()) { - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - COINBASE_MATURITY = _COINBASE_MATURITY; - if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { - fprintf(stderr,"ContextualCheckInputs failure.1 i.%d of %d\n",i,(int32_t)tx.vin.size()); - - return state.Invalid( - error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); - } - } - } - } - - return true; -}*/ + { + if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) { + fprintf(stderr,"ContextualCheckInputs failure.0\n"); + return false; + } + + if (!tx.IsCoinBase()) + { + // While checking, GetBestBlock() refers to the parent block. + // This is also true for mempool checks. + CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; + int nSpendHeight = pindexPrev->nHeight + 1; + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + const COutPoint &prevout = tx.vin[i].prevout; + const CCoins *coins = inputs.AccessCoins(prevout.hash); + // Assertion is okay because NonContextualCheckInputs ensures the inputs + // are available. + assert(coins); + + // If prev is coinbase, check that it's matured + if (coins->IsCoinBase()) { + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + COINBASE_MATURITY = _COINBASE_MATURITY; + if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { + fprintf(stderr,"ContextualCheckInputs failure.1 i.%d of %d\n",i,(int32_t)tx.vin.size()); + + return state.Invalid( + error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); + } + } + } + } + + return true; + }*/ namespace { - -bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) -{ - // Open history file to append - CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: OpenUndoFile failed", __func__); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(blockundo); - fileout << FLATDATA(messageStart) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("%s: ftell failed", __func__); - pos.nPos = (unsigned int)fileOutPos; - fileout << blockundo; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - fileout << hasher.GetHash(); - - return true; -} - -bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) -{ - // Open history file to read - CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - - // Read block - uint256 hashChecksum; - try { - filein >> blockundo; - filein >> hashChecksum; + + bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) + { + // Open history file to append + CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: OpenUndoFile failed", __func__); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(blockundo); + fileout << FLATDATA(messageStart) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) + return error("%s: ftell failed", __func__); + pos.nPos = (unsigned int)fileOutPos; + fileout << blockundo; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + fileout << hasher.GetHash(); + + return true; } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + + bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) + { + // Open history file to read + CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + + // Read block + uint256 hashChecksum; + try { + filein >> blockundo; + filein >> hashChecksum; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + if (hashChecksum != hasher.GetHash()) + return error("%s: Checksum mismatch", __func__); + + return true; } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - if (hashChecksum != hasher.GetHash()) - return error("%s: Checksum mismatch", __func__); - - return true; -} - -/** Abort with a message */ -bool AbortNode(const std::string& strMessage, const std::string& userMessage="") -{ - strMiscWarning = strMessage; - LogPrintf("*** %s\n", strMessage); - uiInterface.ThreadSafeMessageBox( - userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, - "", CClientUIInterface::MSG_ERROR); - StartShutdown(); - return false; -} - -bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="") -{ - AbortNode(strMessage, userMessage); - return state.Error(strMessage); -} - + + /** Abort with a message */ + bool AbortNode(const std::string& strMessage, const std::string& userMessage="") + { + strMiscWarning = strMessage; + LogPrintf("*** %s\n", strMessage); + uiInterface.ThreadSafeMessageBox( + userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; + } + + bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="") + { + AbortNode(strMessage, userMessage); + return state.Error(strMessage); + } + } // anon namespace /** @@ -2234,7 +2306,7 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out) { bool fClean = true; - + CCoinsModifier coins = view.ModifyCoins(out.hash); if (undo.nHeight != 0) { // undo data contains height: this is the last output of the prevout tx being spent @@ -2253,17 +2325,17 @@ static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const CO if (coins->vout.size() < out.n+1) coins->vout.resize(out.n+1); coins->vout[out.n] = undo.txout; - + return fClean; } bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { assert(pindex->GetBlockHash() == view.GetBestBlock()); - + if (pfClean) *pfClean = false; - + bool fClean = true; komodo_disconnect(pindex,block); CBlockUndo blockUndo; @@ -2272,41 +2344,74 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex return error("DisconnectBlock(): no undo data available"); if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) return error("DisconnectBlock(): failure reading undo data"); - + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) return error("DisconnectBlock(): block and undo data inconsistent"); + std::vector > addressIndex; + std::vector > addressUnspentIndex; + std::vector > spentIndex; // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); + if (fAddressIndex) { + + for (unsigned int k = tx.vout.size(); k-- > 0;) { + const CTxOut &out = tx.vout[k]; + + if (out.scriptPubKey.IsPayToScriptHash()) { + vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + + // undo receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); + + // undo unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), hash, k), CAddressUnspentValue())); + + } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { + vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + + // undo receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue)); + + // undo unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue())); + + } else { + continue; + } + + } + + } // Check that all outputs are available and match the outputs in the block itself // exactly. { - CCoinsModifier outs = view.ModifyCoins(hash); - outs->ClearUnspendable(); - - CCoins outsBlock(tx, pindex->nHeight); - // The CCoins serialization does not serialize negative numbers. - // No network rules currently depend on the version here, so an inconsistency is harmless - // but it must be corrected before txout nversion ever influences a network rule. - if (outsBlock.nVersion < 0) - outs->nVersion = outsBlock.nVersion; - if (*outs != outsBlock) - fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); - - // remove outputs - outs->Clear(); + CCoinsModifier outs = view.ModifyCoins(hash); + outs->ClearUnspendable(); + + CCoins outsBlock(tx, pindex->nHeight); + // The CCoins serialization does not serialize negative numbers. + // No network rules currently depend on the version here, so an inconsistency is harmless + // but it must be corrected before txout nversion ever influences a network rule. + if (outsBlock.nVersion < 0) + outs->nVersion = outsBlock.nVersion; + if (*outs != outsBlock) + fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); + + // remove outputs + outs->Clear(); } - + // unspend nullifiers BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { view.SetNullifier(nf, false); } } - + // restore inputs if (i > 0) { // not coinbases const CTxUndo &txundo = blockUndo.vtxundo[i-1]; @@ -2317,30 +2422,71 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex const CTxInUndo &undo = txundo.vprevout[j]; if (!ApplyTxInUndo(undo, view, out)) fClean = false; + + const CTxIn input = tx.vin[j]; + + if (fSpentIndex) { + // undo and delete the spent index + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue())); + } + + if (fAddressIndex) { + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + if (prevout.scriptPubKey.IsPayToScriptHash()) { + vector hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); + + // undo spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); + + // restore unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); + + + } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { + vector hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); + + // undo spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); + + // restore unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); + + } else { + continue; + } + } } } } - + // set the old best anchor back view.PopAnchor(blockUndo.old_tree_root); - + // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); - + if (pfClean) { *pfClean = fClean; return true; } + if (fAddressIndex) { + if (!pblocktree->EraseAddressIndex(addressIndex)) { + return AbortNode(state, "Failed to delete address index"); + } + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + return AbortNode(state, "Failed to write address unspent index"); + } + } return fClean; } void static FlushBlockFile(bool fFinalize = false) { LOCK(cs_LastBlockFile); - + CDiskBlockPos posOld(nLastBlockFile, 0); - + FILE *fileOld = OpenBlockFile(posOld); if (fileOld) { if (fFinalize) @@ -2348,7 +2494,7 @@ void static FlushBlockFile(bool fFinalize = false) FileCommit(fileOld); fclose(fileOld); } - + fileOld = OpenUndoFile(posOld); if (fileOld) { if (fFinalize) @@ -2376,20 +2522,20 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const int64_t nPowTargetSpacing) { if (bestHeader == NULL || initialDownloadCheck()) return; - + static int64_t lastAlertTime = 0; int64_t now = GetAdjustedTime(); if (lastAlertTime > now-60*60*24) return; // Alert at most once per day - + const int SPAN_HOURS=4; const int SPAN_SECONDS=SPAN_HOURS*60*60; int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; - + boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); - + std::string strWarning; int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; - + LOCK(cs); const CBlockIndex* i = bestHeader; int nBlocks = 0; @@ -2398,17 +2544,17 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const i = i->pprev; if (i == NULL) return; // Ran out of chain, we must not be fully synced } - + // How likely is it to find that many by chance? double p = boost::math::pdf(poisson, nBlocks); - + LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p); - + // Aim for one false-positive about every fifty years of normal running: const int FIFTY_YEARS = 50*365*24*60*60; double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); - + if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) { // Many fewer blocks than expected: alert! @@ -2435,9 +2581,10 @@ static int64_t nTimeIndex = 0; static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) { const CChainParams& chainparams = Params(); + //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight); AssertLockHeld(cs_main); bool fExpensiveChecks = true; @@ -2450,15 +2597,24 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } auto verifier = libzcash::ProofVerifier::Strict(); auto disabledVerifier = libzcash::ProofVerifier::Disabled(); - + int32_t futureblock; // Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in - if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck)) + if (!CheckBlock(&futureblock,pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, fCheckPOW, !fJustCheck) || futureblock != 0 ) + { + //fprintf(stderr,"checkblock failure in connectblock futureblock.%d\n",futureblock); return false; - + } + // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); + if ( hashPrevBlock != view.GetBestBlock() ) + { + fprintf(stderr,"ConnectBlock(): hashPrevBlock != view.GetBestBlock()\n"); + return state.DoS(1, error("ConnectBlock(): hashPrevBlock != view.GetBestBlock()"), + REJECT_INVALID, "hashPrevBlock-not-bestblock"); + } assert(hashPrevBlock == view.GetBestBlock()); - + // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { @@ -2472,7 +2628,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } return true; } - + bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); //if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet" // return(false); @@ -2484,15 +2640,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30"); } - + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; - + // DERSIG (BIP66) is also always enforced, but does not have a flag. - + CBlockUndo blockundo; - + CCheckQueueControl control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); - + int64_t nTimeStart = GetTimeMicros(); CAmount nFees = 0; int nInputs = 0; @@ -2502,7 +2658,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector > vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); - + std::vector > addressIndex; + std::vector > addressUnspentIndex; + std::vector > spentIndex; // Construct the incremental merkle tree at the current // block position, auto old_tree_root = view.GetBestAnchor(); @@ -2514,38 +2672,74 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // This should never fail: we should always be able to get the root // that is on the tip of our chain assert(view.GetAnchorAt(old_tree_root, tree)); - + { // Consistency check: the root of the tree we're given should // match what we asked for. assert(tree.root() == old_tree_root); } - + // Grab the consensus branch ID for the block's height auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus()); - + std::vector txdata; txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; + const uint256 txhash = tx.GetHash(); nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); -//fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime); + //fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime); if (!tx.IsCoinBase()) { if (!view.HaveInputs(tx)) return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent"); - + // are the JoinSplit's requirements met? if (!view.HaveJoinSplitRequirements(tx)) return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); + if (fAddressIndex || fSpentIndex) + { + for (size_t j = 0; j < tx.vin.size(); j++) { + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + uint160 hashBytes; + int addressType; + + if (prevout.scriptPubKey.IsPayToScriptHash()) { + hashBytes = uint160(vector (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); + addressType = 2; + } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { + hashBytes = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); + addressType = 1; + } else { + hashBytes.SetNull(); + addressType = 0; + } + + if (fAddressIndex && addressType > 0) { + // record spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); + + // remove address from unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); + } + + if (fSpentIndex) { + // add the spent index to determine the txid and input that spent an output + // and to find the amount and address from an input + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); + } + } + + } // Add in sigops done by pay-to-script-hash inputs; // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. @@ -2554,19 +2748,49 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); } - + txdata.emplace_back(tx); - + if (!tx.IsCoinBase()) { nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut(); sum += interest; - + std::vector vChecks; if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } + + if (fAddressIndex) { + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + + if (out.scriptPubKey.IsPayToScriptHash()) { + vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); + + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(2, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); + + } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { + vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue)); + + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); + + } else { + continue; + } + + } + } + //if ( ASSETCHAINS_SYMBOL[0] == 0 ) // komodo_earned_interest(pindex->nHeight,sum); CTxUndo undoDummy; @@ -2574,37 +2798,47 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin blockundo.vtxundo.push_back(CTxUndo()); } UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); - + BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) { // Insert the note commitments into our temporary tree. - + tree.append(note_commitment); } } - + vPos.push_back(std::make_pair(tx.GetHash(), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } - + view.PushAnchor(tree); if (!fJustCheck) { pindex->hashAnchorEnd = tree.root(); } blockundo.old_tree_root = old_tree_root; - + 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()) + sum; + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 ) + { + uint64_t checktoshis; + if ( (checktoshis= komodo_commission((CBlock *)&block)) != 0 ) + { + if ( block.vtx[0].vout.size() == 2 && block.vtx[0].vout[1].nValue == checktoshis ) + blockReward += checktoshis; + else fprintf(stderr,"checktoshis %.8f numvouts %d\n",dstr(checktoshis),(int32_t)block.vtx[0].vout.size()); + } + } 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"); + 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 ) 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)); } @@ -2612,10 +2846,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, false); int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart; LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime2 - nTimeStart), nInputs <= 1 ? 0 : 0.001 * (nTime2 - nTimeStart) / (nInputs-1), nTimeVerify * 0.000001); - + if (fJustCheck) return true; - + // Write undo information to disk if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { @@ -2625,42 +2859,76 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return error("ConnectBlock(): FindUndoPos failed"); if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) return AbortNode(state, "Failed to write undo data"); - + // update nUndoPos in block index pindex->nUndoPos = pos.nPos; pindex->nStatus |= BLOCK_HAVE_UNDO; } - + // Now that all consensus rules have been validated, set nCachedBranchId. // Move this if BLOCK_VALID_CONSENSUS is ever altered. static_assert(BLOCK_VALID_CONSENSUS == BLOCK_VALID_SCRIPTS, - "nCachedBranchId must be set after all consensus rules have been validated."); + "nCachedBranchId must be set after all consensus rules have been validated."); if (IsActivationHeightForAnyUpgrade(pindex->nHeight, Params().GetConsensus())) { pindex->nStatus |= BLOCK_ACTIVATES_UPGRADE; pindex->nCachedBranchId = CurrentEpochBranchId(pindex->nHeight, chainparams.GetConsensus()); } else if (pindex->pprev) { pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; } - + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); setDirtyBlockIndex.insert(pindex); } - + if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); + if (fAddressIndex) { + if (!pblocktree->WriteAddressIndex(addressIndex)) { + return AbortNode(state, "Failed to write address index"); + } + + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + return AbortNode(state, "Failed to write address unspent index"); + } + } + + if (fSpentIndex) + if (!pblocktree->UpdateSpentIndex(spentIndex)) + return AbortNode(state, "Failed to write transaction index"); + + if (fTimestampIndex) { + unsigned int logicalTS = pindex->nTime; + unsigned int prevLogicalTS = 0; + + // retrieve logical timestamp of the previous block + if (pindex->pprev) + if (!pblocktree->ReadTimestampBlockIndex(pindex->pprev->GetBlockHash(), prevLogicalTS)) + LogPrintf("%s: Failed to read previous block's logical timestamp\n", __func__); + + if (logicalTS <= prevLogicalTS) { + logicalTS = prevLogicalTS + 1; + LogPrintf("%s: Previous logical timestamp is newer Actual[%d] prevLogical[%d] Logical[%d]\n", __func__, pindex->nTime, prevLogicalTS, logicalTS); + } + + if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(logicalTS, pindex->GetBlockHash()))) + return AbortNode(state, "Failed to write timestamp index"); + + if (!pblocktree->WriteTimestampBlockIndex(CTimestampBlockIndexKey(pindex->GetBlockHash()), CTimestampBlockIndexValue(logicalTS))) + return AbortNode(state, "Failed to write blockhash index"); + } // add this block to the view's block chain view.SetBestBlock(pindex->GetBlockHash()); - + int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2; LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001); - + // Watch for changes to the previous coinbase transaction. static uint256 hashPrevBestCoinBase; GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.vtx[0].GetHash(); - + int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3; LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001); @@ -2690,88 +2958,88 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { std::set setFilesToPrune; bool fFlushForPrune = false; try { - if (fPruneMode && fCheckForPruning && !fReindex) { - FindFilesToPrune(setFilesToPrune); - fCheckForPruning = false; - if (!setFilesToPrune.empty()) { - fFlushForPrune = true; - if (!fHavePruned) { - pblocktree->WriteFlag("prunedblockfiles", true); - fHavePruned = true; + if (fPruneMode && fCheckForPruning && !fReindex) { + FindFilesToPrune(setFilesToPrune); + fCheckForPruning = false; + if (!setFilesToPrune.empty()) { + fFlushForPrune = true; + if (!fHavePruned) { + pblocktree->WriteFlag("prunedblockfiles", true); + fHavePruned = true; + } } } - } - int64_t nNow = GetTimeMicros(); - // Avoid writing/flushing immediately after startup. - if (nLastWrite == 0) { - nLastWrite = nNow; - } - if (nLastFlush == 0) { - nLastFlush = nNow; - } - if (nLastSetChain == 0) { - nLastSetChain = nNow; - } - size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); - // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). - bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; - // The cache is over the limit, we have to write now. - bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; - // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. - bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; - // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. - bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; - // Combine all conditions that result in a full cache flush. - bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; - // Write blocks and block index to disk. - if (fDoFullFlush || fPeriodicWrite) { - // Depend on nMinDiskSpace to ensure we can write block index - if (!CheckDiskSpace(0)) - return state.Error("out of disk space"); - // First make sure all block and undo data is flushed to disk. - FlushBlockFile(); - // Then update all block file information (which may refer to block and undo files). - { - std::vector > vFiles; - vFiles.reserve(setDirtyFileInfo.size()); - for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { - vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); - setDirtyFileInfo.erase(it++); - } - std::vector vBlocks; - vBlocks.reserve(setDirtyBlockIndex.size()); - for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { - vBlocks.push_back(*it); - setDirtyBlockIndex.erase(it++); - } - if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { - return AbortNode(state, "Files to write to block index database"); - } + int64_t nNow = GetTimeMicros(); + // Avoid writing/flushing immediately after startup. + if (nLastWrite == 0) { + nLastWrite = nNow; + } + if (nLastFlush == 0) { + nLastFlush = nNow; + } + if (nLastSetChain == 0) { + nLastSetChain = nNow; + } + size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); + // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). + bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; + // The cache is over the limit, we have to write now. + bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; + // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. + bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; + // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. + bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; + // Combine all conditions that result in a full cache flush. + bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; + // Write blocks and block index to disk. + if (fDoFullFlush || fPeriodicWrite) { + // Depend on nMinDiskSpace to ensure we can write block index + if (!CheckDiskSpace(0)) + return state.Error("out of disk space"); + // First make sure all block and undo data is flushed to disk. + FlushBlockFile(); + // Then update all block file information (which may refer to block and undo files). + { + std::vector > vFiles; + vFiles.reserve(setDirtyFileInfo.size()); + for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { + vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); + setDirtyFileInfo.erase(it++); + } + std::vector vBlocks; + vBlocks.reserve(setDirtyBlockIndex.size()); + for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { + vBlocks.push_back(*it); + setDirtyBlockIndex.erase(it++); + } + if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { + return AbortNode(state, "Files to write to block index database"); + } + } + // Finally remove any pruned files + if (fFlushForPrune) + UnlinkPrunedFiles(setFilesToPrune); + nLastWrite = nNow; + } + // Flush best chain related state. This can only be done if the blocks / block index write was also done. + if (fDoFullFlush) { + // Typical CCoins structures on disk are around 128 bytes in size. + // Pushing a new one to the database can cause it to be written + // twice (once in the log, and once in the tables). This is already + // an overestimation, as most will delete an existing entry or + // overwrite one. Still, use a conservative safety factor of 2. + if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) + return state.Error("out of disk space"); + // Flush the chainstate (which may refer to block index entries). + if (!pcoinsTip->Flush()) + return AbortNode(state, "Failed to write to coin database"); + nLastFlush = nNow; + } + if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) { + // Update best block in wallet (so we can detect restored wallets). + GetMainSignals().SetBestChain(chainActive.GetLocator()); + nLastSetChain = nNow; } - // Finally remove any pruned files - if (fFlushForPrune) - UnlinkPrunedFiles(setFilesToPrune); - nLastWrite = nNow; - } - // Flush best chain related state. This can only be done if the blocks / block index write was also done. - if (fDoFullFlush) { - // Typical CCoins structures on disk are around 128 bytes in size. - // Pushing a new one to the database can cause it to be written - // twice (once in the log, and once in the tables). This is already - // an overestimation, as most will delete an existing entry or - // overwrite one. Still, use a conservative safety factor of 2. - if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) - return state.Error("out of disk space"); - // Flush the chainstate (which may refer to block index entries). - if (!pcoinsTip->Flush()) - return AbortNode(state, "Failed to write to coin database"); - nLastFlush = nNow; - } - if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) { - // Update best block in wallet (so we can detect restored wallets). - GetMainSignals().SetBestChain(chainActive.GetLocator()); - nLastSetChain = nNow; - } } catch (const std::runtime_error& e) { return AbortNode(state, std::string("System error while flushing: ") + e.what()); } @@ -2793,18 +3061,18 @@ void PruneAndFlush() { void static UpdateTip(CBlockIndex *pindexNew) { const CChainParams& chainParams = Params(); chainActive.SetTip(pindexNew); - + // New best block nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - + KOMODO_NEWBLOCKS++; LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); - + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); + cvBlockChange.notify_all(); - + // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; if (!IsInitialBlockDownload() && !fWarned) @@ -2838,7 +3106,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { assert(pindexDelete); // Read block from disk. CBlock block; - if (!ReadBlockFromDisk(block, pindexDelete)) + if (!ReadBlockFromDisk(block, pindexDelete,1)) return AbortNode(state, "Failed to read block"); // Apply the block atomically to the chain state. uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor(); @@ -2854,7 +3122,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { // Write the chain state to disk, if necessary. if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) return false; - + if (!fBare) { // Resurrect mempool transactions from the disconnected block. BOOST_FOREACH(const CTransaction &tx, block.vtx) { @@ -2870,7 +3138,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { mempool.removeWithAnchor(anchorBeforeDisconnect); } } - + // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); // Get the current commitment tree @@ -2905,7 +3173,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * int64_t nTime1 = GetTimeMicros(); CBlock block; if (!pblock) { - if (!ReadBlockFromDisk(block, pindexNew)) + if (!ReadBlockFromDisk(block, pindexNew,1)) return AbortNode(state, "Failed to read block"); pblock = █ } @@ -2918,7 +3186,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - bool rv = ConnectBlock(*pblock, state, pindexNew, view); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, true); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) @@ -2940,10 +3208,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * // Remove conflicting transactions from the mempool. list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); - + // Remove transactions that expire at new block height from mempool mempool.removeExpired(pindexNew->nHeight); - + // Update chainActive & related variables. UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool @@ -2958,12 +3226,14 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * // Update cached incremental witnesses //fprintf(stderr,"chaintip true\n"); GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true); - + EnforceNodeDeprecation(pindexNew->nHeight); - + int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + komodo_broadcast(pblock,8); return true; } @@ -2974,7 +3244,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * static CBlockIndex* FindMostWorkChain() { do { CBlockIndex *pindexNew = NULL; - + // Find the best candidate header. { std::set::reverse_iterator it = setBlockIndexCandidates.rbegin(); @@ -2982,14 +3252,14 @@ static CBlockIndex* FindMostWorkChain() { return NULL; pindexNew = *it; } - + // Check whether all blocks on the path between the currently active chain and the candidate are valid. // Just going until the active chain is an optimization, as we know all blocks in it are valid already. CBlockIndex *pindexTest = pindexNew; bool fInvalidAncestor = false; while (pindexTest && !chainActive.Contains(pindexTest)) { assert(pindexTest->nChainTx || pindexTest->nHeight == 0); - + // Pruned nodes may have entries in setBlockIndexCandidates for // which block files have been deleted. Remove those as candidates // for the most work chain if we come across them; we can't switch @@ -3046,7 +3316,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo bool fInvalidFound = false; const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); - + // - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks. // - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain, // then pindexFork will be null, and we would need to remove the entire chain including @@ -3055,23 +3325,23 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance"); if (reorgLength > MAX_REORG_LENGTH) { auto msg = strprintf(_( - "A block chain reorganization has been detected that would roll back %d blocks! " - "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." - ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + - _("Reorganization details") + ":\n" + - "- " + strprintf(_("Current tip: %s, height %d, work %s"), - pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + - "- " + strprintf(_("New tip: %s, height %d, work %s"), - pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + - "- " + strprintf(_("Fork point: %s, height %d"), - pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + - _("Please help, human!"); + "A block chain reorganization has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + + _("Reorganization details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d, work %s"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("New tip: %s, height %d, work %s"), + pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("Fork point: %s %s, height %d"), + ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + + _("Please help, human!"); LogPrintf("*** %s\n", msg); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; } - + // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; while (chainActive.Tip() && chainActive.Tip() != pindexFork) { @@ -3081,19 +3351,21 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } if ( KOMODO_REWIND != 0 ) { - fprintf(stderr,"rewind start ht.%d\n",chainActive.Tip()->nHeight); - while ( KOMODO_REWIND > 0 && chainActive.Tip()->nHeight > KOMODO_REWIND ) + CBlockIndex *tipindex; + fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND); + while ( KOMODO_REWIND > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > KOMODO_REWIND ) { + fBlocksDisconnected = true; + fprintf(stderr,"%d ",(int32_t)tipindex->nHeight); + InvalidateBlock(state,tipindex); if ( !DisconnectTip(state) ) - { - InvalidateBlock(state,chainActive.Tip()); break; - } } - fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND); - sleep(60); + fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli -ac_name=%s stop\n",KOMODO_REWIND,ASSETCHAINS_SYMBOL); + sleep(20); + fprintf(stderr,"resuming normal operations\n"); KOMODO_REWIND = 0; - return(true); + //return(true); } // Build list of new blocks to connect. std::vector vpindexToConnect; @@ -3111,7 +3383,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo pindexIter = pindexIter->pprev; } nHeight = nTargetHeight; - + // Connect new blocks. BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { @@ -3137,20 +3409,20 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } } } - + if (fBlocksDisconnected) { mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); } mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); mempool.check(pcoinsTip); - + // Callbacks/notifications for a new best chain. if (fInvalidFound) CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); else CheckForkWarningConditions(); - + return true; } @@ -3165,23 +3437,23 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) { const CChainParams& chainParams = Params(); do { boost::this_thread::interruption_point(); - + bool fInitialDownload; { LOCK(cs_main); pindexMostWork = FindMostWorkChain(); - + // Whether we have anything to do at all. if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; pindexNewTip = chainActive.Tip(); fInitialDownload = IsInitialBlockDownload(); } // When we reach this point, we switched to a new tip (stored in pindexNewTip). - + // Notifications/callbacks that can run without cs_main if (!fInitialDownload) { uint256 hashNewTip = pindexNewTip->GetBlockHash(); @@ -3194,8 +3466,8 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) { if (nLocalServices & NODE_NETWORK) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); + if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } // Notify external listeners about the new tip. GetMainSignals().UpdatedBlockTip(pindexNewTip); @@ -3203,23 +3475,23 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) { } //else fprintf(stderr,"initial download skips propagation\n"); } while(pindexMostWork != chainActive.Tip()); CheckBlockIndex(); - + // Write changes periodically to disk, after relay. if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { return false; } - + return true; } bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { AssertLockHeld(cs_main); - + // Mark the block itself as invalid. pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); - + while (chainActive.Contains(pindex)) { CBlockIndex *pindexWalk = chainActive.Tip(); pindexWalk->nStatus |= BLOCK_FAILED_CHILD; @@ -3230,12 +3502,12 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { if (!DisconnectTip(state)) { mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); return false; } } //LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); - + // The resulting new best tip may not be in setBlockIndexCandidates anymore, so // add it again. BlockMap::iterator it = mapBlockIndex.begin(); @@ -3245,19 +3517,19 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { } it++; } - + InvalidChainFound(pindex); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeWithoutBranchId( - CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); return true; } bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { AssertLockHeld(cs_main); - + int nHeight = pindex->nHeight; - + // Remove the invalidity flag from this block and all its descendants. BlockMap::iterator it = mapBlockIndex.begin(); while (it != mapBlockIndex.end()) { @@ -3274,7 +3546,7 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { } it++; } - + // Remove the invalidity flag from all ancestors too. while (pindex != NULL) { if (pindex->nStatus & BLOCK_FAILED_MASK) { @@ -3291,9 +3563,21 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) // Check for duplicate uint256 hash = block.GetHash(); BlockMap::iterator it = mapBlockIndex.find(hash); + BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (it != mapBlockIndex.end()) - return it->second; - + { + if ( it->second != 0 ) // vNodes.size() >= KOMODO_LIMITED_NETWORKSIZE, change behavior to allow komodo_ensure to work + { + // this is the strange case where somehow the hash is in the mapBlockIndex via as yet undetermined process, but the pindex for the hash is not there. Theoretically it is due to processing the block headers, but I have seen it get this case without having received it from the block headers or anywhere else... jl777 + //fprintf(stderr,"addtoblockindex already there %p\n",it->second); + return it->second; + } + if ( miPrev != mapBlockIndex.end() && (*miPrev).second == 0 ) + { + //fprintf(stderr,"edge case of both block and prevblock in the strange state\n"); + return(0); // return here to avoid the state of pindex->nHeight not set and pprev NULL + } + } // Construct new block index object CBlockIndex* pindexNew = new CBlockIndex(block); assert(pindexNew); @@ -3303,20 +3587,21 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) pindexNew->nSequenceId = 0; BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); - BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { - pindexNew->pprev = (*miPrev).second; - pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + if ( (pindexNew->pprev= (*miPrev).second) != 0 ) + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + else fprintf(stderr,"unexpected null pprev %s\n",hash.ToString().c_str()); pindexNew->BuildSkip(); } pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); pindexNew->RaiseValidity(BLOCK_VALID_TREE); if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) pindexBestHeader = pindexNew; - + setDirtyBlockIndex.insert(pindexNew); - + //fprintf(stderr,"added to block index %s %p\n",hash.ToString().c_str(),pindexNew); + mi->second = pindexNew; return pindexNew; } @@ -3340,12 +3625,12 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl pindexNew->nStatus |= BLOCK_HAVE_DATA; pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); setDirtyBlockIndex.insert(pindexNew); - + if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. deque queue; queue.push_back(pindexNew); - + // Recursively process any descendant blocks that now may be eligible to be connected. while (!queue.empty()) { CBlockIndex *pindex = queue.front(); @@ -3380,19 +3665,19 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew)); } } - + return true; } bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) { LOCK(cs_LastBlockFile); - + unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; if (vinfoBlockFile.size() <= nFile) { vinfoBlockFile.resize(nFile + 1); } - + if (!fKnown) { while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { nFile++; @@ -3403,7 +3688,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd pos.nFile = nFile; pos.nPos = vinfoBlockFile[nFile].nSize; } - + if (nFile != nLastBlockFile) { if (!fKnown) { LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); @@ -3411,13 +3696,13 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd FlushBlockFile(!fKnown); nLastBlockFile = nFile; } - + vinfoBlockFile[nFile].AddBlock(nHeight, nTime); if (fKnown) vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); else vinfoBlockFile[nFile].nSize += nAddSize; - + if (!fKnown) { unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; @@ -3436,7 +3721,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd return state.Error("out of disk space"); } } - + setDirtyFileInfo.insert(nFile); return true; } @@ -3444,14 +3729,14 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) { pos.nFile = nFile; - + LOCK(cs_LastBlockFile); - + unsigned int nNewSize; pos.nPos = vinfoBlockFile[nFile].nUndoSize; nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; setDirtyFileInfo.insert(nFile); - + unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; if (nNewChunks > nOldChunks) { @@ -3468,13 +3753,12 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne else return state.Error("out of disk space"); } - + return true; } -bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW) +bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW) { - uint8_t pubkey33[33]; // Check timestamp if ( 0 ) { @@ -3491,77 +3775,126 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl fprintf(stderr," <- chainTip\n"); } } + *futureblockp = 0; if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) - return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); + { + CBlockIndex *tipindex; + fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetAdjustedTime()); + if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetAdjustedTime() + 60 + 5 ) + { + //fprintf(stderr,"it is the next block, let's wait for %d seconds\n",GetAdjustedTime() + 60 - blockhdr.GetBlockTime()); + while ( blockhdr.GetBlockTime() > GetAdjustedTime() + 60 ) + sleep(1); + //fprintf(stderr,"now its valid\n"); + } + else + { + if (blockhdr.GetBlockTime() < GetAdjustedTime() + 600) + *futureblockp = 1; + LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetAdjustedTime()); + return false; //state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); + } + } + 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"); + } // Check block version - //if (block.nVersion < MIN_BLOCK_VERSION) - // return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low"); - - // Check Equihash solution is valid - if ( fCheckPOW && !CheckEquihashSolution(&blockhdr, Params()) ) - return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); + if (height > 0 && blockhdr.nVersion < MIN_BLOCK_VERSION) + return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low"); + // Check Equihash solution is valid + if ( fCheckPOW ) + { + if ( !CheckEquihashSolution(&blockhdr, Params()) ) + 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); - 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"); + /*komodo_index2pubkey33(pubkey33,pindex,height); + if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,blockhdr.GetHash(), blockhdr.nBits, Params().GetConsensus(),blockhdr.nTime) ) + return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),REJECT_INVALID, "high-hash");*/ return true; } -int32_t komodo_check_deposit(int32_t height,const CBlock& block); -bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, +int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime); +int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height); + +bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, libzcash::ProofVerifier& verifier, bool fCheckPOW, bool fCheckMerkleRoot) { + uint8_t pubkey33[33]; uint256 hash; // These are checks that are independent of context. - + hash = block.GetHash(); + // 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; - + if (!CheckBlockHeader(futureblockp,height,pindex,block,state,fCheckPOW)) + { + if ( *futureblockp == 0 ) + { + LogPrintf("CheckBlock header error"); + return false; + } + } + if ( fCheckPOW ) + { + //if ( !CheckEquihashSolution(&block, Params()) ) + // return state.DoS(100, error("CheckBlock: Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); + komodo_block2pubkey33(pubkey33,(CBlock *)&block); + if ( !CheckProofOfWork(height,pubkey33,hash,block.nBits,Params().GetConsensus(),block.nTime) ) + { + int32_t z; for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&hash)[z]); + fprintf(stderr," failed hash ht.%d\n",height); + return state.DoS(50, error("CheckBlock: proof of work failed"),REJECT_INVALID, "high-hash"); + } + if ( komodo_checkPOW(1,(CBlock *)&block,height) < 0 ) // checks Equihash + return state.DoS(100, error("CheckBlock: failed slow_checkPOW"),REJECT_INVALID, "failed-slow_checkPOW"); + } // Check the merkle root. if (fCheckMerkleRoot) { bool mutated; uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); if (block.hashMerkleRoot != hashMerkleRoot2) - return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"), + return state.DoS(100, error("CheckBlock: hashMerkleRoot mismatch"), REJECT_INVALID, "bad-txnmrklroot", true); - + // Check for merkle tree malleability (CVE-2012-2459): repeating sequences // of transactions in a block without affecting the merkle root of a block, // while still invalidating it. if (mutated) - return state.DoS(100, error("CheckBlock(): duplicate transaction"), + return state.DoS(100, error("CheckBlock: duplicate transaction"), REJECT_INVALID, "bad-txns-duplicate", true); } - + // All potential-corruption validation must be done before we do any // transaction validation, as otherwise we may mark the header as invalid // because we receive the wrong transactions for it. - + // Size limits if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, error("CheckBlock(): size limits failed"), + return state.DoS(100, error("CheckBlock: size limits failed"), REJECT_INVALID, "bad-blk-length"); - + // First transaction must be coinbase, the rest must not be - if (!block.vtx[0].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), + if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) + return state.DoS(100, error("CheckBlock: first tx is not coinbase"), REJECT_INVALID, "bad-cb-missing"); for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): more than one coinbase"), + return state.DoS(100, error("CheckBlock: more than one coinbase"), REJECT_INVALID, "bad-cb-multiple"); - + // Check transactions BOOST_FOREACH(const CTransaction& tx, block.vtx) { - if ( komodo_validate_interest(tx,height == 0 ? komodo_block2height((CBlock *)&block) : height,block.nTime,1) < 0 ) - return error("CheckBlock: komodo_validate_interest failed"); + if ( komodo_validate_interest(tx,height == 0 ? komodo_block2height((CBlock *)&block) : height,block.nTime,0) < 0 ) + return error("CheckBlock: komodo_validate_interest failed"); if (!CheckTransaction(tx, state, verifier)) - return error("CheckBlock(): CheckTransaction failed"); + return error("CheckBlock: CheckTransaction failed"); } unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -3569,13 +3902,14 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat nSigOps += GetLegacySigOpCount(tx); } if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), + 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(height,block,(pindex==0||pindex->pprev==0)?0:pindex->pprev->nTime) < 0 ) { - static uint32_t counter; - if ( counter++ < 100 ) - fprintf(stderr,"check deposit rejection\n"); + //static uint32_t counter; + //if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) + // fprintf(stderr,"check deposit rejection\n"); + LogPrintf("CheckBlockHeader komodo_check_deposit error"); return(false); } return true; @@ -3588,19 +3922,19 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta uint256 hash = block.GetHash(); if (hash == consensusParams.hashGenesisBlock) return true; - + assert(pindexPrev); - + int nHeight = pindexPrev->nHeight+1; - + // Check proof of work - if ( (ASSETCHAINS_SYMBOL[0] != 0 || (nHeight < 235300 || nHeight > 236000)) && block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + if ( (ASSETCHAINS_SYMBOL[0] != 0 || nHeight < 235300 || nHeight > 236000) && block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) { cout << block.nBits << " block.nBits vs. calc " << GetNextWorkRequired(pindexPrev, &block, consensusParams) << endl; return state.DoS(100, error("%s: incorrect proof of work", __func__), REJECT_INVALID, "bad-diffbits"); } - + // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) { @@ -3619,13 +3953,20 @@ 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)) + { + /*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; - if (pcheckpoint && (nHeight < pcheckpoint->nHeight || nHeight == 1 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight > 1) ) - return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d) vs %d", __func__, nHeight,pcheckpoint->nHeight)); + if (pcheckpoint && nHeight > 1 && nHeight < pcheckpoint->nHeight ) + return state.DoS(1, 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 ) { CBlockIndex *heightblock = chainActive[nHeight]; @@ -3633,14 +3974,14 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta { //fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight); return true; - } else return state.DoS(100, error("%s: forked chain %d older than last notarized (height %d) vs %d", __func__,nHeight, notarized_height)); + } else return state.DoS(1, error("%s: forked chain %d older than last notarized (height %d) vs %d", __func__,nHeight, notarized_height)); } } // Reject block.nVersion < 4 blocks if (block.nVersion < 4) return state.Invalid(error("%s : rejected nVersion<4 block", __func__), REJECT_OBSOLETE, "bad-version"); - + return true; } @@ -3648,24 +3989,24 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; const Consensus::Params& consensusParams = Params().GetConsensus(); - + // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, block.vtx) { - + // Check transaction contextually against consensus rules at block height if (!ContextualCheckTransaction(tx, state, nHeight, 100)) { return false; // Failure reason has been set in validation state object } - + int nLockTimeFlags = 0; int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) - ? pindexPrev->GetMedianTimePast() - : block.GetBlockTime(); + ? pindexPrev->GetMedianTimePast() + : block.GetBlockTime(); if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } } - + // Enforce BIP 34 rule that the coinbase starts with serialized block height. // In Zcash this has been enforced since launch, except that the genesis // block didn't include the height in the coinbase (see Zcash protocol spec @@ -3678,99 +4019,130 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); } } - + return true; } -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) +//static uint256 komodo_requestedhash; +//static int32_t komodo_requestedcount; + +bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) { + static uint256 zero; const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); + // Check for duplicate uint256 hash = block.GetHash(); BlockMap::iterator miSelf = mapBlockIndex.find(hash); CBlockIndex *pindex = NULL; - if (miSelf != mapBlockIndex.end()) { + if (miSelf != mapBlockIndex.end()) + { // Block header is already known. - pindex = miSelf->second; + if ( (pindex= miSelf->second) == 0 ) + miSelf->second = pindex = AddToBlockIndex(block); if (ppindex) *ppindex = pindex; - if (pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK) + if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK ) return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); - if ( pindex != 0 && IsInitialBlockDownload() == 0 ) // jl777 debug test + /*if ( pindex != 0 && hash == komodo_requestedhash ) { - if (!CheckBlockHeader(pindex->nHeight,pindex, block, state)) - { - pindex->nStatus |= BLOCK_FAILED_MASK; - fprintf(stderr,"known block failing CheckBlockHeader %d\n",(int32_t)pindex->nHeight); - return false; - } - CBlockIndex* pindexPrev = NULL; - if (hash != chainparams.GetConsensus().hashGenesisBlock) - { - BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); - if (mi == mapBlockIndex.end()) - { - pindex->nStatus |= BLOCK_FAILED_MASK; - fprintf(stderr,"known block.%d failing to find prevblock\n",(int32_t)pindex->nHeight); - return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); - } - pindexPrev = (*mi).second; - if (pindexPrev == 0 || (pindexPrev->nStatus & BLOCK_FAILED_MASK) ) - { - pindex->nStatus |= BLOCK_FAILED_MASK; - fprintf(stderr,"known block.%d found invalid prevblock\n",(int32_t)pindex->nHeight); - return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); - } - } - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) - { - pindex->nStatus |= BLOCK_FAILED_MASK; - fprintf(stderr,"known block.%d failing ContextualCheckBlockHeader\n",(int32_t)pindex->nHeight); - return false; - } - } - + fprintf(stderr,"AddToBlockIndex A komodo_requestedhash %s\n",komodo_requestedhash.ToString().c_str()); + memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); + komodo_requestedcount = 0; + }*/ + + //if ( pindex == 0 ) + // fprintf(stderr,"accepthdr %s already known but no pindex\n",hash.ToString().c_str()); return true; } - - if (!CheckBlockHeader(*ppindex!=0?(*ppindex)->nHeight:0,*ppindex, block, state)) - return false; - + if (!CheckBlockHeader(futureblockp,*ppindex!=0?(*ppindex)->nHeight:0,*ppindex, block, state,0)) + { + if ( *futureblockp == 0 ) + { + LogPrintf("AcceptBlockHeader CheckBlockHeader error\n"); + return false; + } + } // Get prev block index CBlockIndex* pindexPrev = NULL; - if (hash != chainparams.GetConsensus().hashGenesisBlock) { + if (hash != chainparams.GetConsensus().hashGenesisBlock) + { BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) { - return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); + //fprintf(stderr,"AcceptBlockHeader hashPrevBlock %s not found\n",block.hashPrevBlock.ToString().c_str()); + /*if ( komodo_requestedhash == zero ) + { + komodo_requestedhash = block.hashPrevBlock; + komodo_requestedcount = 0; + }*/ + LogPrintf("AcceptBlockHeader hashPrevBlock %s not found\n",block.hashPrevBlock.ToString().c_str()); + return(false); + //return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); } pindexPrev = (*mi).second; - if (pindexPrev == 0 || (pindexPrev->nStatus & BLOCK_FAILED_MASK) ) + if (pindexPrev == 0 ) + { + /*fprintf(stderr,"AcceptBlockHeader failed no pindexPrev %s\n",block.hashPrevBlock.ToString().c_str()); + if ( komodo_requestedhash == zero ) + { + komodo_requestedhash = block.hashPrevBlock; + komodo_requestedcount = 0; + }*/ + LogPrintf("AcceptBlockHeader hashPrevBlock %s no pindexPrev\n",block.hashPrevBlock.ToString().c_str()); + return(false); + } + if ( (pindexPrev->nStatus & BLOCK_FAILED_MASK) ) return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); } if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + { + //fprintf(stderr,"AcceptBlockHeader ContextualCheckBlockHeader failed\n"); + LogPrintf("AcceptBlockHeader ContextualCheckBlockHeader failed\n"); return false; + } if (pindex == NULL) - pindex = AddToBlockIndex(block); + { + if ( (pindex= AddToBlockIndex(block)) != 0 ) + { + miSelf = mapBlockIndex.find(hash); + if (miSelf != mapBlockIndex.end()) + miSelf->second = pindex; + //fprintf(stderr,"AcceptBlockHeader couldnt add to block index\n"); + } + } if (ppindex) *ppindex = pindex; + /*if ( pindex != 0 && hash == komodo_requestedhash ) + { + fprintf(stderr,"AddToBlockIndex komodo_requestedhash %s\n",komodo_requestedhash.ToString().c_str()); + memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); + komodo_requestedcount = 0; + }*/ return true; } -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) { const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); - + CBlockIndex *&pindex = *ppindex; - if (!AcceptBlockHeader(block, state, &pindex)) - return false; + if (!AcceptBlockHeader(futureblockp,block, state, &pindex)) + { + if ( *futureblockp == 0 ) + { + LogPrintf("AcceptBlock AcceptBlockHeader error\n"); + return false; + } + } if ( pindex == 0 ) { - fprintf(stderr,"AcceptBlock error null pindex\n"); + LogPrintf("AcceptBlock null pindex error\n"); return false; } + //fprintf(stderr,"acceptblockheader passed\n"); // Try to process all requested blocks that we don't have, but only // process an unrequested block if it's new and has enough work to // advance our tip, and isn't too many blocks ahead. @@ -3781,29 +4153,35 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // blocks which are too close in height to the tip. Apply this test // regardless of whether pruning is enabled; it should generally be safe to // not process unrequested blocks. - bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); - + bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + BLOCK_DOWNLOAD_WINDOW)); //MIN_BLOCKS_TO_KEEP)); + // TODO: deal better with return value and error conditions for duplicate // and unrequested blocks. + //fprintf(stderr,"Accept %s flags already.%d requested.%d morework.%d farahead.%d\n",pindex->GetBlockHash().ToString().c_str(),fAlreadyHave,fRequested,fHasMoreWork,fTooFarAhead); if (fAlreadyHave) return true; if (!fRequested) { // If we didn't ask for it: if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned if (!fHasMoreWork) return true; // Don't process less-work chains if (fTooFarAhead) return true; // Block height is too high } - + // See method docstring for why this is always disabled auto verifier = libzcash::ProofVerifier::Disabled(); - if ((!CheckBlock(pindex->nHeight,pindex,block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) { - if (state.IsInvalid() && !state.CorruptionPossible()) { - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); + if ((!CheckBlock(futureblockp,pindex->nHeight,pindex,block, state, verifier,0)) || !ContextualCheckBlock(block, state, pindex->pprev)) + { + if ( *futureblockp == 0 ) + { + if (state.IsInvalid() && !state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + } + LogPrintf("AcceptBlock CheckBlock or ContextualCheckBlock error\n"); + return false; } - return false; } - + int nHeight = pindex->nHeight; - + // Write block to history file try { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -3820,11 +4198,13 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } catch (const std::runtime_error& e) { return AbortNode(state, std::string("System error: ") + e.what()); } - + if (fCheckForPruning) FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files - - return true; + if ( *futureblockp == 0 ) + return true; + LogPrintf("AcceptBlock block from future error\n"); + return false; } static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) @@ -3841,40 +4221,133 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned void komodo_currentheight_set(int32_t height); -bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) +CBlockIndex *komodo_ensure(CBlock *pblock,uint256 hash) +{ + CBlockIndex *pindex = 0; + BlockMap::iterator miSelf = mapBlockIndex.find(hash); + if ( miSelf != mapBlockIndex.end() ) + { + if ( (pindex= miSelf->second) == 0 ) // create pindex so first Accept block doesnt fail + { + miSelf->second = AddToBlockIndex(*pblock); + //fprintf(stderr,"Block header %s is already known, but without pindex -> ensured %p\n",hash.ToString().c_str(),miSelf->second); + } + /*if ( hash != Params().GetConsensus().hashGenesisBlock ) + { + miSelf = mapBlockIndex.find(pblock->hashPrevBlock); + if ( miSelf != mapBlockIndex.end() ) + { + if ( miSelf->second == 0 ) + { + miSelf->second = InsertBlockIndex(pblock->hashPrevBlock); + fprintf(stderr,"autocreate previndex %s\n",pblock->hashPrevBlock.ToString().c_str()); + } + } + }*/ + } + return(pindex); +} + +CBlockIndex *oldkomodo_ensure(CBlock *pblock,uint256 hash) +{ + CBlockIndex *pindex=0,*previndex=0; + if ( (pindex= mapBlockIndex[hash]) == 0 ) + { + pindex = new CBlockIndex(); + if (!pindex) + throw runtime_error("komodo_ensure: new CBlockIndex failed"); + BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindex)).first; + pindex->phashBlock = &((*mi).first); + } + BlockMap::iterator miSelf = mapBlockIndex.find(hash); + if ( miSelf == mapBlockIndex.end() ) + { + LogPrintf("komodo_ensure unexpected missing hash %s\n",hash.ToString().c_str()); + return(0); + } + if ( miSelf->second == 0 ) // create pindex so first Accept block doesnt fail + { + if ( pindex == 0 ) + { + pindex = AddToBlockIndex(*pblock); + fprintf(stderr,"ensure call addtoblockindex, got %p\n",pindex); + } + if ( pindex != 0 ) + { + miSelf->second = pindex; + LogPrintf("Block header %s is already known, but without pindex -> ensured %p\n",hash.ToString().c_str(),miSelf->second); + } else LogPrintf("komodo_ensure unexpected null pindex\n"); + } + /*if ( hash != Params().GetConsensus().hashGenesisBlock ) + { + miSelf = mapBlockIndex.find(pblock->hashPrevBlock); + if ( miSelf == mapBlockIndex.end() ) + previndex = InsertBlockIndex(pblock->hashPrevBlock); + if ( (miSelf= mapBlockIndex.find(pblock->hashPrevBlock)) != mapBlockIndex.end() ) + { + if ( miSelf->second == 0 ) // create pindex so first Accept block doesnt fail + { + if ( previndex == 0 ) + previndex = InsertBlockIndex(pblock->hashPrevBlock); + if ( previndex != 0 ) + { + miSelf->second = previndex; + LogPrintf("autocreate previndex %s\n",pblock->hashPrevBlock.ToString().c_str()); + } else LogPrintf("komodo_ensure unexpected null previndex\n"); + } + } else LogPrintf("komodo_ensure unexpected null miprev\n"); + } + }*/ + return(pindex); +} + +bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) { // Preliminary checks - bool checked; + bool checked; uint256 hash; int32_t futureblock=0; auto verifier = libzcash::ProofVerifier::Disabled(); + hash = pblock->GetHash(); +//fprintf(stderr,"process newblock %s\n",hash.ToString().c_str()); if ( chainActive.Tip() != 0 ) komodo_currentheight_set(chainActive.Tip()->nHeight); - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier); - else checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier); + checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0); { LOCK(cs_main); - bool fRequested = MarkBlockAsReceived(pblock->GetHash()); + bool fRequested = MarkBlockAsReceived(hash); fRequested |= fForceProcessing; - if (!checked) { + if ( checked != 0 && komodo_checkPOW(from_miner && ASSETCHAINS_STAKED == 0,pblock,height) < 0 ) + { + checked = 0; + fprintf(stderr,"passed checkblock but failed checkPOW.%d\n",from_miner && ASSETCHAINS_STAKED == 0); + } + if (!checked && futureblock == 0) + { if ( pfrom != 0 ) + { Misbehaving(pfrom->GetId(), 1); + } return error("%s: CheckBlock FAILED", __func__); } - // Store to disk CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp); + if ( 1 ) + { + // without the komodo_ensure call, it is quite possible to get a non-error but null pindex returned from AcceptBlockHeader. In a 2 node network, it will be a long time before that block is reprocessed. Even though restarting makes it rescan, it seems much better to keep the nodes in sync + komodo_ensure(pblock,hash); + } + bool ret = AcceptBlock(&futureblock,*pblock, state, &pindex, fRequested, dbp); if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } CheckBlockIndex(); - if (!ret) + if (!ret && futureblock == 0) return error("%s: AcceptBlock FAILED", __func__); + //else fprintf(stderr,"added block %s %p\n",pindex->GetBlockHash().ToString().c_str(),pindex->pprev); } - - if (!ActivateBestChain(state, pblock)) + + if (futureblock == 0 && !ActivateBestChain(state, pblock)) return error("%s: ActivateBestChain failed", __func__); - + return true; } @@ -3882,37 +4355,38 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex { AssertLockHeld(cs_main); assert(pindexPrev == chainActive.Tip()); - + CCoinsViewCache viewNew(pcoinsTip); CBlockIndex indexDummy(block); indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; // JoinSplit proofs are verified in ConnectBlock auto verifier = libzcash::ProofVerifier::Disabled(); - // NOTE: CheckBlockHeader is called by CheckBlock if (!ContextualCheckBlockHeader(block, state, pindexPrev)) { - fprintf(stderr,"TestBlockValidity failure A\n"); + //fprintf(stderr,"TestBlockValidity failure A checkPOW.%d\n",fCheckPOW); return false; } - if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot)) + int32_t futureblock; + if (!CheckBlock(&futureblock,indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot)) { - //fprintf(stderr,"TestBlockValidity failure B\n"); + //fprintf(stderr,"TestBlockValidity failure B checkPOW.%d\n",fCheckPOW); return false; } if (!ContextualCheckBlock(block, state, pindexPrev)) { - fprintf(stderr,"TestBlockValidity failure C\n"); + //fprintf(stderr,"TestBlockValidity failure C checkPOW.%d\n",fCheckPOW); return false; } - if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) + if (!ConnectBlock(block, state, &indexDummy, viewNew, true,fCheckPOW)) { - fprintf(stderr,"TestBlockValidity failure D\n"); + //fprintf(stderr,"TestBlockValidity failure D checkPOW.%d\n",fCheckPOW); return false; } assert(state.IsValid()); - + if ( futureblock != 0 ) + return(false); return true; } @@ -3942,7 +4416,7 @@ void PruneOneBlockFile(const int fileNumber) pindex->nDataPos = 0; pindex->nUndoPos = 0; setDirtyBlockIndex.insert(pindex); - + // Prune from mapBlocksUnlinked -- any block we prune would have // to be downloaded again in order to consider its chain, at which // point it would be considered as a candidate for @@ -3957,7 +4431,7 @@ void PruneOneBlockFile(const int fileNumber) } } } - + vinfoBlockFile[fileNumber].SetNull(); setDirtyFileInfo.insert(fileNumber); } @@ -3983,7 +4457,6 @@ void FindFilesToPrune(std::set& setFilesToPrune) if (chainActive.Tip()->nHeight <= Params().PruneAfterHeight()) { return; } - unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP; uint64_t nCurrentUsage = CalculateCurrentUsage(); // We don't check to prune until after we've allocated new space for files @@ -3992,21 +4465,21 @@ void FindFilesToPrune(std::set& setFilesToPrune) uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; uint64_t nBytesToPrune; int count=0; - + if (nCurrentUsage + nBuffer >= nPruneTarget) { for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; - + if (vinfoBlockFile[fileNumber].nSize == 0) continue; - + if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target? break; - + // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) continue; - + PruneOneBlockFile(fileNumber); // Queue up the files for removal setFilesToPrune.insert(fileNumber); @@ -4014,26 +4487,27 @@ void FindFilesToPrune(std::set& setFilesToPrune) count++; } } - + LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", - nPruneTarget/1024/1024, nCurrentUsage/1024/1024, - ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, - nLastBlockWeCanPrune, count); + nPruneTarget/1024/1024, nCurrentUsage/1024/1024, + ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, + nLastBlockWeCanPrune, count); } bool CheckDiskSpace(uint64_t nAdditionalBytes) { uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; - + // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) return AbortNode("Disk space is low!", _("Error: Disk space is low!")); - + return true; } FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) { + static int32_t didinit[64]; if (pos.IsNull()) return NULL; boost::filesystem::path path = GetBlockPosFilename(pos, prefix); @@ -4045,6 +4519,11 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) LogPrintf("Unable to open file %s\n", path.string()); return NULL; } + if ( pos.nFile < sizeof(didinit)/sizeof(*didinit) && didinit[pos.nFile] == 0 && strcmp(prefix,(char *)"blk") == 0 ) + { + komodo_prefetch(file); + didinit[pos.nFile] = 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()); @@ -4072,30 +4551,34 @@ CBlockIndex * InsertBlockIndex(uint256 hash) { if (hash.IsNull()) return NULL; - + // Return existing BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) return (*mi).second; - + // Create new CBlockIndex* pindexNew = new CBlockIndex(); if (!pindexNew) throw runtime_error("LoadBlockIndex(): new CBlockIndex failed"); mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); + //fprintf(stderr,"inserted to block index %s\n",hash.ToString().c_str()); return pindexNew; } +//void komodo_pindex_init(CBlockIndex *pindex,int32_t height); + bool static LoadBlockIndexDB() { const CChainParams& chainparams = Params(); + LogPrintf("%s: start loading guts\n", __func__); if (!pblocktree->LoadBlockIndexGuts()) return false; - + LogPrintf("%s: loaded guts\n", __func__); boost::this_thread::interruption_point(); - + // Calculate nChainWork vector > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); @@ -4103,8 +4586,11 @@ bool static LoadBlockIndexDB() { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); + //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); } + //fprintf(stderr,"load blockindexDB paired %u\n",(uint32_t)time(NULL)); sort(vSortedByHeight.begin(), vSortedByHeight.end()); + //fprintf(stderr,"load blockindexDB sorted %u\n",(uint32_t)time(NULL)); BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; @@ -4151,7 +4637,9 @@ bool static LoadBlockIndexDB() pindex->BuildSkip(); if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) pindexBestHeader = pindex; + //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); } + //fprintf(stderr,"load blockindexDB chained %u\n",(uint32_t)time(NULL)); // Load block file info pblocktree->ReadLastBlockFile(nLastBlockFile); @@ -4169,7 +4657,7 @@ bool static LoadBlockIndexDB() break; } } - + // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); set setBlkDataFiles; @@ -4179,7 +4667,9 @@ bool static LoadBlockIndexDB() if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); } + //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); } + //fprintf(stderr,"load blockindexDB %u\n",(uint32_t)time(NULL)); for (std::set::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) { CDiskBlockPos pos(*it, 0); @@ -4187,20 +4677,31 @@ bool static LoadBlockIndexDB() return false; } } - + // Check whether we have ever pruned block & undo files pblocktree->ReadFlag("prunedblockfiles", fHavePruned); if (fHavePruned) LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); - + // Check whether we need to continue reindexing bool fReindexing = false; pblocktree->ReadReindexing(fReindexing); fReindex |= fReindexing; - + // Check whether we have a transaction index pblocktree->ReadFlag("txindex", fTxIndex); LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); + // Check whether we have an address index + pblocktree->ReadFlag("addressindex", fAddressIndex); + LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); + + // Check whether we have a timestamp index + pblocktree->ReadFlag("timestampindex", fTimestampIndex); + LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled"); + + // Check whether we have a spent index + pblocktree->ReadFlag("spentindex", fSpentIndex); + LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled"); // Fill in-memory data BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) @@ -4214,8 +4715,9 @@ bool static LoadBlockIndexDB() if (pindex->pprev) { pindex->pprev->hashAnchorEnd = pindex->hashAnchor; } + //komodo_pindex_init(pindex,(int32_t)pindex->nHeight); } - + // Load pointer to end of best chain BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); if (it == mapBlockIndex.end()) @@ -4223,16 +4725,16 @@ bool static LoadBlockIndexDB() chainActive.SetTip(it->second); // Set hashAnchorEnd for the end of best chain it->second->hashAnchorEnd = pcoinsTip->GetBestAnchor(); - + PruneBlockIndexCandidates(); - + LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); - + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); + EnforceNodeDeprecation(chainActive.Height(), true); - + return true; } @@ -4251,7 +4753,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) return true; - + // Verify blocks in the best chain if (nCheckDepth <= 0) nCheckDepth = 1000000000; // suffices until the year 19000 @@ -4266,6 +4768,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth CValidationState state; // No need to verify JoinSplits twice auto verifier = libzcash::ProofVerifier::Disabled(); + //fprintf(stderr,"start VerifyDB %u\n",(uint32_t)time(NULL)); for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); @@ -4274,10 +4777,11 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth break; CBlock block; // check level 0: read from disk - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex,0)) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity - if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state, verifier)) + int32_t futureblock; + if (nCheckLevel >= 1 && !CheckBlock(&futureblock,pindex->nHeight,pindex,block, state, verifier,0) ) return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { @@ -4303,9 +4807,10 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth if (ShutdownRequested()) return true; } + //fprintf(stderr,"end VerifyDB %u\n",(uint32_t)time(NULL)); if (pindexFailure) return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); - + // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { CBlockIndex *pindex = pindexState; @@ -4314,22 +4819,22 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); pindex = chainActive.Next(pindex); CBlock block; - if (!ReadBlockFromDisk(block, pindex)) + if (!ReadBlockFromDisk(block, pindex,0)) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins,false, true)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } - + LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); - + return true; } bool RewindBlockIndex(const CChainParams& params) { LOCK(cs_main); - + // RewindBlockIndex is called after LoadBlockIndex, so at this point every block // index will have nCachedBranchId set based on the values previously persisted // to disk. By definition, a set nCachedBranchId means that the block was @@ -4344,10 +4849,10 @@ bool RewindBlockIndex(const CChainParams& params) bool fFlagSet = pindex->nStatus & BLOCK_ACTIVATES_UPGRADE; bool fFlagExpected = IsActivationHeightForAnyUpgrade(pindex->nHeight, consensus); return fFlagSet == fFlagExpected && - pindex->nCachedBranchId && - *pindex->nCachedBranchId == CurrentEpochBranchId(pindex->nHeight, consensus); + pindex->nCachedBranchId && + *pindex->nCachedBranchId == CurrentEpochBranchId(pindex->nHeight, consensus); }; - + int nHeight = 1; while (nHeight <= chainActive.Height()) { if (!sufficientlyValidated(chainActive[nHeight])) { @@ -4355,28 +4860,28 @@ bool RewindBlockIndex(const CChainParams& params) } nHeight++; } - + // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 auto rewindLength = chainActive.Height() - nHeight; if (rewindLength > 0 && rewindLength > MAX_REORG_LENGTH) { auto pindexOldTip = chainActive.Tip(); auto pindexRewind = chainActive[nHeight - 1]; auto msg = strprintf(_( - "A block chain rewind has been detected that would roll back %d blocks! " - "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." - ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + - _("Rewind details") + ":\n" + - "- " + strprintf(_("Current tip: %s, height %d"), - pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + - "- " + strprintf(_("Rewinding to: %s, height %d"), - pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + - _("Please help, human!"); + "A block chain rewind has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + + _("Rewind details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + + "- " + strprintf(_("Rewinding to: %s, height %d"), + pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + + _("Please help, human!"); LogPrintf("*** %s\n", msg); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; } - + CValidationState state; CBlockIndex* pindex = chainActive.Tip(); while (chainActive.Height() >= nHeight) { @@ -4395,13 +4900,13 @@ bool RewindBlockIndex(const CChainParams& params) if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) return false; } - + // Reduce validity flag and have-data flags. // We do this after actual disconnecting, otherwise we'll end up writing the lack of data // to disk before writing the chainstate, resulting in a failure to continue if interrupted. for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { CBlockIndex* pindexIter = it->second; - + // Note: If we encounter an insufficiently validated block that // is on chainActive, it must be because we are a pruning node, and // this block or some successor doesn't HAVE_DATA, so we were unable to @@ -4410,8 +4915,8 @@ bool RewindBlockIndex(const CChainParams& params) if (!sufficientlyValidated(pindexIter) && !chainActive.Contains(pindexIter)) { // Reduce validity pindexIter->nStatus = - std::min(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | - (pindexIter->nStatus & ~BLOCK_VALID_MASK); + std::min(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | + (pindexIter->nStatus & ~BLOCK_VALID_MASK); // Remove have-data flags pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO); // Remove branch ID @@ -4429,6 +4934,12 @@ bool RewindBlockIndex(const CChainParams& params) pindexIter->nSequenceId = 0; // Make sure it gets written setDirtyBlockIndex.insert(pindexIter); + if (pindexIter == pindexBestInvalid) + { + //fprintf(stderr,"Reset invalid block marker if it was pointing to this block\n"); + pindexBestInvalid = NULL; + } + // Update indices setBlockIndexCandidates.erase(pindexIter); auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev); @@ -4443,15 +4954,15 @@ bool RewindBlockIndex(const CChainParams& params) setBlockIndexCandidates.insert(pindexIter); } } - + PruneBlockIndexCandidates(); - + CheckBlockIndex(); - + if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) { return false; } - + return true; } @@ -4478,7 +4989,7 @@ void UnloadBlockIndex() setDirtyFileInfo.clear(); mapNodeState.clear(); recentRejects.reset(NULL); - + BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { delete entry.second; } @@ -4488,7 +4999,6 @@ void UnloadBlockIndex() bool LoadBlockIndex() { - extern int32_t KOMODO_LOADINGBLOCKS; // Load block index from databases KOMODO_LOADINGBLOCKS = 1; if (!fReindex && !LoadBlockIndexDB()) @@ -4496,7 +5006,6 @@ bool LoadBlockIndex() KOMODO_LOADINGBLOCKS = 0; return false; } - KOMODO_LOADINGBLOCKS = 0; fprintf(stderr,"finished loading blocks %s\n",ASSETCHAINS_SYMBOL); return true; } @@ -4505,19 +5014,29 @@ bool LoadBlockIndex() bool InitBlockIndex() { const CChainParams& chainparams = Params(); LOCK(cs_main); - + // Initialize global variables that cannot be constructed at startup. recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); - + // Check whether we're already initialized if (chainActive.Genesis() != NULL) return true; - + // Use the provided setting for -txindex in the new database fTxIndex = GetBoolArg("-txindex", true); pblocktree->WriteFlag("txindex", fTxIndex); - LogPrintf("Initializing databases...\n"); + // Use the provided setting for -addressindex in the new database + fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX); + pblocktree->WriteFlag("addressindex", fAddressIndex); + // Use the provided setting for -timestampindex in the new database + fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX); + pblocktree->WriteFlag("timestampindex", fTimestampIndex); + + fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX); + pblocktree->WriteFlag("spentindex", fSpentIndex); + LogPrintf("Initializing databases...\n"); + // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) if (!fReindex) { try { @@ -4531,6 +5050,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)) @@ -4541,7 +5062,7 @@ bool InitBlockIndex() { return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); } } - + return true; } @@ -4553,15 +5074,16 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); - + int nLoaded = 0; try { // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor - CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + //CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + CBufferedFile blkdat(fileIn, 32*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); uint64_t nRewind = blkdat.GetPos(); while (!blkdat.eof()) { boost::this_thread::interruption_point(); - + blkdat.SetPos(nRewind); nRewind++; // start one byte further next time, in case of failure blkdat.SetLimit(); // remove former limit @@ -4592,28 +5114,28 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) CBlock block; blkdat >> block; nRewind = blkdat.GetPos(); - + // detect out of order blocks, and store them for later uint256 hash = block.GetHash(); if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), - block.hashPrevBlock.ToString()); + block.hashPrevBlock.ToString()); if (dbp) mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); continue; } - + // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (ProcessNewBlock(0,state, NULL, &block, true, dbp)) + if (ProcessNewBlock(0,0,state, NULL, &block, true, dbp)) nLoaded++; if (state.IsError()) break; } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } - + // Recursively process earlier encountered successors of this block deque queue; queue.push_back(hash); @@ -4623,12 +5145,12 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); while (range.first != range.second) { std::multimap::iterator it = range.first; - if (ReadBlockFromDisk(mapBlockIndex[hash]!=0?mapBlockIndex[hash]->nHeight:0,block, it->second)) + if (ReadBlockFromDisk(mapBlockIndex[hash]!=0?mapBlockIndex[hash]->nHeight:0,block, it->second,1)) { LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), - head.ToString()); + head.ToString()); CValidationState dummy; - if (ProcessNewBlock(0,dummy, NULL, &block, true, &it->second)) + if (ProcessNewBlock(0,0,dummy, NULL, &block, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -4656,9 +5178,9 @@ void static CheckBlockIndex() if (!fCheckBlockIndex) { return; } - + LOCK(cs_main); - + // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when // iterating the block tree require that chainActive has been initialized.) @@ -4666,20 +5188,20 @@ void static CheckBlockIndex() assert(mapBlockIndex.size() <= 1); return; } - + // Build forward-pointing map of the entire block tree. std::multimap forward; for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { - forward.insert(std::make_pair(it->second->pprev, it->second)); + forward.insert(std::make_pair(it->second->pprev, it->second)); } - + assert(forward.size() == mapBlockIndex.size()); - + std::pair::iterator,std::multimap::iterator> rangeGenesis = forward.equal_range(NULL); CBlockIndex *pindex = rangeGenesis.first->second; rangeGenesis.first++; assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL. - + // Iterate over the entire block tree, using depth-first search. // Along the way, remember whether there are blocks on the path from genesis // block being explored which are the first to have certain properties. @@ -4701,7 +5223,7 @@ void static CheckBlockIndex() if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex; if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex; if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex; - + // Begin: actual consistency checks. if (pindex->pprev == NULL) { // Genesis block checks. @@ -4787,7 +5309,7 @@ void static CheckBlockIndex() } // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow // End: actual consistency checks. - + // Try descending into the first subnode. std::pair::iterator,std::multimap::iterator> range = forward.equal_range(pindex); if (range.first != range.second) { @@ -4830,7 +5352,7 @@ void static CheckBlockIndex() } } } - + // Check that we actually traversed the entire map. assert(nNodes == forward.size()); } @@ -4845,20 +5367,20 @@ std::string GetWarnings(const std::string& strFor) int nPriority = 0; string strStatusBar; string strRPC; - + if (!CLIENT_VERSION_IS_RELEASE) strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); - + if (GetBoolArg("-testsafemode", false)) strStatusBar = strRPC = "testsafemode enabled"; - + // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { nPriority = 1000; strStatusBar = strMiscWarning; } - + if (fLargeWorkForkFound) { nPriority = 2000; @@ -4869,7 +5391,7 @@ std::string GetWarnings(const std::string& strFor) nPriority = 2000; strStatusBar = strRPC = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } - + // Alerts { LOCK(cs_mapAlerts); @@ -4886,7 +5408,7 @@ std::string GetWarnings(const std::string& strFor) } } } - + if (strFor == "statusbar") return strStatusBar; else if (strFor == "rpc") @@ -4912,7 +5434,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { switch (inv.type) { - case MSG_TX: + case MSG_TX: { assert(recentRejects); if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) @@ -4924,14 +5446,14 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); recentRejects->reset(); } - + return recentRejects->contains(inv.hash) || - mempool.exists(inv.hash) || - mapOrphanTransactions.count(inv.hash) || - pcoinsTip->HaveCoins(inv.hash); + mempool.exists(inv.hash) || + mapOrphanTransactions.count(inv.hash) || + pcoinsTip->HaveCoins(inv.hash); } - case MSG_BLOCK: - return mapBlockIndex.count(inv.hash); + case MSG_BLOCK: + return mapBlockIndex.count(inv.hash); } // Don't know what it is, just say we already got one return true; @@ -4940,21 +5462,21 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) void static ProcessGetData(CNode* pfrom) { std::deque::iterator it = pfrom->vRecvGetData.begin(); - + vector vNotFound; - + LOCK(cs_main); - + while (it != pfrom->vRecvGetData.end()) { // Don't bother if send buffer is too full to respond anyway if (pfrom->nSendSize >= SendBufferSize()) break; - + const CInv &inv = *it; { boost::this_thread::interruption_point(); it++; - + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) { bool send = false; @@ -4969,8 +5491,8 @@ void static ProcessGetData(CNode* pfrom) // chain if they are valid, and no more than a month older (both in time, and in // best equivalent proof of work) than the best header chain we know about. send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && - (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); + (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } @@ -4982,7 +5504,7 @@ void static ProcessGetData(CNode* pfrom) { // Send block from disk CBlock block; - if (!ReadBlockFromDisk(block, (*mi).second)) + if (!ReadBlockFromDisk(block, (*mi).second,1)) { assert(!"cannot load block from disk"); } @@ -5058,17 +5580,17 @@ void static ProcessGetData(CNode* pfrom) vNotFound.push_back(inv); } } - + // Track requests for our stuff. GetMainSignals().Inventory(inv.hash); - + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) break; } } - + pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it); - + if (!vNotFound.empty()) { // Let the peer know that we didn't find what it asked for, so it doesn't // have to wait around forever. Currently only SPV clients actually care @@ -5091,10 +5613,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); return true; } - - - - + + + + if (strCommand == "version") { // Each connection can only send one version message @@ -5104,7 +5626,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 1); return false; } - + int64_t nTime; CAddress addrMe; CAddress addrFrom; @@ -5119,7 +5641,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fDisconnect = true; return false; } - + // When Overwinter is active, reject incoming connections from non-Overwinter nodes const Consensus::Params& params = Params().GetConsensus(); if (NetworkUpgradeActive(GetHeight(), params, Consensus::UPGRADE_OVERWINTER) @@ -5127,12 +5649,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", - params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); + strprintf("Version must be %d or greater", + params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); pfrom->fDisconnect = true; return false; } - + if (pfrom->nVersion == 10300) pfrom->nVersion = 300; if (!vRecv.empty()) @@ -5147,7 +5669,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message else pfrom->fRelayTxes = true; - + // Disconnect if we connected to ourself if (nNonce == nLocalHostNonce && nNonce > 1) { @@ -5155,26 +5677,26 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fDisconnect = true; return true; } - + pfrom->addrLocal = addrMe; if (pfrom->fInbound && addrMe.IsRoutable()) { SeenLocal(addrMe); } - + // Be shy and don't send version until we hear if (pfrom->fInbound) pfrom->PushVersion(); - + pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); - + // Potentially mark this peer as a preferred download peer. UpdatePreferredDownload(pfrom, State(pfrom->GetId())); - + // Change version pfrom->PushMessage("verack"); pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); - + if (!pfrom->fInbound) { // Advertise our address @@ -5191,7 +5713,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushAddress(addr); } } - + // Get recent addresses if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) { @@ -5206,72 +5728,72 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, addrman.Good(addrFrom); } } - + // Relay alerts { LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - item.second.RelayTo(pfrom); + item.second.RelayTo(pfrom); } - + pfrom->fSuccessfullyConnected = true; - + string remoteAddr; if (fLogIPs) remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); - + LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", pfrom->cleanSubVer, pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, remoteAddr); - + int64_t nTimeOffset = nTime - GetTime(); pfrom->nTimeOffset = nTimeOffset; AddTimeData(pfrom->addr, nTimeOffset); } - - + + else if (pfrom->nVersion == 0) { // Must have a version message before anything else Misbehaving(pfrom->GetId(), 1); return false; } - - + + else if (strCommand == "verack") { pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); - + // Mark this node as currently connected, so we update its timestamp later. if (pfrom->fNetworkNode) { LOCK(cs_main); State(pfrom->GetId())->fCurrentlyConnected = true; } } - - + + // Disconnect existing peer connection when: // 1. The version message has been received // 2. Overwinter is active // 3. Peer version is pre-Overwinter else if (NetworkUpgradeActive(GetHeight(), chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER) - && (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)) + && (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)) { LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", - chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); + strprintf("Version must be %d or greater", + chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); pfrom->fDisconnect = true; return false; } - - + + else if (strCommand == "addr") { vector vAddr; vRecv >> vAddr; - + // Don't want addr from older versions unless seeding if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) return true; @@ -5280,7 +5802,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("message addr size() = %u", vAddr.size()); } - + // Store the new addresses vector vAddrOk; int64_t nNow = GetAdjustedTime(); @@ -5288,7 +5810,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, BOOST_FOREACH(CAddress& addr, vAddr) { boost::this_thread::interruption_point(); - + if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) addr.nTime = nNow - 5 * 24 * 60 * 60; pfrom->AddAddressKnown(addr); @@ -5332,8 +5854,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pfrom->fOneShot) pfrom->fDisconnect = true; } - - + + else if (strCommand == "inv") { vector vInv; @@ -5343,24 +5865,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("message inv size() = %u", vInv.size()); } - + LOCK(cs_main); - + std::vector vToFetch; - + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { const CInv &inv = vInv[nInv]; - + boost::this_thread::interruption_point(); pfrom->AddInventoryKnown(inv); - + bool fAlreadyHave = AlreadyHave(inv); LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); - + if (!fAlreadyHave && !fImporting && !fReindex && inv.type != MSG_BLOCK) pfrom->AskFor(inv); - + if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { @@ -5384,21 +5906,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } - + // Track requests for our stuff GetMainSignals().Inventory(inv.hash); - + if (pfrom->nSendSize > (SendBufferSize() * 2)) { Misbehaving(pfrom->GetId(), 50); return error("send buffer size() = %u", pfrom->nSendSize); } } - + if (!vToFetch.empty()) pfrom->PushMessage("getdata", vToFetch); } - - + + else if (strCommand == "getdata") { vector vInv; @@ -5408,29 +5930,29 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("message getdata size() = %u", vInv.size()); } - + if (fDebug || (vInv.size() != 1)) LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id); - + if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); - + pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); ProcessGetData(pfrom); } - - + + else if (strCommand == "getblocks") { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; - + LOCK(cs_main); - + // Find the last block the caller has in the main chain CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); - + // Send the rest of the chain if (pindex) pindex = chainActive.Next(pindex); @@ -5454,19 +5976,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } } - - + + else if (strCommand == "getheaders") { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; - + LOCK(cs_main); - + if (IsInitialBlockDownload()) return true; - + CBlockIndex* pindex = NULL; if (locator.IsNull()) { @@ -5483,12 +6005,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pindex) pindex = chainActive.Next(pindex); } - + // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector vHeaders; int nLimit = MAX_HEADERS_RESULTS; LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); - if ( pfrom->lasthdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pfrom->lasthdrsreq != (int32_t)(pindex ? pindex->nHeight : -1) ) + //if ( pfrom->lasthdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pfrom->lasthdrsreq != (int32_t)(pindex ? pindex->nHeight : -1) )// no need to ever suppress this { pfrom->lasthdrsreq = (int32_t)(pindex ? pindex->nHeight : -1); for (; pindex; pindex = chainActive.Next(pindex)) @@ -5499,44 +6021,44 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } pfrom->PushMessage("headers", vHeaders); } - else if ( NOTARY_PUBKEY33[0] != 0 ) + /*else if ( NOTARY_PUBKEY33[0] != 0 ) { static uint32_t counter; if ( counter++ < 3 ) fprintf(stderr,"you can ignore redundant getheaders from peer.%d %d prev.%d\n",(int32_t)pfrom->id,(int32_t)(pindex ? pindex->nHeight : -1),pfrom->lasthdrsreq); - } + }*/ } - - + + else if (strCommand == "tx") { vector vWorkQueue; vector vEraseQueue; CTransaction tx; vRecv >> tx; - + CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); - + LOCK(cs_main); - + bool fMissingInputs = false; CValidationState state; - + pfrom->setAskFor.erase(inv.hash); mapAlreadyAskedFor.erase(inv); - + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { 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()); - + 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++) @@ -5556,8 +6078,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // 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)) @@ -5587,15 +6109,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mempool.check(pcoinsTip); } } - + BOOST_FOREACH(uint256 hash, vEraseQueue) - EraseOrphanTx(hash); + EraseOrphanTx(hash); } // TODO: currently, prohibit joinsplits from entering mapOrphans else if (fMissingInputs && tx.vjoinsplit.size() == 0) { AddOrphanTx(tx, pfrom->GetId()); - + // DoS prevention: do not allow mapOrphanTransactions to grow unbounded unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); @@ -5604,7 +6126,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } else { assert(recentRejects); recentRejects->insert(tx.GetHash()); - + if (pfrom->fWhitelisted) { // Always relay transactions received from whitelisted peers, even // if they were already in the mempool or rejected from it due @@ -5620,7 +6142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, RelayTransaction(tx); } else { LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s (code %d))\n", - tx.GetHash().ToString(), pfrom->id, state.GetRejectReason(), state.GetRejectCode()); + tx.GetHash().ToString(), pfrom->id, state.GetRejectReason(), state.GetRejectCode()); } } } @@ -5628,20 +6150,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (state.IsInvalid(nDoS)) { LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), - pfrom->id, pfrom->cleanSubVer, - state.GetRejectReason()); + pfrom->id, pfrom->cleanSubVer, + state.GetRejectReason()); pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } } - - + + else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing { std::vector headers; - + // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. unsigned int nCount = ReadCompactSize(vRecv); if (nCount > MAX_HEADERS_RESULTS) { @@ -5653,14 +6175,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> headers[n]; ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } - + LOCK(cs_main); - + if (nCount == 0) { // Nothing interesting. Stop asking this peers for more headers. return true; } - + CBlockIndex *pindexLast = NULL; BOOST_FOREACH(const CBlockHeader& header, headers) { CValidationState state; @@ -5668,19 +6190,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - if (!AcceptBlockHeader(header, state, &pindexLast)) { + int32_t futureblock; + //fprintf(stderr,"headers msg nCount.%d\n",(int32_t)nCount); + if (!AcceptBlockHeader(&futureblock,header, state, &pindexLast)) { int nDoS; - if (state.IsInvalid(nDoS)) { - if (nDoS > 0) + if (state.IsInvalid(nDoS)) + { + if (nDoS > 0 && futureblock == 0) Misbehaving(pfrom->GetId(), nDoS/nDoS); return error("invalid header received"); } } } - + if (pindexLast) UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); - + if (nCount == MAX_HEADERS_RESULTS && pindexLast) { // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue @@ -5692,27 +6217,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256()); } } - + CheckBlockIndex(); } - + else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing { CBlock block; vRecv >> block; - + CInv inv(MSG_BLOCK, block.GetHash()); LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id); - + pfrom->AddInventoryKnown(inv); - + CValidationState state; // Process all blocks from whitelisted peers, even if not requested, // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(0,state, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(0,0,state, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), @@ -5722,10 +6247,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), nDoS); } } - + } - - + + // This asymmetric behavior for inbound and outbound connections was introduced // to prevent a fingerprinting attack: an attacker can send specific fake addresses // to users' AddrMan and later request them by sending getaddr messages. @@ -5740,18 +6265,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } pfrom->fSentAddr = true; - + pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); BOOST_FOREACH(const CAddress &addr, vAddr) - pfrom->PushAddress(addr); + pfrom->PushAddress(addr); } - - + + else if (strCommand == "mempool") { LOCK2(cs_main, pfrom->cs_filter); - + std::vector vtxid; mempool.queryHashes(vtxid); vector vInv; @@ -5761,7 +6286,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool fInMemPool = mempool.lookup(hash, tx); if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) || - (!pfrom->pfilter)) + (!pfrom->pfilter)) vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { pfrom->PushMessage("inv", vInv); @@ -5771,8 +6296,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (vInv.size() > 0) pfrom->PushMessage("inv", vInv); } - - + + else if (strCommand == "ping") { if (pfrom->nVersion > BIP0031_VERSION) @@ -5793,8 +6318,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->PushMessage("pong", nonce); } } - - + + else if (strCommand == "pong") { int64_t pingUsecEnd = nTimeReceived; @@ -5802,10 +6327,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, size_t nAvail = vRecv.in_avail(); bool bPingFinished = false; std::string sProblem; - + if (nAvail >= sizeof(nonce)) { vRecv >> nonce; - + // Only process pong message if there is an outstanding ping (old ping without nonce should never pong) if (pfrom->nPingNonceSent != 0) { if (nonce == pfrom->nPingNonceSent) { @@ -5837,27 +6362,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bPingFinished = true; sProblem = "Short payload"; } - + if (!(sProblem.empty())) { LogPrint("net", "pong peer=%d %s: %s, %x expected, %x received, %u bytes\n", - pfrom->id, - pfrom->cleanSubVer, - sProblem, - pfrom->nPingNonceSent, - nonce, - nAvail); + pfrom->id, + pfrom->cleanSubVer, + sProblem, + pfrom->nPingNonceSent, + nonce, + nAvail); } if (bPingFinished) { pfrom->nPingNonceSent = 0; } } - - + + else if (fAlerts && strCommand == "alert") { CAlert alert; vRecv >> alert; - + uint256 alertHash = alert.GetHash(); if (pfrom->setKnown.count(alertHash) == 0) { @@ -5868,7 +6393,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) - alert.RelayTo(pnode); + alert.RelayTo(pnode); } } else { @@ -5882,13 +6407,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } } - - + + else if (strCommand == "filterload") { CBloomFilter filter; vRecv >> filter; - + if (!filter.IsWithinSizeConstraints()) // There is no excuse for sending a too-large filter Misbehaving(pfrom->GetId(), 100); @@ -5901,13 +6426,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } pfrom->fRelayTxes = true; } - - + + else if (strCommand == "filteradd") { vector vData; vRecv >> vData; - + // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, // and thus, the maximum size any matched object can have) in a filteradd message if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) @@ -5921,8 +6446,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 100); } } - - + + else if (strCommand == "filterclear") { LOCK(pfrom->cs_filter); @@ -5930,18 +6455,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->pfilter = new CBloomFilter(); pfrom->fRelayTxes = true; } - - + + else if (strCommand == "reject") { if (fDebug) { try { string strMsg; unsigned char ccode; string strReason; vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); - + ostringstream ss; ss << strMsg << " code " << itostr(ccode) << ": " << strReason; - + if (strMsg == "block" || strMsg == "tx") { uint256 hash; @@ -5959,14 +6484,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // We do not care about the NOTFOUND message, but logging an Unknown Command // message would be undesirable as we transmit it ourselves. } - + else { // Ignore unknown commands for extensibility LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); } - - - + + + return true; } @@ -5975,7 +6500,7 @@ bool ProcessMessages(CNode* pfrom) { //if (fDebug) // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); - + // // Message format // (4) message start @@ -5985,41 +6510,41 @@ bool ProcessMessages(CNode* pfrom) // (x) data // bool fOk = true; - + if (!pfrom->vRecvGetData.empty()) ProcessGetData(pfrom); - + // this maintains the order of responses if (!pfrom->vRecvGetData.empty()) return fOk; - + std::deque::iterator it = pfrom->vRecvMsg.begin(); while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { // Don't bother if send buffer is too full to respond anyway if (pfrom->nSendSize >= SendBufferSize()) break; - + // get next message CNetMessage& msg = *it; - + //if (fDebug) // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__, // msg.hdr.nMessageSize, msg.vRecv.size(), // msg.complete() ? "Y" : "N"); - + // end, if an incomplete message is found if (!msg.complete()) break; - + // at this point, any failure means we can delete the current message it++; - + // Scan for message start if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) { LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); fOk = false; break; } - + // Read header CMessageHeader& hdr = msg.hdr; if (!hdr.IsValid(Params().MessageStart())) @@ -6028,10 +6553,10 @@ bool ProcessMessages(CNode* pfrom) continue; } string strCommand = hdr.GetCommand(); - + // Message size unsigned int nMessageSize = hdr.nMessageSize; - + // Checksum CDataStream& vRecv = msg.vRecv; uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); @@ -6039,10 +6564,10 @@ bool ProcessMessages(CNode* pfrom) if (nChecksum != hdr.nChecksum) { LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__, - SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); + SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); continue; } - + // Process message bool fRet = false; try @@ -6076,17 +6601,17 @@ bool ProcessMessages(CNode* pfrom) } catch (...) { PrintExceptionContinue(NULL, "ProcessMessages()"); } - + if (!fRet) LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); - + break; } - + // In case the connection got shut down, its receive buffer was wiped if (!pfrom->fDisconnect) pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it); - + return fOk; } @@ -6098,7 +6623,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Don't send anything until we get its version message if (pto->nVersion == 0) return true; - + // // Message: ping // @@ -6127,11 +6652,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("ping"); } } - + TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState() if (!lockMain) return true; - + // Address refresh broadcast static int64_t nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) @@ -6142,14 +6667,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Periodically clear addrKnown to allow refresh broadcasts if (nLastRebroadcast) pnode->addrKnown.reset(); - + // Rebroadcast our address AdvertizeLocal(pnode); } if (!vNodes.empty()) nLastRebroadcast = GetTime(); } - + // // Message: addr // @@ -6175,7 +6700,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (!vAddr.empty()) pto->PushMessage("addr", vAddr); } - + CNodeState &state = *State(pto->GetId()); if (state.fShouldBan) { if (pto->fWhitelisted) @@ -6191,11 +6716,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } state.fShouldBan = false; } - + BOOST_FOREACH(const CBlockReject& reject, state.rejects) - pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); + pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); state.rejects.clear(); - + // Start block sync if (pindexBestHeader == NULL) pindexBestHeader = chainActive.Tip(); @@ -6210,7 +6735,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256()); } } - + // Resend wallet transactions that haven't gotten in a block yet // Except during reindex, importing and IBD, when old wallet // transactions become unconfirmed and spams other nodes. @@ -6218,7 +6743,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) { GetMainSignals().Broadcast(nTimeBestReceived); } - + // // Message: inventory // @@ -6232,7 +6757,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) { if (pto->setInventoryKnown.count(inv)) continue; - + // trickle out tx inv to protect privacy if (inv.type == MSG_TX && !fSendTrickle) { @@ -6243,14 +6768,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle) uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt)); hashRand = Hash(BEGIN(hashRand), END(hashRand)); bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0); - + if (fTrickleWait) { vInvWait.push_back(inv); continue; } } - + // returns true if wasn't already contained in the set if (pto->setInventoryKnown.insert(inv).second) { @@ -6266,7 +6791,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } if (!vInv.empty()) pto->PushMessage("inv", vInv); - + // Detect whether we're stalling int64_t nNow = GetTimeMicros(); if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { @@ -6298,10 +6823,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->fDisconnect = true; } } - + // // Message: getdata (blocks) // + static uint256 zero; vector vGetData; if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vector vToDownload; @@ -6311,7 +6837,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), - pindex->nHeight, pto->id); + pindex->nHeight, pto->id); } if (state.nBlocksInFlight == 0 && staller != -1) { if (State(staller)->nStallingSince == 0) { @@ -6320,7 +6846,21 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } } } - + /*CBlockIndex *pindex; + if ( komodo_requestedhash != zero && komodo_requestedcount < 16 && (pindex= mapBlockIndex[komodo_requestedhash]) != 0 ) + { + LogPrint("net","komodo_requestedhash.%d request %s to nodeid.%d\n",komodo_requestedcount,komodo_requestedhash.ToString().c_str(),pto->GetId()); + fprintf(stderr,"komodo_requestedhash.%d request %s to nodeid.%d\n",komodo_requestedcount,komodo_requestedhash.ToString().c_str(),pto->GetId()); + vGetData.push_back(CInv(MSG_BLOCK, komodo_requestedhash)); + MarkBlockAsInFlight(pto->GetId(), komodo_requestedhash, consensusParams, pindex); + komodo_requestedcount++; + if ( komodo_requestedcount > 16 ) + { + memset(&komodo_requestedhash,0,sizeof(komodo_requestedhash)); + komodo_requestedcount = 0; + } + }*/ + // // Message: getdata (non-blocks) // @@ -6345,14 +6885,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } if (!vGetData.empty()) pto->PushMessage("getdata", vGetData); - + } return true; } - std::string CBlockFileInfo::ToString() const { - return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); - } +std::string CBlockFileInfo::ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); +} @@ -6366,7 +6906,7 @@ public: for (; it1 != mapBlockIndex.end(); it1++) delete (*it1).second; mapBlockIndex.clear(); - + // orphan transactions mapOrphanTransactions.clear(); mapOrphanTransactionsByPrev.clear(); @@ -6375,7 +6915,7 @@ public: extern "C" const char* getDataDir() { - return GetDataDir().string().c_str(); + return GetDataDir().string().c_str(); } @@ -6383,14 +6923,14 @@ extern "C" const char* getDataDir() CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight) { CMutableTransaction mtx; - + bool isOverwintered = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_OVERWINTER); if (isOverwintered) { mtx.fOverwintered = true; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nVersion = 3; // Expiry height is not set. Only fields required for a parser to treat as a valid Overwinter V3 tx. - + // TODO: In future, when moving from Overwinter to Sapling, it will be useful // to set the expiry height to: min(activation_height - 1, default_expiry_height) } diff --git a/src/main.h b/src/main.h index 66c43655c..3a43b5fba 100644 --- a/src/main.h +++ b/src/main.h @@ -20,9 +20,10 @@ #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 "script/script_ext.h" +#include "spentindex.h" #include "sync.h" #include "tinyformat.h" #include "txmempool.h" @@ -102,6 +103,12 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; /** Maximum length of reject messages. */ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; +static const bool DEFAULT_ADDRESSINDEX = false; +static const bool DEFAULT_TIMESTAMPINDEX = false; +static const bool DEFAULT_SPENTINDEX = false; +static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000; +static const bool DEFAULT_DB_COMPRESSION = true; + // Sanity check the magic numbers when we change them BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE); BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE); @@ -184,7 +191,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. * @return True if state.IsValid() */ -bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); +bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -269,6 +276,338 @@ struct CNodeStateStats { std::vector vHeightInFlight; }; +struct CTimestampIndexIteratorKey { + unsigned int timestamp; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata32be(s, timestamp); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + timestamp = ser_readdata32be(s); + } + + CTimestampIndexIteratorKey(unsigned int time) { + timestamp = time; + } + + CTimestampIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + } +}; + +struct CTimestampIndexKey { + unsigned int timestamp; + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 36; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata32be(s, timestamp); + blockHash.Serialize(s, nType, nVersion); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + timestamp = ser_readdata32be(s); + blockHash.Unserialize(s, nType, nVersion); + } + + CTimestampIndexKey(unsigned int time, uint256 hash) { + timestamp = time; + blockHash = hash; + } + + CTimestampIndexKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexKey { + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 32; + } + + template + void Serialize(Stream& s, int nType, int nVersion) const { + blockHash.Serialize(s, nType, nVersion); + } + + template + void Unserialize(Stream& s, int nType, int nVersion) { + blockHash.Unserialize(s, nType, nVersion); + } + + CTimestampBlockIndexKey(uint256 hash) { + blockHash = hash; + } + + CTimestampBlockIndexKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + } +}; + +struct CTimestampBlockIndexValue { + unsigned int ltimestamp; + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata32be(s, ltimestamp); + } + + template + void Unserialize(Stream& s, int nType, int nVersion) { + ltimestamp = ser_readdata32be(s); + } + + CTimestampBlockIndexValue (unsigned int time) { + ltimestamp = time; + } + + CTimestampBlockIndexValue() { + SetNull(); + } + + void SetNull() { + ltimestamp = 0; + } +}; + +struct CAddressUnspentKey { + unsigned int type; + uint160 hashBytes; + uint256 txhash; + size_t index; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 57; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + txhash.Serialize(s, nType, nVersion); + ser_writedata32(s, index); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + txhash.Unserialize(s, nType, nVersion); + index = ser_readdata32(s); + } + + CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) { + type = addressType; + hashBytes = addressHash; + txhash = txid; + index = indexValue; + } + + CAddressUnspentKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + txhash.SetNull(); + index = 0; + } +}; + +struct CAddressUnspentValue { + CAmount satoshis; + CScript script; + int blockHeight; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(satoshis); + READWRITE(script); + READWRITE(blockHeight); + } + + CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) { + satoshis = sats; + script = scriptPubKey; + blockHeight = height; + } + + CAddressUnspentValue() { + SetNull(); + } + + void SetNull() { + satoshis = -1; + script.clear(); + blockHeight = 0; + } + + bool IsNull() const { + return (satoshis == -1); + } +}; + +struct CAddressIndexKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + unsigned int txindex; + uint256 txhash; + size_t index; + bool spending; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 66; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + // Heights are stored big-endian for key sorting in LevelDB + ser_writedata32be(s, blockHeight); + ser_writedata32be(s, txindex); + txhash.Serialize(s, nType, nVersion); + ser_writedata32(s, index); + char f = spending; + ser_writedata8(s, f); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + blockHeight = ser_readdata32be(s); + txindex = ser_readdata32be(s); + txhash.Unserialize(s, nType, nVersion); + index = ser_readdata32(s); + char f = ser_readdata8(s); + spending = f; + } + + CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex, + uint256 txid, size_t indexValue, bool isSpending) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + txindex = blockindex; + txhash = txid; + index = indexValue; + spending = isSpending; + } + + CAddressIndexKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + txindex = 0; + txhash.SetNull(); + index = 0; + spending = false; + } + +}; + +struct CAddressIndexIteratorKey { + unsigned int type; + uint160 hashBytes; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 21; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + } + + CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) { + type = addressType; + hashBytes = addressHash; + } + + CAddressIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + } +}; + +struct CAddressIndexIteratorHeightKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 25; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + ser_writedata32be(s, blockHeight); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + blockHeight = ser_readdata32be(s); + } + + CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + } + + CAddressIndexIteratorHeightKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + } +}; + struct CDiskTxPos : public CDiskBlockPos { unsigned int nTxOffset; // after header @@ -432,11 +771,18 @@ public: ScriptError GetScriptError() const { return error; } }; +bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, const bool fActiveOnly, std::vector > &hashes); +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start = 0, int end = 0); +bool GetAddressUnspent(uint160 addressHash, int type, + std::vector > &unspentOutputs); /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos,bool checkPOW); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW); /** Functions for validating blocks and updating the block tree */ @@ -448,11 +794,11 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); /** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false,bool fCheckPOW = false); /** Context-independent validity checks */ -bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); -bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, +bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); +bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, libzcash::ProofVerifier& verifier, bool fCheckPOW = true, bool fCheckMerkleRoot = true); @@ -470,8 +816,8 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere. * If dbp is non-NULL, the file is known to already reside on disk */ -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); -bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); +bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); +bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); diff --git a/src/miner.cpp b/src/miner.cpp index 1839f6102..92a4ed80c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -65,7 +65,7 @@ public: set setDependsOn; CFeeRate feeRate; double dPriority; - + COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) { } @@ -79,10 +79,10 @@ typedef boost::tuple TxPriority; class TxPriorityCompare { bool byFee; - + public: TxPriorityCompare(bool _byFee) : byFee(_byFee) { } - + bool operator()(const TxPriority& a, const TxPriority& b) { if (byFee) @@ -102,13 +102,13 @@ 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" 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 uint64_t ASSETCHAINS_COMMISSION; +extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED; extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[]; extern const char *ASSETCHAINS_ALGORITHMS[]; extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[]; @@ -118,17 +118,19 @@ extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33]; uint32_t Mining_start,Mining_height; int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize); -uint64_t komodo_paxtotal(); +//uint64_t komodo_paxtotal(); int32_t komodo_baseid(char *origbase); -int32_t komodo_is_issuer(); -int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t tokomodo); -int32_t komodo_isrealtime(int32_t *kmdheightp); +//int32_t komodo_is_issuer(); +//int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t tokomodo); +//int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); int64_t komodo_block_unlocktime(uint32_t nHeight); +uint64_t komodo_commission(const CBlock *block); +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) { - 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()) @@ -137,7 +139,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return NULL; } CBlock *pblock = &pblocktemplate->block; // pointer for convenience - if ( ASSETCHAINS_SYMBOL[0] != 0 && komodo_baseid(ASSETCHAINS_SYMBOL) >= 0 && chainActive.Tip()->nHeight >= ASSETCHAINS_MINHEIGHT ) + /*if ( ASSETCHAINS_SYMBOL[0] != 0 && komodo_baseid(ASSETCHAINS_SYMBOL) >= 0 && chainActive.Tip()->nHeight >= ASSETCHAINS_MINHEIGHT ) { isrealtime = komodo_isrealtime(&kmdheight); deposits = komodo_paxtotal(); @@ -158,35 +160,35 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) KOMODO_ON_DEMAND = 0; if ( 0 && deposits != 0 ) printf("miner KOMODO_DEPOSIT %llu pblock->nHeight %d mempool.GetTotalTxSize(%d)\n",(long long)komodo_paxtotal(),(int32_t)chainActive.Tip()->nHeight,(int32_t)mempool.GetTotalTxSize()); - } + }*/ // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - + // Add dummy coinbase tx as first transaction pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end - + // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - + // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); - + // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - + // Collect memory pool transactions into the block CAmount nFees = 0; - + { LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); @@ -209,13 +211,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->nTime = GetAdjustedTime(); CCoinsViewCache view(pcoinsTip); - uint32_t expired; + uint32_t expired; uint64_t commission; // Priority order to process transactions list vOrphan; // list memory doesn't move map > mapDependers; bool fPrintPriority = GetBoolArg("-printpriority", false); - + // This vector will be sorted into a priority queue: vector vecPriority; vecPriority.reserve(mempool.mapTx.size()); @@ -223,16 +225,19 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->GetTx(); - + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) - ? nMedianTimePast - : pblock->GetBlockTime(); - + ? nMedianTimePast + : pblock->GetBlockTime(); + if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight)) - continue; - if ( komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,2) < 0 ) { - fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure\n"); + //fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight)); + continue; + } + if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 ) + { + //fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime); continue; } COrphan* porphan = NULL; @@ -256,7 +261,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) vOrphan.pop_back(); break; } - + // Has to wait for dependencies if (!porphan) { @@ -271,27 +276,27 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); - + CAmount nValueIn = coins->vout[txin.prevout.n].nValue; nTotalIn += nValueIn; - + int nConf = nHeight - coins->nHeight; - + dPriority += (double)nValueIn * nConf; } nTotalIn += tx.GetJoinSplitValueIn(); - + if (fMissingInputs) continue; - + // Priority is sum(valuein * age) / modified_txsize unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority = tx.ComputePriority(dPriority, nTxSize); - + uint256 hash = tx.GetHash(); mempool.ApplyDeltas(hash, dPriority, nTotalIn); - + CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); - + if (porphan) { porphan->dPriority = dPriority; @@ -300,45 +305,52 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) else vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx()))); } - + // Collect transactions into block uint64_t nBlockSize = 1000; uint64_t nBlockTx = 0; int64_t interest; int nBlockSigOps = 100; bool fSortedByFee = (nBlockPrioritySize <= 0); - + TxPriorityCompare comparer(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); - + while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); CFeeRate feeRate = vecPriority.front().get<1>(); const CTransaction& tx = *(vecPriority.front().get<2>()); - + std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); vecPriority.pop_back(); - + // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) + { + //fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize); continue; - + } + // Legacy limits on sigOps: unsigned int nTxSigOps = GetLegacySigOpCount(tx); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) + { + //fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS); continue; - + } // Skip free transactions if we're past the minimum block size: const uint256& hash = tx.GetHash(); double dPriorityDelta = 0; CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + { + //fprintf(stderr,"fee rate skip\n"); continue; - + } // Prioritise by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && @@ -348,26 +360,32 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) comparer = TxPriorityCompare(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); } - + if (!view.HaveInputs(tx)) + { + //fprintf(stderr,"dont have inputs\n"); continue; - + } 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) + { + //fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS); continue; - + } // Note that flags: we don't want to set mempool/IsStandard() // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; PrecomputedTransactionData txdata(tx); if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) + { + //fprintf(stderr,"context failure\n"); continue; - + } UpdateCoins(tx, view, nHeight); - + // Added pblock->vtx.push_back(tx); pblocktemplate->vTxFees.push_back(nTxFees); @@ -376,12 +394,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) ++nBlockTx; nBlockSigOps += nTxSigOps; nFees += nTxFees; - + if (fPrintPriority) { LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString()); } - + // Add transactions that depend on this one to the priority queue if (mapDependers.count(hash)) { @@ -399,11 +417,41 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } } } - + nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); - + blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + //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 ) + { + 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); + //if ( blocktime > pindexPrev->GetMedianTimePast()+60 ) + // blocktime = pindexPrev->GetMedianTimePast() + 60; + if ( (siglen= komodo_staked(txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) + { + CAmount txfees = 0; + pblock->vtx.push_back(txStaked); + pblocktemplate->vTxFees.push_back(txfees); + pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); + nFees += txfees; + pblock->nTime = blocktime; + if ( GetAdjustedTime() < pblock->nTime )//|| pblock->GetBlockTime() > GetAdjustedTime() + 60) + { + fprintf(stderr,"need to wait %d seconds to mine:\n",(int32_t)(pblock->nTime - GetAdjustedTime())); + while ( GetAdjustedTime()+30 < pblock->nTime ) + { + sleep(30); + fprintf(stderr,"%d ",(int32_t)(pblock->nTime - GetAdjustedTime())); + } + fprintf(stderr,"finished waiting\n"); + //sleep(pblock->nTime - GetAdjustedTime()); + } + } else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); + } + // Create coinbase tx CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); txNew.vin.resize(1); @@ -414,6 +462,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus()) + nFees; txNew.nExpiryHeight = 0; + txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); // check if coinbase transactions must be time locked at current subsidy and prepend the time lock // to transaction if so, cast for GTE operator @@ -433,104 +482,107 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript)); txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK); txNew.vout[1].nValue = 0; + } // timelocks and commissions are currently incompatible due to validation complexity of the combination + else if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&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"); } - /*if ( ASSETCHAINS_SYMBOL[0] == 0 ) - { - int32_t i,opretlen; uint8_t opret[256],*ptr; - if ( (nHeight % 60) == 0 || komodo_gateway_deposits(&txNew,(char *)"KMD",1) == 0 ) - { - if ( (opretlen= komodo_pax_opreturn((int32_t)nHeight,opret,sizeof(opret))) > 0 ) // have pricefeed - { - txNew.vout.resize(2); - txNew.vout[1].scriptPubKey.resize(opretlen); - ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); - for (i=0; i 1 ) - fprintf(stderr,"%s txNew numvouts.%d\n",ASSETCHAINS_SYMBOL,(int32_t)txNew.vout.size()); - }*/ - pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; + // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); + // Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters) nonce <<= ASSETCHAINS_NONCESHIFT[ASSETCHAINS_ALGO]; nonce >>= 16; pblock->nNonce = ArithToUint256(nonce); - + // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashReserved = uint256(); - //UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + if ( ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || NOTARY_PUBKEY33[0] == 0 ) + { + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + } pblock->nSolution.clear(); pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - - CValidationState state; - if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) + if ( ASSETCHAINS_SYMBOL[0] == 0 && NOTARY_PUBKEY33[0] != 0 && pblock->nTime < pindexPrev->nTime+60 ) { - static uint32_t counter; - if ( counter++ < 100 ) - fprintf(stderr,"warning: testblockvalidity failed\n"); - return(0); + pblock->nTime = pindexPrev->nTime + 60; + //while ( pblock->GetBlockTime() > GetAdjustedTime() + 10 ) + // sleep(1); + //fprintf(stderr,"block.nTime %u vs prev.%u, gettime.%u vs adjusted.%u\n",(uint32_t)pblock->nTime,(uint32_t)(pindexPrev->nTime + 60),(uint32_t)pblock->GetBlockTime(),(uint32_t)(GetAdjustedTime() + 60)); + } + else + { + CValidationState state; + if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) + { + //static uint32_t counter; + //if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) + // fprintf(stderr,"warning: miner testblockvalidity failed\n"); + return(0); + } } } - + return pblocktemplate.release(); } - + /* -#ifdef ENABLE_WALLET -boost::optional GetMinerScriptPubKey(CReserveKey& reservekey) -#else -boost::optional GetMinerScriptPubKey() -#endif -{ - CKeyID keyID; - CBitcoinAddress addr; - if (addr.SetString(GetArg("-mineraddress", ""))) { - addr.GetKeyID(keyID); - } else { -#ifdef ENABLE_WALLET - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) { - return boost::optional(); - } - keyID = pubkey.GetID(); -#else - return boost::optional(); -#endif - } - - CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; - return scriptPubKey; -} - -#ifdef ENABLE_WALLET -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - boost::optional scriptPubKey = GetMinerScriptPubKey(reservekey); -#else -CBlockTemplate* CreateNewBlockWithKey() -{ - boost::optional scriptPubKey = GetMinerScriptPubKey(); -#endif - - if (!scriptPubKey) { - return NULL; - } - return CreateNewBlock(*scriptPubKey); -}*/ + #ifdef ENABLE_WALLET + boost::optional GetMinerScriptPubKey(CReserveKey& reservekey) + #else + boost::optional GetMinerScriptPubKey() + #endif + { + CKeyID keyID; + CBitcoinAddress addr; + if (addr.SetString(GetArg("-mineraddress", ""))) { + addr.GetKeyID(keyID); + } else { + #ifdef ENABLE_WALLET + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) { + return boost::optional(); + } + keyID = pubkey.GetID(); + #else + return boost::optional(); + #endif + } + + CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; + return scriptPubKey; + } + + #ifdef ENABLE_WALLET + CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) + { + boost::optional scriptPubKey = GetMinerScriptPubKey(reservekey); + #else + CBlockTemplate* CreateNewBlockWithKey() + { + boost::optional scriptPubKey = GetMinerScriptPubKey(); + #endif + + if (!scriptPubKey) { + return NULL; + } + return CreateNewBlock(*scriptPubKey); + }*/ ////////////////////////////////////////////////////////////////////////////// // @@ -553,7 +605,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); - + pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } @@ -590,6 +642,26 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) return CreateNewBlock(scriptPubKey); } +void komodo_broadcast(CBlock *pblock,int32_t limit) +{ + int32_t n = 1; + //fprintf(stderr,"broadcast new block t.%u\n",(uint32_t)time(NULL)); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if ( pnode->hSocket == INVALID_SOCKET ) + continue; + if ( (rand() % n) == 0 ) + { + pnode->PushMessage("block", *pblock); + if ( n++ > limit ) + break; + } + } + } + //fprintf(stderr,"finished broadcast new block t.%u\n",(uint32_t)time(NULL)); +} static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) #else @@ -598,7 +670,7 @@ static bool ProcessBlockFound(CBlock* pblock) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue),chainActive.Tip()->nHeight+1); - + // Found a solution { LOCK(cs_main); @@ -613,11 +685,11 @@ static bool ProcessBlockFound(CBlock* pblock) for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); fprintf(stderr," <- chainTip (stale)\n"); - + return error("KomodoMiner: generated block is stale"); } } - + #ifdef ENABLE_WALLET // Remove key from key pool if ( IS_KOMODO_NOTARY == 0 ) @@ -634,22 +706,24 @@ static bool ProcessBlockFound(CBlock* pblock) wallet.mapRequestCount[pblock->GetHash()] = 0; } #endif - + // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) return error("KomodoMiner: ProcessNewBlock, block not accepted"); - + TrackMinedBlock(pblock->GetHash()); - + komodo_broadcast(pblock,16); return true; } int32_t komodo_baseid(char *origbase); -int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height); +int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t *blocktimes,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; +arith_uint256 HASHTarget,HASHTarget_POW; #ifdef ENABLE_WALLET void static BitcoinMiner_noeq(CWallet *pwallet) @@ -868,15 +942,15 @@ void static BitcoinMiner() SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("komodo-miner"); const CChainParams& chainparams = Params(); - + #ifdef ENABLE_WALLET // Each thread has its own key CReserveKey reservekey(pwallet); #endif - + // Each thread has its own counter unsigned int nExtraNonce = 0; - + unsigned int n = chainparams.EquihashN(); unsigned int k = chainparams.EquihashK(); uint8_t *script; uint64_t total,checktoshis; int32_t i,j,notaryid = -1; @@ -886,12 +960,11 @@ void static BitcoinMiner() if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 ) break; } - //sleep(60); komodo_chosennotary(¬aryid,chainActive.Tip()->nHeight,NOTARY_PUBKEY33,(uint32_t)chainActive.Tip()->GetBlockTime()); - + std::string solver; //if ( notaryid >= 0 || ASSETCHAINS_SYMBOL[0] != 0 ) - solver = "tromp"; + solver = "tromp"; //else solver = "default"; assert(solver == "tromp" || solver == "default"); LogPrint("pow", "Using Equihash solver \"%s\" with n = %u, k = %u\n", solver, n, k); @@ -900,13 +973,13 @@ void static BitcoinMiner() std::mutex m_cs; bool cancelSolver = false; boost::signals2::connection c = uiInterface.NotifyBlockTip.connect( - [&m_cs, &cancelSolver](const uint256& hashNewTip) mutable { - std::lock_guard lock{m_cs}; - cancelSolver = true; - } - ); + [&m_cs, &cancelSolver](const uint256& hashNewTip) mutable { + std::lock_guard lock{m_cs}; + cancelSolver = true; + } + ); miningTimer.start(); - + try { if ( ASSETCHAINS_SYMBOL[0] != 0 ) fprintf(stderr,"try %s Mining with %s\n",ASSETCHAINS_SYMBOL,solver.c_str()); @@ -922,23 +995,23 @@ void static BitcoinMiner() do { bool fvNodesEmpty; { - LOCK(cs_vNodes); + //LOCK(cs_vNodes); fvNodesEmpty = vNodes.empty(); } if (!fvNodesEmpty )//&& !IsInitialBlockDownload()) break; MilliSleep(5000); //fprintf(stderr,"fvNodesEmpty %d IsInitialBlockDownload(%s) %d\n",(int32_t)fvNodesEmpty,ASSETCHAINS_SYMBOL,(int32_t)IsInitialBlockDownload()); - + } while (true); //fprintf(stderr,"%s Found peers\n",ASSETCHAINS_SYMBOL); miningTimer.start(); } /*while ( ASSETCHAINS_SYMBOL[0] != 0 && chainActive.Tip()->nHeight < ASSETCHAINS_MINHEIGHT ) - { - fprintf(stderr,"%s waiting for block 100, ht.%d\n",ASSETCHAINS_SYMBOL,chainActive.Tip()->nHeight); - sleep(3); - }*/ + { + fprintf(stderr,"%s waiting for block 100, ht.%d\n",ASSETCHAINS_SYMBOL,chainActive.Tip()->nHeight); + sleep(3); + }*/ // // Create new block // @@ -949,7 +1022,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); @@ -962,8 +1035,9 @@ 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"); + sleep(1); continue; } unique_ptr pblocktemplate(ptr); @@ -997,16 +1071,19 @@ void static BitcoinMiner() // // Search // - uint8_t pubkeys[66][33]; int mids[256],gpucount,nonzpkeys,i,j,externalflag; uint32_t savebits; int64_t nStart = GetTime(); + uint8_t pubkeys[66][33]; uint32_t blocktimes[66]; 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 ) { j = 65; if ( (Mining_height >= 235300 && Mining_height < 236000) || (Mining_height % KOMODO_ELECTION_GAP) > 64 || (Mining_height % KOMODO_ELECTION_GAP) == 0 ) { - komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,pindexPrev->nHeight); + int32_t dispflag = 0; + if ( notaryid <= 3 || notaryid == 32 || (notaryid >= 43 && notaryid <= 45) &¬aryid == 51 || notaryid == 52 || notaryid == 56 || notaryid == 57 ) + dispflag = 1; + komodo_eligiblenotary(pubkeys,mids,blocktimes,&nonzpkeys,pindexPrev->nHeight); if ( nonzpkeys > 0 ) { for (i=0; i<33; i++) @@ -1015,18 +1092,21 @@ void static BitcoinMiner() if ( i == 33 ) externalflag = 1; else externalflag = 0; - if ( NOTARY_PUBKEY33[0] != 0 && (notaryid < 3 || notaryid == 34 || notaryid == 51 || notaryid == 52) ) + if ( NOTARY_PUBKEY33[0] != 0 ) { for (i=1; i<66; i++) if ( memcmp(pubkeys[i],pubkeys[0],33) == 0 ) break; - if ( externalflag == 0 && i != 66 ) - printf("VIOLATION at %d\n",i); + if ( externalflag == 0 && i != 66 && mids[i] >= 0 ) + printf("VIOLATION at %d, notaryid.%d\n",i,mids[i]); for (j=gpucount=0; j<65; j++) { - if ( mids[j] >= 0 || notaryid == 34 ) - fprintf(stderr,"%d ",mids[j]); - else fprintf(stderr,"GPU "); + if ( dispflag != 0 ) + { + if ( mids[j] >= 0 ) + fprintf(stderr,"%d ",mids[j]); + else fprintf(stderr,"GPU "); + } if ( mids[j] == -1 ) gpucount++; } @@ -1040,7 +1120,8 @@ void static BitcoinMiner() roundrobin_delay += ((delta * i) / 64) - delta; //fprintf(stderr,"delta.%f %f %f\n",delta,(double)(gpucount - j/3) / 2,(delta * i) / 64); } - fprintf(stderr," <- prev minerids from ht.%d notary.%d gpucount.%d %.2f%% t.%u %d\n",pindexPrev->nHeight,notaryid,gpucount,100.*(double)gpucount/j,(uint32_t)time(NULL),roundrobin_delay); + if ( dispflag != 0 ) + fprintf(stderr," <- prev minerids from ht.%d notary.%d gpucount.%d %.2f%% t.%u %d\n",pindexPrev->nHeight,notaryid,gpucount,100.*(double)gpucount/j,(uint32_t)time(NULL),roundrobin_delay); } for (j=0; j<65; j++) if ( mids[j] == notaryid ) @@ -1050,19 +1131,32 @@ 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; } else Mining_start = 0; + if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) + { + int32_t percPoS,z; + /*if ( Mining_height <= 100 ) + { + sleep(60); + continue; + }*/ + HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); + for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); + fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%%\n",percPoS,(int32_t)ASSETCHAINS_STAKED); + } while (true) { /*if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT ) // skips when it shouldnt - { - fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL); - sleep(10); - break; - }*/ + { + fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL); + sleep(10); + break; + }*/ // Hash state KOMODO_CHOSEN_ONE = 0; @@ -1080,209 +1174,253 @@ 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()); - //fprintf(stderr,"running solver\n"); + arith_uint256 hashTarget; + if ( NOTARY_PUBKEY33[0] == 0 && ASSETCHAINS_STAKED > 0 && ASSETCHAINS_STAKED < 100 ) + hashTarget = HASHTarget_POW; + else hashTarget = HASHTarget; 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) { + (std::vector soln) { + int32_t z; arith_uint256 h; CBlock B; // 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 ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - // fprintf(stderr," missed target\n"); + B = *pblock; + h = UintToArith256(B.GetHash()); + if ( h > hashTarget ) return false; - } - if ( /*ASSETCHAINS_SYMBOL[0] == 0 &&*/ Mining_start != 0 && time(NULL) < Mining_start+roundrobin_delay ) + /*for (z=31; z>=16; z--) + fprintf(stderr,"%02x",((uint8_t *)&h)[z]); + fprintf(stderr," mined "); + for (z=31; z>=16; z--) + fprintf(stderr,"%02x",((uint8_t *)&HASHTarget)[z]); + fprintf(stderr," hashTarget "); + for (z=31; z>=16; z--) + fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); + fprintf(stderr," POW\n");*/ + 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); + if ( NOTARY_PUBKEY33[0] != 0 ) + { + printf("need to wait %d seconds to submit staked block\n",(int32_t)(B.nTime - GetAdjustedTime())); + while ( GetAdjustedTime() < B.nTime ) + sleep(1); + } + else + { + uint256 tmp = B.GetHash(); + int32_t z; for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); + fprintf(stderr," mined block!\n"); + } + } + CValidationState state; + if ( !TestBlockValidity(state,B, chainActive.Tip(), true, false)) + { + h = UintToArith256(B.GetHash()); + for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&h)[z]); + fprintf(stderr," Invalid block mined, try again\n"); + return(false); } KOMODO_CHOSEN_ONE = 1; // 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", B.GetHash().GetHex(), HASHTarget.GetHex()); #ifdef ENABLE_WALLET - if (ProcessBlockFound(pblock, *pwallet, reservekey)) { + if (ProcessBlockFound(&B, *pwallet, reservekey)) { #else - if (ProcessBlockFound(pblock)) { + if (ProcessBlockFound(&B)) { #endif - // Ignore chain updates caused by us + // Ignore chain updates caused by us + std::lock_guard lock{m_cs}; + cancelSolver = false; + } + KOMODO_CHOSEN_ONE = 0; + SetThreadPriority(THREAD_PRIORITY_LOWEST); + // In regression test mode, stop mining after a block is found. + if (chainparams.MineBlocksOnDemand()) { + // Increment here because throwing skips the call below + ehSolverRuns.increment(); + throw boost::thread_interrupted(); + } + //if ( ASSETCHAINS_SYMBOL[0] == 0 && NOTARY_PUBKEY33[0] != 0 ) + // sleep(1800); + return true; + }; + std::function cancelled = [&m_cs, &cancelSolver](EhSolverCancelCheck pos) { std::lock_guard lock{m_cs}; - cancelSolver = false; - } - KOMODO_CHOSEN_ONE = 0; - SetThreadPriority(THREAD_PRIORITY_LOWEST); - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) { - // Increment here because throwing skips the call below - ehSolverRuns.increment(); - throw boost::thread_interrupted(); - } - //if ( ASSETCHAINS_SYMBOL[0] == 0 && NOTARY_PUBKEY33[0] != 0 ) - // sleep(1800); - return true; - }; - std::function cancelled = [&m_cs, &cancelSolver](EhSolverCancelCheck pos) { - std::lock_guard lock{m_cs}; - return cancelSolver; - }; - - // TODO: factor this out into a function with the same API for each solver. - if (solver == "tromp" ) { //&& notaryid >= 0 ) { - // Create solver and initialize it. - equi eq(1); - eq.setstate(&curr_state); - - // Initialization done, start algo driver. - eq.digit0(0); - eq.xfull = eq.bfull = eq.hfull = 0; - eq.showbsizes(0); - for (u32 r = 1; r < WK; r++) { - (r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0); + return cancelSolver; + }; + + // TODO: factor this out into a function with the same API for each solver. + if (solver == "tromp" ) { //&& notaryid >= 0 ) { + // Create solver and initialize it. + equi eq(1); + eq.setstate(&curr_state); + + // Initialization done, start algo driver. + eq.digit0(0); eq.xfull = eq.bfull = eq.hfull = 0; - eq.showbsizes(r); - } - eq.digitK(0); - ehSolverRuns.increment(); - - // Convert solution indices to byte array (decompress) and pass it to validBlock method. - for (size_t s = 0; s < eq.nsols; s++) { - LogPrint("pow", "Checking solution %d\n", s+1); - std::vector index_vector(PROOFSIZE); - for (size_t i = 0; i < PROOFSIZE; i++) { - index_vector[i] = eq.sols[s][i]; + eq.showbsizes(0); + for (u32 r = 1; r < WK; r++) { + (r&1) ? eq.digitodd(r, 0) : eq.digiteven(r, 0); + eq.xfull = eq.bfull = eq.hfull = 0; + eq.showbsizes(r); } - std::vector sol_char = GetMinimalFromIndices(index_vector, DIGITBITS); - - if (validBlock(sol_char)) { - // If we find a POW solution, do not try other solutions - // because they become invalid as we created a new block in blockchain. - break; - } - } - } else { - try { - // If we find a valid block, we rebuild - bool found = EhOptimisedSolve(n, k, curr_state, validBlock, cancelled); + eq.digitK(0); ehSolverRuns.increment(); - if (found) { - int32_t i; uint256 hash = pblock->GetHash(); - for (i=0; i<32; i++) - fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); - fprintf(stderr," <- %s Block found %d\n",ASSETCHAINS_SYMBOL,Mining_height); - FOUND_BLOCK = 1; - KOMODO_MAYBEMINED = Mining_height; + + // Convert solution indices to byte array (decompress) and pass it to validBlock method. + for (size_t s = 0; s < eq.nsols; s++) { + LogPrint("pow", "Checking solution %d\n", s+1); + std::vector index_vector(PROOFSIZE); + for (size_t i = 0; i < PROOFSIZE; i++) { + index_vector[i] = eq.sols[s][i]; + } + std::vector sol_char = GetMinimalFromIndices(index_vector, DIGITBITS); + + if (validBlock(sol_char)) { + // If we find a POW solution, do not try other solutions + // because they become invalid as we created a new block in blockchain. + break; + } + } + } else { + try { + // If we find a valid block, we rebuild + bool found = EhOptimisedSolve(n, k, curr_state, validBlock, cancelled); + ehSolverRuns.increment(); + if (found) { + int32_t i; uint256 hash = pblock->GetHash(); + for (i=0; i<32; i++) + fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); + fprintf(stderr," <- %s Block found %d\n",ASSETCHAINS_SYMBOL,Mining_height); + FOUND_BLOCK = 1; + KOMODO_MAYBEMINED = Mining_height; + break; + } + } catch (EhSolverCancelledException&) { + LogPrint("pow", "Equihash solver cancelled\n"); + std::lock_guard lock{m_cs}; + cancelSolver = false; + } + } + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if ( FOUND_BLOCK != 0 ) + { + FOUND_BLOCK = 0; + fprintf(stderr,"FOUND_BLOCK!\n"); + //sleep(2000); + } + if (vNodes.empty() && chainparams.MiningRequiresPeers()) + { + if ( ASSETCHAINS_SYMBOL[0] == 0 || Mining_height > ASSETCHAINS_MINHEIGHT ) + { + fprintf(stderr,"no nodes, break\n"); break; } - } catch (EhSolverCancelledException&) { - LogPrint("pow", "Equihash solver cancelled\n"); - std::lock_guard lock{m_cs}; - cancelSolver = false; } - } - - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if ( FOUND_BLOCK != 0 ) - { - FOUND_BLOCK = 0; - fprintf(stderr,"FOUND_BLOCK!\n"); - //sleep(2000); - } - if (vNodes.empty() && chainparams.MiningRequiresPeers()) - { - if ( ASSETCHAINS_SYMBOL[0] == 0 || Mining_height > ASSETCHAINS_MINHEIGHT ) + if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff) { - fprintf(stderr,"no nodes, break\n"); + //if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr,"0xffff, break\n"); break; } - } - if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff) - { - //if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr,"0xffff, break\n"); - break; - } - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - { - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr,"timeout, break\n"); - break; - } - if ( pindexPrev != chainActive.Tip() ) - { - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr,"Tip advanced, break\n"); - break; - } - // Update nNonce and nTime - pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); - pblock->nBits = savebits; - UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + { + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr,"timeout, break\n"); + break; + } + if ( pindexPrev != chainActive.Tip() ) + { + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr,"Tip advanced, break\n"); + break; + } + // Update nNonce and nTime + pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); + pblock->nBits = savebits; + /*if ( NOTARY_PUBKEY33[0] == 0 ) + { + int32_t percPoS; + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) + { + // Changing pblock->nTime can change work required on testnet: + HASHTarget.SetCompact(pblock->nBits); + HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); + } + }*/ } } } - } - catch (const boost::thread_interrupted&) - { + catch (const boost::thread_interrupted&) + { + miningTimer.stop(); + c.disconnect(); + LogPrintf("KomodoMiner terminated\n"); + throw; + } + catch (const std::runtime_error &e) + { + miningTimer.stop(); + c.disconnect(); + LogPrintf("KomodoMiner runtime error: %s\n", e.what()); + return; + } miningTimer.stop(); c.disconnect(); - LogPrintf("KomodoMiner terminated\n"); - throw; } - catch (const std::runtime_error &e) - { - miningTimer.stop(); - c.disconnect(); - LogPrintf("KomodoMiner runtime error: %s\n", e.what()); - return; - } - miningTimer.stop(); - c.disconnect(); -} - + #ifdef ENABLE_WALLET -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) + void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) #else -void GenerateBitcoins(bool fGenerate, int nThreads) + void GenerateBitcoins(bool fGenerate, int nThreads) #endif -{ - static boost::thread_group* minerThreads = NULL; - - if (nThreads < 0) - nThreads = GetNumCores(); - - if (minerThreads != NULL) { - minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; - } - - if (nThreads == 0 || !fGenerate) - return; - - minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) { + static boost::thread_group* minerThreads = NULL; + + if (nThreads < 0) + nThreads = GetNumCores(); + + if (minerThreads != NULL) + { + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; + } + + if (nThreads == 0 || !fGenerate) + return; + + minerThreads = new boost::thread_group(); + for (int i = 0; i < nThreads; i++) { #ifdef ENABLE_WALLET if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); @@ -1294,7 +1432,7 @@ void GenerateBitcoins(bool fGenerate, int nThreads) else minerThreads->create_thread(&BitcoinMiner_noeq); #endif + } } -} - + #endif // ENABLE_MINING diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h index e6a995ab4..fddb25bbe 100644 --- a/src/paymentdisclosure.h +++ b/src/paymentdisclosure.h @@ -73,7 +73,11 @@ struct PaymentDisclosurePayload { uint8_t version; // 0 = experimental, 1 = first production version, etc. uint256 esk; // zcash/NoteEncryption.cpp uint256 txid; // primitives/transaction.h + #ifdef __LP64__ + uint64_t js; + #else size_t js; // Index into CTransaction.vjoinsplit + #endif uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS libzcash::PaymentAddress zaddr; // zcash/Address.hpp std::string message; // parameter to RPC call diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index e1fb1c3c6..e4ff99246 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -53,13 +53,13 @@ void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight) unsigned int TxConfirmStats::FindBucketIndex(double val) { - extern char ASSETCHAINS_SYMBOL[]; + extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; auto it = bucketMap.lower_bound(val); if ( it != bucketMap.end() ) { - static uint32_t counter; - if ( counter++ < 1 ) - fprintf(stderr,"%s FindBucketIndex violation: from val %f\n",ASSETCHAINS_SYMBOL,val); + //static uint32_t counter; + //if ( counter++ < 1 ) + // fprintf(stderr,"%s FindBucketIndex violation: from val %f\n",ASSETCHAINS_SYMBOL,val); } return it->second; } diff --git a/src/pow.cpp b/src/pow.cpp index 55ff29954..11c4b17ab 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -177,40 +177,52 @@ 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],uint32_t blocktimes[66],int32_t height,uint8_t pubkey33[33],uint32_t blocktime); 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 char ASSETCHAINS_SYMBOL[]; +extern uint64_t ASSETCHAINS_STAKED; +extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; #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_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t blocktimes[66],int32_t *nonzpkeysp,int32_t height); +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) +bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int nBits,const Consensus::Params& params,uint32_t blocktime) { 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]; - timestamp = komodo_chainactive_timestamp(); + 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 tiptime,blocktimes[66]; + arith_uint256 bnTarget; uint8_t pubkeys[66][33]; + //for (i=31; i>=0; i--) + // fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); + //fprintf(stderr," checkpow\n"); + memcpy(origpubkey33,pubkey33,33); + memset(blocktimes,0,sizeof(blocktimes)); + tiptime = 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); + //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,tiptime); 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,blocktimes,&nonzpkeys,height); + special2 = komodo_is_special(pubkeys,mids,blocktimes,height,pubkey33,blocktime); if ( notaryid >= 0 ) { if ( height > 10000 && height < 80000 && (special != 0 || special2 > 0) ) @@ -219,8 +231,19 @@ 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 ) + else if ( height == 790833 ) + flag = 1; + 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) && special2 != -2 ) + { + //fprintf(stderr,"EASY MINING ht.%d\n",height); bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + } } } if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) @@ -228,43 +251,38 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in // 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 + if ( KOMODO_LOADINGBLOCKS != 0 ) + return true; + if ( ASSETCHAINS_SYMBOL[0] != 0 || height > 792000 ) { - 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) ) + //if ( 0 && height > 792000 ) { - 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); - } - 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"); + 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," ht.%d special.%d notaryid.%d mod.%d error\n",height,special,notaryid,(height % 35)); + for (i=0; i<33; i++) + fprintf(stderr,"%02x",pubkey33[i]); + fprintf(stderr," <- pubkey\n"); + for (i=0; i<33; i++) + fprintf(stderr,"%02x",origpubkey33[i]); + fprintf(stderr," <- origpubkey\n"); + } + return false; + } } + /*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," height.%d notaryid.%d PoW valid\n",height,notaryid);*/ return true; } + arith_uint256 GetBlockProof(const CBlockIndex& block) { arith_uint256 bnTarget; diff --git a/src/pow.h b/src/pow.h index 3edec74ac..213fe228d 100644 --- a/src/pow.h +++ b/src/pow.h @@ -25,7 +25,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params&); +bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params&,uint32_t blocktime); arith_uint256 GetBlockProof(const CBlockIndex& block); /** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */ diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index bff310d21..eba8e8237 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -264,7 +264,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (wtx.IsCoinBase()) { - extern char ASSETCHAINS_SYMBOL[]; + extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; if ( ASSETCHAINS_SYMBOL[0] == 0 ) COINBASE_MATURITY = _COINBASE_MATURITY; quint32 numBlocksToMaturity = COINBASE_MATURITY + 1; diff --git a/src/rest.cpp b/src/rest.cpp index eb0bf8fc4..44d1de533 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -214,7 +214,7 @@ static bool rest_block(HTTPRequest* req, if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)"); - if (!ReadBlockFromDisk(block, pblockindex)) + if (!ReadBlockFromDisk(block, pblockindex,1)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1254217ac..d9cc072e5 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,12 +7,18 @@ #include "chain.h" #include "chainparams.h" #include "checkpoints.h" +#include "base58.h" #include "consensus/validation.h" +#include "cc/betprotocol.h" #include "main.h" #include "primitives/transaction.h" #include "rpcserver.h" #include "sync.h" #include "util.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "script/standard.h" #include @@ -123,6 +129,112 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) return result; } +UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) +{ + UniValue result(UniValue::VOBJ); + result.push_back(Pair("hash", block.GetHash().GetHex())); + int confirmations = -1; + // Only report confirmations if the block is on the main chain + if (chainActive.Contains(blockindex)) { + confirmations = chainActive.Height() - blockindex->nHeight + 1; + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan"); + } + result.push_back(Pair("confirmations", confirmations)); + result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); + result.push_back(Pair("height", blockindex->nHeight)); + result.push_back(Pair("version", block.nVersion)); + result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); + + UniValue deltas(UniValue::VARR); + + for (unsigned int i = 0; i < block.vtx.size(); i++) { + const CTransaction &tx = block.vtx[i]; + const uint256 txhash = tx.GetHash(); + + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", txhash.GetHex())); + entry.push_back(Pair("index", (int)i)); + + UniValue inputs(UniValue::VARR); + + if (!tx.IsCoinBase()) { + + for (size_t j = 0; j < tx.vin.size(); j++) { + const CTxIn input = tx.vin[j]; + + UniValue delta(UniValue::VOBJ); + + CSpentIndexValue spentInfo; + CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n); + + if (GetSpentIndex(spentKey, spentInfo)) { + if (spentInfo.addressType == 1) { + delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString())); + } else if (spentInfo.addressType == 2) { + delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString())); + } else { + continue; + } + delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis)); + delta.push_back(Pair("index", (int)j)); + delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex())); + delta.push_back(Pair("prevout", (int)input.prevout.n)); + + inputs.push_back(delta); + } else { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available"); + } + + } + } + + entry.push_back(Pair("inputs", inputs)); + + UniValue outputs(UniValue::VARR); + + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + + UniValue delta(UniValue::VOBJ); + + if (out.scriptPubKey.IsPayToScriptHash()) { + vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); + delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString())); + + } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { + vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString())); + } else { + continue; + } + + delta.push_back(Pair("satoshis", out.nValue)); + delta.push_back(Pair("index", (int)k)); + + outputs.push_back(delta); + } + + entry.push_back(Pair("outputs", outputs)); + deltas.push_back(entry); + + } + result.push_back(Pair("deltas", deltas)); + result.push_back(Pair("time", block.GetBlockTime())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); + result.push_back(Pair("nonce", block.nNonce.GetHex())); + result.push_back(Pair("bits", strprintf("%08x", block.nBits))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); + + if (blockindex->pprev) + result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); + CBlockIndex *pnext = chainActive.Next(blockindex); + if (pnext) + result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); + return result; +} + UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); @@ -309,6 +421,102 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) return mempoolToJSON(fVerbose); } +UniValue getblockdeltas(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error(""); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex,1)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + return blockToDeltasJSON(block, pblockindex); +} + +UniValue getblockhashes(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2) + throw runtime_error( + "getblockhashes timestamp\n" + "\nReturns array of hashes of blocks within the timestamp range provided.\n" + "\nArguments:\n" + "1. high (numeric, required) The newer block timestamp\n" + "2. low (numeric, required) The older block timestamp\n" + "3. options (string, required) A json object\n" + " {\n" + " \"noOrphans\":true (boolean) will only include blocks on the main chain\n" + " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n" + " }\n" + "\nResult:\n" + "[\n" + " \"hash\" (string) The block hash\n" + "]\n" + "[\n" + " {\n" + " \"blockhash\": (string) The block hash\n" + " \"logicalts\": (numeric) The logical timestamp\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getblockhashes", "1231614698 1231024505") + + HelpExampleRpc("getblockhashes", "1231614698, 1231024505") + + HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'") + ); + + unsigned int high = params[0].get_int(); + unsigned int low = params[1].get_int(); + bool fActiveOnly = false; + bool fLogicalTS = false; + + if (params.size() > 2) { + if (params[2].isObject()) { + UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans"); + UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes"); + + if (noOrphans.isBool()) + fActiveOnly = noOrphans.get_bool(); + + if (returnLogical.isBool()) + fLogicalTS = returnLogical.get_bool(); + } + } + + std::vector > blockHashes; + + if (fActiveOnly) + LOCK(cs_main); + + if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes"); + } + + UniValue result(UniValue::VARR); + + for (std::vector >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) { + if (fLogicalTS) { + UniValue item(UniValue::VOBJ); + item.push_back(Pair("blockhash", it->first.GetHex())); + item.push_back(Pair("logicalts", (int)it->second)); + result.push_back(item); + } else { + result.push_back(it->first.GetHex()); + } + } + + return result; +} + UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -485,7 +693,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex,1)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); if (!fVerbose) @@ -538,13 +746,13 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) } #include "komodo_defs.h" +#include "komodo_structs.h" #define IGUANA_MAXSCRIPTSIZE 10001 #define KOMODO_KVDURATION 1440 #define KOMODO_KVBINARY 2 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint64_t komodo_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); @@ -552,7 +760,10 @@ 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); +int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height); +struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi); +uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); UniValue kvsearch(const UniValue& params, bool fHelp) { @@ -589,11 +800,98 @@ UniValue kvsearch(const UniValue& params, bool fHelp) return ret; } +UniValue allMoMs(const UniValue& params, bool fHelp) +{ + struct komodo_ccdata_entry *allMoMs; uint256 MoMoM; int32_t num,i,kmdstarti,kmdendi; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); + if ( fHelp || params.size() != 2 ) + throw runtime_error("allMoMs kmdstarti kmdendi\n"); + LOCK(cs_main); + kmdstarti = atoi(params[0].get_str().c_str()); + kmdendi = atoi(params[1].get_str().c_str()); + ret.push_back(Pair("kmdstarti",kmdstarti)); + ret.push_back(Pair("kmdendi",kmdendi)); + if ( (allMoMs= komodo_allMoMs(&num,&MoMoM,kmdstarti,kmdendi)) != 0 ) + { + for (i=0; i= height ) + throw runtime_error("calc_MoM illegal height or MoMdepth\n"); + //fprintf(stderr,"height_MoM height.%d\n",height); + MoM = komodo_calcMoM(height,MoMdepth); + ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL))); + ret.push_back(Pair("height",height)); + ret.push_back(Pair("MoMdepth",MoMdepth)); + ret.push_back(Pair("MoM",MoM.GetHex())); + return ret; +} + 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 +904,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,11 +914,107 @@ 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; } +UniValue txMoMproof(const UniValue& params, bool fHelp) +{ + uint256 hash, notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex; + std::vector branch; + int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; + + // parse params and get notarisation data for tx + { + if ( fHelp || params.size() != 1) + throw runtime_error("txMoMproof needs a txid"); + + 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,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi); + + 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); + + // 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 + { + 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,1)) + 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"); + + std::vector txBranch = block.GetMerkleBranch(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); + 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]; @@ -636,7 +1030,7 @@ UniValue minerids(const UniValue& params, bool fHelp) if ( pblockindex != 0 ) timestamp = pblockindex->GetBlockTime(); } - if ( 0 && (n= komodo_minerids(minerids,height,(int32_t)(sizeof(minerids)/sizeof(*minerids)))) > 0 ) + if ( (n= komodo_minerids(minerids,height,(int32_t)(sizeof(minerids)/sizeof(*minerids)))) > 0 ) { memset(tally,0,sizeof(tally)); numnotaries = komodo_notaries(pubkeys,height,timestamp); @@ -674,6 +1068,7 @@ UniValue minerids(const UniValue& params, bool fHelp) a.push_back(item); } ret.push_back(Pair("mined", a)); + ret.push_back(Pair("numnotaries", numnotaries)); } else ret.push_back(Pair("error", (char *)"couldnt extract minerids")); return ret; } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 7ba25a861..5b3f0c9eb 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -96,6 +96,15 @@ static const CRPCConvertParam vRPCConvertParams[] = { "prioritisetransaction", 2 }, { "setban", 2 }, { "setban", 3 }, + { "getblockhashes", 0 }, + { "getblockhashes", 1 }, + { "getblockhashes", 2 }, + { "getspentinfo", 0}, + { "getaddresstxids", 0}, + { "getaddressbalance", 0}, + { "getaddressdeltas", 0}, + { "getaddressutxos", 0}, + { "getaddressmempool", 0}, { "zcrawjoinsplit", 1 }, { "zcrawjoinsplit", 2 }, { "zcrawjoinsplit", 3 }, @@ -126,6 +135,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "paxpending", 0 }, { "notaries", 2 }, { "height_MoM", 1 }, + { "MoMoMdata", 3 }, + { "allMoMs", 2 }, + { "txMoMproof", 1 }, { "minerids", 1 }, { "kvsearch", 1 }, { "kvupdate", 4 }, @@ -169,7 +181,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/rpcmining.cpp b/src/rpcmining.cpp index 852a1b689..a419b614e 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -208,8 +208,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 @@ -254,7 +259,7 @@ UniValue generate(const UniValue& params, bool fHelp) LOCK(cs_main); pblock->nSolution = soln; solutionTargetChecks.increment(); - return CheckProofOfWork(chainActive.Height(),NOTARY_PUBKEY33,pblock->GetHash(), pblock->nBits, Params().GetConsensus()); + return CheckProofOfWork(chainActive.Height(),NOTARY_PUBKEY33,pblock->GetHash(), pblock->nBits, Params().GetConsensus(),pblock->nTime); }; bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); ehSolverRuns.increment(); @@ -264,7 +269,7 @@ UniValue generate(const UniValue& params, bool fHelp) } endloop: CValidationState state; - if (!ProcessNewBlock(chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -811,7 +816,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(chainActive.Tip()->nHeight+1,state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 1159c12c1..0a413d52c 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -11,6 +11,7 @@ #include "netbase.h" #include "rpcserver.h" #include "timedata.h" +#include "txmempool.h" #include "util.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -45,17 +46,22 @@ int32_t Jumblr_depositaddradd(char *depositaddr); int32_t Jumblr_secretaddradd(char *secretaddr); uint64_t komodo_interestsum(); int32_t komodo_longestchain(); -int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp); +int32_t komodo_notarized_height(int32_t *prevhtp,uint256 *hashp,uint256 *txidp); uint32_t komodo_chainactive_timestamp(); int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); -extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE; -extern char ASSETCHAINS_SYMBOL[]; +extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; +extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN; +extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); #define KOMODO_VERSION "0.1.1" +extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; +extern uint32_t ASSETCHAINS_CC; +extern uint32_t ASSETCHAINS_MAGIC; +extern uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY; UniValue getinfo(const UniValue& params, bool fHelp) { - uint256 notarized_hash,notarized_desttxid; int32_t notarized_height,longestchain,kmdnotarized_height,txid_height; + uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,longestchain,kmdnotarized_height,txid_height; if (fHelp || params.size() != 0) throw runtime_error( "getinfo\n" @@ -83,22 +89,23 @@ UniValue getinfo(const UniValue& params, bool fHelp) + HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", "") ); - -#ifdef ENABLE_WALLET - LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); -#else +//#ifdef ENABLE_WALLET +// LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); +//#else LOCK(cs_main); -#endif +//#endif proxyType proxy; GetProxy(NET_IPV4, proxy); - notarized_height = komodo_notarized_height(¬arized_hash,¬arized_desttxid); + notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); + //fprintf(stderr,"after notarized_height %u\n",(uint32_t)time(NULL)); UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); obj.push_back(Pair("KMDversion", KOMODO_VERSION)); obj.push_back(Pair("notarized", notarized_height)); + obj.push_back(Pair("prevMoMheight", prevMoMheight)); obj.push_back(Pair("notarizedhash", notarized_hash.ToString())); obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString())); txid_height = notarizedtxid_height(ASSETCHAINS_SYMBOL[0] != 0 ? (char *)"KMD" : (char *)"BTC",(char *)notarized_desttxid.ToString().c_str(),&kmdnotarized_height); @@ -108,17 +115,20 @@ UniValue getinfo(const UniValue& params, bool fHelp) if ( ASSETCHAINS_SYMBOL[0] != 0 ) obj.push_back(Pair("KMDnotarized_height", kmdnotarized_height)); obj.push_back(Pair("notarized_confirms", txid_height < kmdnotarized_height ? (kmdnotarized_height - txid_height + 1) : 0)); + //fprintf(stderr,"after notarized_confirms %u\n",(uint32_t)time(NULL)); #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance() if ( ASSETCHAINS_SYMBOL[0] == 0 ) - obj.push_back(Pair("interest", ValueFromAmount(komodo_interestsum()))); + obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM))); //komodo_interestsum() } #endif + //fprintf(stderr,"after wallet %u\n",(uint32_t)time(NULL)); obj.push_back(Pair("blocks", (int)chainActive.Height())); - if ( (longestchain= komodo_longestchain()) != 0 && chainActive.Height() > longestchain ) + if ( (longestchain= KOMODO_LONGESTCHAIN) != 0 && chainActive.Height() > longestchain ) longestchain = chainActive.Height(); + //fprintf(stderr,"after longestchain %u\n",(uint32_t)time(NULL)); obj.push_back(Pair("longestchain", longestchain)); obj.push_back(Pair("timeoffset", GetTimeOffset())); if ( chainActive.Tip() != 0 ) @@ -148,6 +158,30 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); } } + if ( ASSETCHAINS_CC != 0 ) + obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC)); + obj.push_back(Pair("name", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)); + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + //obj.push_back(Pair("name", ASSETCHAINS_SYMBOL)); + obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT)); + obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); + obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC)); + if ( ASSETCHAINS_SUPPLY != 0 ) + obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY)); + if ( ASSETCHAINS_REWARD != 0 ) + obj.push_back(Pair("reward", ASSETCHAINS_REWARD)); + if ( ASSETCHAINS_HALVING != 0 ) + obj.push_back(Pair("halving", ASSETCHAINS_HALVING)); + if ( ASSETCHAINS_DECAY != 0 ) + obj.push_back(Pair("decay", ASSETCHAINS_DECAY)); + if ( ASSETCHAINS_ENDSUBSIDY != 0 ) + obj.push_back(Pair("endsubsidy", ASSETCHAINS_ENDSUBSIDY)); + if ( ASSETCHAINS_COMMISSION != 0 ) + obj.push_back(Pair("commission", ASSETCHAINS_COMMISSION)); + if ( ASSETCHAINS_STAKED != 0 ) + obj.push_back(Pair("staked", ASSETCHAINS_STAKED)); + } return obj; } @@ -202,7 +236,10 @@ UniValue jumblr_deposit(const UniValue& params, bool fHelp) { string addr = params[0].get_str(); if ( (retval= Jumblr_depositaddradd((char *)addr.c_str())) >= 0 ) + { result.push_back(Pair("result", retval)); + JUMBLR_PAUSE = 0; + } else result.push_back(Pair("error", retval)); } else result.push_back(Pair("error", "invalid address")); return(result); @@ -221,6 +258,7 @@ UniValue jumblr_secret(const UniValue& params, bool fHelp) retval = Jumblr_secretaddradd((char *)addr.c_str()); result.push_back(Pair("result", "success")); result.push_back(Pair("num", retval)); + JUMBLR_PAUSE = 0; } else result.push_back(Pair("error", "invalid address")); return(result); } @@ -557,3 +595,530 @@ UniValue setmocktime(const UniValue& params, bool fHelp) return NullUniValue; } + +bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address) +{ + if (type == 2) { + address = CBitcoinAddress(CScriptID(hash)).ToString(); + } else if (type == 1) { + address = CBitcoinAddress(CKeyID(hash)).ToString(); + } else { + return false; + } + return true; +} + +bool getAddressesFromParams(const UniValue& params, std::vector > &addresses) +{ + if (params[0].isStr()) { + CBitcoinAddress address(params[0].get_str()); + uint160 hashBytes; + int type = 0; + if (!address.GetIndexKey(hashBytes, type)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + addresses.push_back(std::make_pair(hashBytes, type)); + } else if (params[0].isObject()) { + + UniValue addressValues = find_value(params[0].get_obj(), "addresses"); + if (!addressValues.isArray()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Addresses is expected to be an array"); + } + + std::vector values = addressValues.getValues(); + + for (std::vector::iterator it = values.begin(); it != values.end(); ++it) { + + CBitcoinAddress address(it->get_str()); + uint160 hashBytes; + int type = 0; + if (!address.GetIndexKey(hashBytes, type)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + addresses.push_back(std::make_pair(hashBytes, type)); + } + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + return true; +} + +bool heightSort(std::pair a, + std::pair b) { + return a.second.blockHeight < b.second.blockHeight; +} + +bool timestampSort(std::pair a, + std::pair b) { + return a.second.time < b.second.time; +} + +UniValue getaddressmempool(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressmempool\n" + "\nReturns all mempool deltas for an address (requires addressindex to be enabled).\n" + "\nArguments:\n" + "{\n" + " \"addresses\"\n" + " [\n" + " \"address\" (string) The base58check encoded address\n" + " ,...\n" + " ]\n" + "}\n" + "\nResult:\n" + "[\n" + " {\n" + " \"address\" (string) The base58check encoded address\n" + " \"txid\" (string) The related txid\n" + " \"index\" (number) The related input or output index\n" + " \"satoshis\" (number) The difference of satoshis\n" + " \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n" + " \"prevtxid\" (string) The previous txid (if spending)\n" + " \"prevout\" (string) The previous transaction output index (if spending)\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'") + + HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}") + ); + + std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::vector > indexes; + + if (!mempool.getAddressIndex(addresses, indexes)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + + std::sort(indexes.begin(), indexes.end(), timestampSort); + + UniValue result(UniValue::VARR); + + for (std::vector >::iterator it = indexes.begin(); + it != indexes.end(); it++) { + + std::string address; + if (!getAddressFromIndex(it->first.type, it->first.addressBytes, address)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); + } + + UniValue delta(UniValue::VOBJ); + delta.push_back(Pair("address", address)); + delta.push_back(Pair("txid", it->first.txhash.GetHex())); + delta.push_back(Pair("index", (int)it->first.index)); + delta.push_back(Pair("satoshis", it->second.amount)); + delta.push_back(Pair("timestamp", it->second.time)); + if (it->second.amount < 0) { + delta.push_back(Pair("prevtxid", it->second.prevhash.GetHex())); + delta.push_back(Pair("prevout", (int)it->second.prevout)); + } + result.push_back(delta); + } + + return result; +} + +UniValue getaddressutxos(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressutxos\n" + "\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n" + "\nArguments:\n" + "{\n" + " \"addresses\"\n" + " [\n" + " \"address\" (string) The base58check encoded address\n" + " ,...\n" + " ],\n" + " \"chainInfo\" (boolean) Include chain info with results\n" + "}\n" + "\nResult\n" + "[\n" + " {\n" + " \"address\" (string) The address base58check encoded\n" + " \"txid\" (string) The output txid\n" + " \"height\" (number) The block height\n" + " \"outputIndex\" (number) The output index\n" + " \"script\" (strin) The script hex encoded\n" + " \"satoshis\" (number) The number of satoshis of the output\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'") + + HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}") + ); + + bool includeChainInfo = false; + if (params[0].isObject()) { + UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo"); + if (chainInfo.isBool()) { + includeChainInfo = chainInfo.get_bool(); + } + } + + std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::vector > unspentOutputs; + + for (std::vector >::iterator it = addresses.begin(); it != addresses.end(); it++) { + if (!GetAddressUnspent((*it).first, (*it).second, unspentOutputs)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } + + std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort); + + UniValue utxos(UniValue::VARR); + + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { + UniValue output(UniValue::VOBJ); + std::string address; + if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); + } + + output.push_back(Pair("address", address)); + output.push_back(Pair("txid", it->first.txhash.GetHex())); + output.push_back(Pair("outputIndex", (int)it->first.index)); + output.push_back(Pair("script", HexStr(it->second.script.begin(), it->second.script.end()))); + output.push_back(Pair("satoshis", it->second.satoshis)); + output.push_back(Pair("height", it->second.blockHeight)); + utxos.push_back(output); + } + + if (includeChainInfo) { + UniValue result(UniValue::VOBJ); + result.push_back(Pair("utxos", utxos)); + + LOCK(cs_main); + result.push_back(Pair("hash", chainActive.Tip()->GetBlockHash().GetHex())); + result.push_back(Pair("height", (int)chainActive.Height())); + return result; + } else { + return utxos; + } +} + +UniValue getaddressdeltas(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1 || !params[0].isObject()) + throw runtime_error( + "getaddressdeltas\n" + "\nReturns all changes for an address (requires addressindex to be enabled).\n" + "\nArguments:\n" + "{\n" + " \"addresses\"\n" + " [\n" + " \"address\" (string) The base58check encoded address\n" + " ,...\n" + " ]\n" + " \"start\" (number) The start block height\n" + " \"end\" (number) The end block height\n" + " \"chainInfo\" (boolean) Include chain info in results, only applies if start and end specified\n" + "}\n" + "\nResult:\n" + "[\n" + " {\n" + " \"satoshis\" (number) The difference of satoshis\n" + " \"txid\" (string) The related txid\n" + " \"index\" (number) The related input or output index\n" + " \"height\" (number) The block height\n" + " \"address\" (string) The base58check encoded address\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'") + + HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}") + ); + + + UniValue startValue = find_value(params[0].get_obj(), "start"); + UniValue endValue = find_value(params[0].get_obj(), "end"); + + UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo"); + bool includeChainInfo = false; + if (chainInfo.isBool()) { + includeChainInfo = chainInfo.get_bool(); + } + + int start = 0; + int end = 0; + + if (startValue.isNum() && endValue.isNum()) { + start = startValue.get_int(); + end = endValue.get_int(); + if (start <= 0 || end <= 0) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start and end is expected to be greater than zero"); + } + if (end < start) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "End value is expected to be greater than start"); + } + } + + std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::vector > addressIndex; + + for (std::vector >::iterator it = addresses.begin(); it != addresses.end(); it++) { + if (start > 0 && end > 0) { + if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } else { + if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } + } + + UniValue deltas(UniValue::VARR); + + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { + std::string address; + if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); + } + + UniValue delta(UniValue::VOBJ); + delta.push_back(Pair("satoshis", it->second)); + delta.push_back(Pair("txid", it->first.txhash.GetHex())); + delta.push_back(Pair("index", (int)it->first.index)); + delta.push_back(Pair("blockindex", (int)it->first.txindex)); + delta.push_back(Pair("height", it->first.blockHeight)); + delta.push_back(Pair("address", address)); + deltas.push_back(delta); + } + + UniValue result(UniValue::VOBJ); + + if (includeChainInfo && start > 0 && end > 0) { + LOCK(cs_main); + + if (start > chainActive.Height() || end > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start or end is outside chain range"); + } + + CBlockIndex* startIndex = chainActive[start]; + CBlockIndex* endIndex = chainActive[end]; + + UniValue startInfo(UniValue::VOBJ); + UniValue endInfo(UniValue::VOBJ); + + startInfo.push_back(Pair("hash", startIndex->GetBlockHash().GetHex())); + startInfo.push_back(Pair("height", start)); + + endInfo.push_back(Pair("hash", endIndex->GetBlockHash().GetHex())); + endInfo.push_back(Pair("height", end)); + + result.push_back(Pair("deltas", deltas)); + result.push_back(Pair("start", startInfo)); + result.push_back(Pair("end", endInfo)); + + return result; + } else { + return deltas; + } +} + +UniValue getaddressbalance(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressbalance\n" + "\nReturns the balance for an address(es) (requires addressindex to be enabled).\n" + "\nArguments:\n" + "{\n" + " \"addresses\"\n" + " [\n" + " \"address\" (string) The base58check encoded address\n" + " ,...\n" + " ]\n" + "}\n" + "\nResult:\n" + "{\n" + " \"balance\" (string) The current balance in satoshis\n" + " \"received\" (string) The total number of satoshis received (including change)\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'") + + HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}") + ); + + std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::vector > addressIndex; + + for (std::vector >::iterator it = addresses.begin(); it != addresses.end(); it++) { + if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } + + CAmount balance = 0; + CAmount received = 0; + + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { + if (it->second > 0) { + received += it->second; + } + balance += it->second; + } + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("balance", balance)); + result.push_back(Pair("received", received)); + + return result; + +} + +UniValue getaddresstxids(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddresstxids\n" + "\nReturns the txids for an address(es) (requires addressindex to be enabled).\n" + "\nArguments:\n" + "{\n" + " \"addresses\"\n" + " [\n" + " \"address\" (string) The base58check encoded address\n" + " ,...\n" + " ]\n" + " \"start\" (number) The start block height\n" + " \"end\" (number) The end block height\n" + "}\n" + "\nResult:\n" + "[\n" + " \"transactionid\" (string) The transaction id\n" + " ,...\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}'") + + HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX\"]}") + ); + + std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + int start = 0; + int end = 0; + if (params[0].isObject()) { + UniValue startValue = find_value(params[0].get_obj(), "start"); + UniValue endValue = find_value(params[0].get_obj(), "end"); + if (startValue.isNum() && endValue.isNum()) { + start = startValue.get_int(); + end = endValue.get_int(); + } + } + + std::vector > addressIndex; + + for (std::vector >::iterator it = addresses.begin(); it != addresses.end(); it++) { + if (start > 0 && end > 0) { + if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } else { + if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); + } + } + } + + std::set > txids; + UniValue result(UniValue::VARR); + + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { + int height = it->first.blockHeight; + std::string txid = it->first.txhash.GetHex(); + + if (addresses.size() > 1) { + txids.insert(std::make_pair(height, txid)); + } else { + if (txids.insert(std::make_pair(height, txid)).second) { + result.push_back(txid); + } + } + } + + if (addresses.size() > 1) { + for (std::set >::const_iterator it=txids.begin(); it!=txids.end(); it++) { + result.push_back(it->second); + } + } + + return result; + +} + +UniValue getspentinfo(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 1 || !params[0].isObject()) + throw runtime_error( + "getspentinfo\n" + "\nReturns the txid and index where an output is spent.\n" + "\nArguments:\n" + "{\n" + " \"txid\" (string) The hex string of the txid\n" + " \"index\" (number) The start block height\n" + "}\n" + "\nResult:\n" + "{\n" + " \"txid\" (string) The transaction id\n" + " \"index\" (number) The spending input index\n" + " ,...\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getspentinfo", "'{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}'") + + HelpExampleRpc("getspentinfo", "{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}") + ); + + UniValue txidValue = find_value(params[0].get_obj(), "txid"); + UniValue indexValue = find_value(params[0].get_obj(), "index"); + + if (!txidValue.isStr() || !indexValue.isNum()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid txid or index"); + } + + uint256 txid = ParseHashV(txidValue, "txid"); + int outputIndex = indexValue.get_int(); + + CSpentIndexKey key(txid, outputIndex); + CSpentIndexValue value; + + if (!GetSpentIndex(key, value)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get spent info"); + } + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("txid", value.txid.GetHex())); + obj.push_back(Pair("index", (int)value.inputIndex)); + obj.push_back(Pair("height", value.blockHeight)); + + return obj; +} diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index d2798f10c..48116a3c4 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -165,14 +165,18 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) return ret; } +int32_t KOMODO_LONGESTCHAIN; int32_t komodo_longestchain() { int32_t ht,n=0,num=0,maxheight=0,height = 0; - LOCK(cs_main); vector vstats; - CopyNodeStats(vstats); + { + LOCK(cs_main); + CopyNodeStats(vstats); + } BOOST_FOREACH(const CNodeStats& stats, vstats) { + //fprintf(stderr,"komodo_longestchain iter.%d\n",n); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid,statestats); ht = 0; @@ -191,8 +195,12 @@ int32_t komodo_longestchain() height = ht; } if ( num > (n >> 1) ) + { + KOMODO_LONGESTCHAIN = height; return(height); - else return(0); + } + KOMODO_LONGESTCHAIN = 0; + return(0); } UniValue addnode(const UniValue& params, bool fHelp) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index e918df2c9..8c88abe43 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -65,7 +65,9 @@ UniValue TxJoinSplitToJSON(const CTransaction& tx) { UniValue joinsplit(UniValue::VOBJ); joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); + joinsplit.push_back(Pair("vpub_oldZat", jsdescription.vpub_old)); joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new))); + joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new)); joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex())); @@ -115,9 +117,10 @@ UniValue TxJoinSplitToJSON(const CTransaction& tx) { 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) +void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0) { - entry.push_back(Pair("txid", tx.GetHash().GetHex())); + uint256 txid = tx.GetHash(); + entry.push_back(Pair("txid", txid.GetHex())); entry.push_back(Pair("overwintered", tx.fOverwintered)); entry.push_back(Pair("version", tx.nVersion)); if (tx.fOverwintered) { @@ -139,6 +142,19 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) o.push_back(Pair("asm", txin.scriptSig.ToString())); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); + + // Add address and value info if spentindex enabled + CSpentIndexValue spentInfo; + CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n); + if (GetSpentIndex(spentKey, spentInfo)) { + in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis))); + in.push_back(Pair("valueSat", spentInfo.satoshis)); + if (spentInfo.addressType == 1) { + in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString())); + } else if (spentInfo.addressType == 2) { + in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString())); + } + } } in.push_back(Pair("sequence", (int64_t)txin.nSequence)); vin.push_back(in); @@ -158,10 +174,21 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) out.push_back(Pair("interest", ValueFromAmount(interest))); } out.push_back(Pair("valueZat", txout.nValue)); + out.push_back(Pair("valueSat", txout.nValue)); // [+] Decker out.push_back(Pair("n", (int64_t)i)); UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); out.push_back(Pair("scriptPubKey", o)); + + // Add spent information if spentindex is enabled + CSpentIndexValue spentInfo; + CSpentIndexKey spentKey(txid, i); + if (GetSpentIndex(spentKey, spentInfo)) { + out.push_back(Pair("spentTxId", spentInfo.txid.GetHex())); + out.push_back(Pair("spentIndex", (int)spentInfo.inputIndex)); + out.push_back(Pair("spentHeight", spentInfo.blockHeight)); + } + vout.push_back(out); } entry.push_back(Pair("vout", vout)); @@ -169,18 +196,76 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) UniValue vjoinsplit = TxJoinSplitToJSON(tx); entry.push_back(Pair("vjoinsplit", vjoinsplit)); + if (!hashBlock.IsNull()) { + entry.push_back(Pair("blockhash", hashBlock.GetHex())); + + if (nConfirmations > 0) { + entry.push_back(Pair("height", nHeight)); + entry.push_back(Pair("confirmations", nConfirmations)); + entry.push_back(Pair("time", nBlockTime)); + entry.push_back(Pair("blocktime", nBlockTime)); + } else { + entry.push_back(Pair("height", -1)); + entry.push_back(Pair("confirmations", 0)); + } + } + +} + +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) +{ + uint256 txid = tx.GetHash(); + entry.push_back(Pair("txid", txid.GetHex())); + entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); + entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); + + UniValue vin(UniValue::VARR); + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + UniValue in(UniValue::VOBJ); + if (tx.IsCoinBase()) + in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + else { + in.push_back(Pair("txid", txin.prevout.hash.GetHex())); + in.push_back(Pair("vout", (int64_t)txin.prevout.n)); + UniValue o(UniValue::VOBJ); + o.push_back(Pair("asm", txin.scriptSig.ToString())); + o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + in.push_back(Pair("scriptSig", o)); + } + in.push_back(Pair("sequence", (int64_t)txin.nSequence)); + vin.push_back(in); + } + entry.push_back(Pair("vin", vin)); + + UniValue vout(UniValue::VARR); + for (unsigned int i = 0; i < tx.vout.size(); i++) { + const CTxOut& txout = tx.vout[i]; + UniValue out(UniValue::VOBJ); + out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + out.push_back(Pair("valueSat", txout.nValue)); + out.push_back(Pair("n", (int64_t)i)); + UniValue o(UniValue::VOBJ); + ScriptPubKeyToJSON(txout.scriptPubKey, o, true); + out.push_back(Pair("scriptPubKey", o)); + vout.push_back(out); + } + entry.push_back(Pair("vout", vout)); + if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end() && (*mi).second) { CBlockIndex* pindex = (*mi).second; if (chainActive.Contains(pindex)) { + entry.push_back(Pair("height", pindex->nHeight)); entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight)); entry.push_back(Pair("time", pindex->GetBlockTime())); entry.push_back(Pair("blocktime", pindex->GetBlockTime())); - } - else + } else { + entry.push_back(Pair("height", -1)); entry.push_back(Pair("confirmations", 0)); + } } } } @@ -279,7 +364,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") ); - LOCK(cs_main); uint256 hash = ParseHashV(params[0], "parameter 1"); @@ -289,8 +373,29 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) CTransaction tx; uint256 hashBlock; - if (!GetTransaction(hash, tx, hashBlock, true)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + int nHeight = 0; + int nConfirmations = 0; + int nBlockTime = 0; + + { + LOCK(cs_main); + if (!GetTransaction(hash, tx, hashBlock, true)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + + BlockMap::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) { + CBlockIndex* pindex = (*mi).second; + if (chainActive.Contains(pindex)) { + nHeight = pindex->nHeight; + nConfirmations = 1 + chainActive.Height() - pindex->nHeight; + nBlockTime = pindex->GetBlockTime(); + } else { + nHeight = -1; + nConfirmations = 0; + nBlockTime = pindex->GetBlockTime(); + } + } + } string strHex = EncodeHexTx(tx); @@ -299,7 +404,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", strHex)); - TxToJSON(tx, hashBlock, result); + TxToJSONExpanded(tx, hashBlock, result, nHeight, nConfirmations, nBlockTime); return result; } @@ -417,7 +522,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp) } CBlock block; - if(!ReadBlockFromDisk(block, pblockindex)) + if(!ReadBlockFromDisk(block, pblockindex,1)) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); unsigned int ntxFound = 0; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 716992082..4eb2270fb 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -238,9 +238,11 @@ UniValue help(const UniValue& params, bool fHelp) return tableRPC.help(strCommand); } +extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; UniValue stop(const UniValue& params, bool fHelp) { + char buf[64]; // Accept the deprecated and ignored 'detach' boolean argument if (fHelp || params.size() > 1) throw runtime_error( @@ -248,7 +250,8 @@ UniValue stop(const UniValue& params, bool fHelp) "\nStop Komodo server."); // Shutdown will take long enough that the response should get back StartShutdown(); - return "Komodo server stopping"; + sprintf(buf,"%s Komodo server stopping",ASSETCHAINS_SYMBOL); + return buf; } /** @@ -281,6 +284,8 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getbestblockhash", &getbestblockhash, true }, { "blockchain", "getblockcount", &getblockcount, true }, { "blockchain", "getblock", &getblock, true }, + { "blockchain", "getblockdeltas", &getblockdeltas, false }, + { "blockchain", "getblockhashes", &getblockhashes, true }, { "blockchain", "getblockhash", &getblockhash, true }, { "blockchain", "getblockheader", &getblockheader, true }, { "blockchain", "getchaintips", &getchaintips, true }, @@ -292,11 +297,16 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, { "blockchain", "verifychain", &verifychain, true }, + { "blockchain", "getspentinfo", &getspentinfo, false }, { "blockchain", "paxprice", &paxprice, true }, { "blockchain", "paxpending", &paxpending, true }, { "blockchain", "paxprices", &paxprices, true }, { "blockchain", "notaries", ¬aries, true }, + { "blockchain", "allMoMs", &allMoMs, true }, + { "blockchain", "MoMoMdata", &MoMoMdata, true }, + { "blockchain", "calc_MoM", &calc_MoM, true }, { "blockchain", "height_MoM", &height_MoM, true }, + { "blockchain", "txMoMproof", &txMoMproof, true }, { "blockchain", "minerids", &minerids, true }, { "blockchain", "kvsearch", &kvsearch, true }, { "blockchain", "kvupdate", &kvupdate, true }, @@ -329,6 +339,13 @@ static const CRPCCommand vRPCCommands[] = { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, #endif +/* Address index */ + { "addressindex", "getaddressmempool", &getaddressmempool, true }, + { "addressindex", "getaddressutxos", &getaddressutxos, false }, + { "addressindex", "getaddressdeltas", &getaddressdeltas, false }, + { "addressindex", "getaddresstxids", &getaddresstxids, false }, + { "addressindex", "getaddressbalance", &getaddressbalance, false }, + /* Utility functions */ { "util", "createmultisig", &createmultisig, true }, { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ diff --git a/src/rpcserver.h b/src/rpcserver.h index 1f6bd2f94..ce412cdb9 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -173,6 +173,11 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri extern void EnsureWalletIsUnlocked(); extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp +extern UniValue getaddressmempool(const UniValue& params, bool fHelp); +extern UniValue getaddressutxos(const UniValue& params, bool fHelp); +extern UniValue getaddressdeltas(const UniValue& params, bool fHelp); +extern UniValue getaddresstxids(const UniValue& params, bool fHelp); +extern UniValue getaddressbalance(const UniValue& params, bool fHelp); extern UniValue getpeerinfo(const UniValue& params, bool fHelp); extern UniValue ping(const UniValue& params, bool fHelp); extern UniValue addnode(const UniValue& params, bool fHelp); @@ -271,6 +276,8 @@ extern UniValue getdifficulty(const UniValue& params, bool fHelp); extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); extern UniValue getrawmempool(const UniValue& params, bool fHelp); +extern UniValue getblockhashes(const UniValue& params, bool fHelp); +extern UniValue getblockdeltas(const UniValue& params, bool fHelp); extern UniValue getblockhash(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblock(const UniValue& params, bool fHelp); @@ -280,6 +287,7 @@ extern UniValue verifychain(const UniValue& params, bool fHelp); extern UniValue getchaintips(const UniValue& params, bool fHelp); extern UniValue invalidateblock(const UniValue& params, bool fHelp); extern UniValue reconsiderblock(const UniValue& params, bool fHelp); +extern UniValue getspentinfo(const UniValue& params, bool fHelp); extern UniValue getblocksubsidy(const UniValue& params, bool fHelp); @@ -304,7 +312,11 @@ extern UniValue z_validateaddress(const UniValue& params, bool fHelp); // in rpc extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp); // in rpcdisclosure.cpp +extern UniValue allMoMs(const UniValue& params, bool fHelp); +extern UniValue MoMoMdata(const UniValue& params, bool fHelp); +extern UniValue calc_MoM(const UniValue& params, bool fHelp); 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); diff --git a/src/script/cc.cpp b/src/script/cc.cpp new file mode 100644 index 000000000..965fae4b0 --- /dev/null +++ b/src/script/cc.cpp @@ -0,0 +1,137 @@ +#include "cryptoconditions/include/cryptoconditions.h" +#include "script/cc.h" + + +bool IsCryptoConditionsEnabled() +{ + return 0 != ASSETCHAINS_CC; +} + + +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; +} + + +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::vector code) +{ + CC *cond = cc_new(CC_Eval); + cond->code = (unsigned char*) malloc(code.size()); + memcpy(cond->code, code.data(), code.size()); + cond->codeLength = code.size(); + return cond; +} + + +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[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; +} + + +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/script/cc.h b/src/script/cc.h new file mode 100644 index 000000000..dc019beba --- /dev/null +++ b/src/script/cc.h @@ -0,0 +1,83 @@ +#ifndef SCRIPT_CC_H +#define SCRIPT_CC_H + +#include "pubkey.h" +#include "script/script.h" +#include "cryptoconditions/include/cryptoconditions.h" + + +extern uint32_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 + */ +bool IsSupportedCryptoCondition(const CC *cond); + + +/* + * Check if crypto condition is signed. Can only accept signed conditions. + */ +bool IsSignedCryptoCondition(const CC *cond); + + +/* + * Construct crypto conditions + */ +CC* CCNewPreimage(std::vector preimage); +CC* CCNewEval(std::vector code); +CC* CCNewSecp256k1(CPubKey k); +CC* CCNewThreshold(int t, std::vector v); + + +/* + * 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 /* SCRIPT_CC_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index d01ebb07c..5438102c3 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; @@ -938,6 +940,37 @@ bool EvalScript( } break; + case OP_CHECKCRYPTOCONDITION: + case OP_CHECKCRYPTOCONDITIONVERIFY: + { + if (!IsCryptoConditionsEnabled()) { + goto INTERPRETER_DEFAULT; + } + + if (stack.size() < 2) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + int fResult = checker.CheckCryptoCondition(stacktop(-1), stacktop(-2), script, consensusBranchId); + if (fResult == -1) { + return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); + } + + popstack(stack); + popstack(stack); + + stack.push_back(fResult == 1 ? vchTrue : vchFalse); + + if (opcode == OP_CHECKCRYPTOCONDITIONVERIFY) + { + if (fResult == 1) + popstack(stack); + else + return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_VERIFY); + } + } + break; + +INTERPRETER_DEFAULT: default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } @@ -1253,6 +1286,49 @@ bool TransactionSignatureChecker::CheckSig( return true; } + +int TransactionSignatureChecker::CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const +{ + // 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, nHashType, amount, consensusBranchId, this->txdata); + } 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(), eval, (void*)this); + cc_free(cond); + return out; +} + + +int TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const +{ + fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n"); + return 0; +} + + bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const { // There are two times of nLockTime: lock-by-blockheight @@ -1296,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, @@ -1311,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/interpreter.h b/src/script/interpreter.h index 7f2956eec..7aa0d5099 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -8,6 +8,7 @@ #include "script_error.h" #include "primitives/transaction.h" +#include "script/cc.h" #include #include @@ -127,18 +128,26 @@ public: return false; } + virtual int CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; 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: @@ -146,6 +155,12 @@ 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; + int CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const; + virtual int CheckEvalCondition(const CC *cond) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.cpp b/src/script/script.cpp index 24a73d637..a130df4aa 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -7,6 +7,8 @@ #include "tinyformat.h" #include "utilstrencodings.h" +#include "script/cc.h" +#include "cryptoconditions/include/cryptoconditions.h" namespace { inline std::string ValueString(const std::vector& vch) @@ -138,6 +140,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"; // expansion case OP_NOP1 : return "OP_NOP1"; @@ -211,6 +216,17 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } +bool CScript::IsPayToPublicKeyHash() const +{ + // Extra-fast test for pay-to-pubkey-hash CScripts: + return (this->size() == 25 && + (*this)[0] == OP_DUP && + (*this)[1] == OP_HASH160 && + (*this)[2] == 0x14 && + (*this)[23] == OP_EQUALVERIFY && + (*this)[24] == OP_CHECKSIG); +} + bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: @@ -220,6 +236,36 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::IsPayToCryptoCondition() const +{ + const_iterator pc = this->begin(); + vector data; + 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::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 out = IsSupportedCryptoCondition(cond); + cc_free(cond); + return out; +} + bool CScript::IsPushOnly() const { const_iterator pc = begin(); diff --git a/src/script/script.h b/src/script/script.h index e0e89185f..e5328cf06 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; @@ -154,6 +157,8 @@ enum opcodetype OP_CHECKSIGVERIFY = 0xad, OP_CHECKMULTISIG = 0xae, OP_CHECKMULTISIGVERIFY = 0xaf, + OP_CHECKCRYPTOCONDITION = 0xcc, + OP_CHECKCRYPTOCONDITIONVERIFY = 0xcd, // expansion OP_NOP1 = 0xb0, @@ -168,13 +173,13 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, - // template matching params OP_SMALLDATA = 0xf9, OP_SMALLINTEGER = 0xfa, OP_PUBKEYS = 0xfb, OP_PUBKEYHASH = 0xfd, OP_PUBKEY = 0xfe, + OP_CRYPTOCONDITION = 0xfc, OP_INVALIDOPCODE = 0xff, }; @@ -561,7 +566,11 @@ public: */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + bool IsPayToPublicKeyHash() const; + 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/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 bb10b8a29..35c8fbfd8 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -52,7 +52,11 @@ typedef enum ScriptError_t /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, - SCRIPT_ERR_ERROR_COUNT + SCRIPT_ERR_ERROR_COUNT, + + /* crypto-condition script errors */ + SCRIPT_ERR_CRYPTOCONDITION_VERIFY, + SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT } ScriptError; #define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT diff --git a/src/script/sigcache.cpp b/src/script/serverchecker.cpp similarity index 68% rename from src/script/sigcache.cpp rename to src/script/serverchecker.cpp index 35b9f0e03..4de69001a 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 "script/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,17 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector + +class CPubKey; + +class ServerTransactionSignatureChecker : public TransactionSignatureChecker +{ +private: + bool store; + +public: + 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(const CC *cond) 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 71838853d..bdba59eca 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 "script/cc.h" #include @@ -68,6 +69,17 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector inline void ser_writedata32(Stream &s, uint32_t obj) obj = htole32(obj); s.write((char*)&obj, 4); } +template inline void ser_writedata32be(Stream &s, uint32_t obj) +{ + obj = htobe32(obj); + s.write((char*)&obj, 4); +} template inline void ser_writedata64(Stream &s, uint64_t obj) { obj = htole64(obj); @@ -118,6 +123,12 @@ template inline uint32_t ser_readdata32(Stream &s) s.read((char*)&obj, 4); return le32toh(obj); } +template inline uint32_t ser_readdata32be(Stream &s) +{ + uint32_t obj; + s.read((char*)&obj, 4); + return be32toh(obj); +} template inline uint64_t ser_readdata64(Stream &s) { uint64_t obj; diff --git a/src/snark/AUTHORS b/src/snark/AUTHORS index 1b2d7a247..cdc8d66af 100644 --- a/src/snark/AUTHORS +++ b/src/snark/AUTHORS @@ -17,3 +17,6 @@ External contributors: Tadanori TERUYA Sean Bowe Daira Hopwood + @mugatu on forum.z.cash + David Mercer + Joshua Yabut diff --git a/src/snark/Makefile b/src/snark/Makefile index b865f992f..17dcfdc6e 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -6,6 +6,13 @@ #* @copyright MIT license (see LICENSE file) #*******************************************************************************/ +# Determine building operating system +ifeq ($(OS),Windows_NT) + uname_S := Windows +else + uname_S := $(shell uname -s) +endif + # To override these, use "make OPTFLAGS=..." etc. CURVE = BN128 OPTFLAGS = -O2 -march=native -mtune=native @@ -106,18 +113,9 @@ EXECUTABLES_WITH_GTEST = EXECUTABLES_WITH_SUPERCOP = \ libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark -GTEST_TESTS = libsnark/gtests +GTEST_TESTS = -GTEST_SRCS = \ - libsnark/algebra/curves/tests/test_bilinearity.cpp \ - libsnark/algebra/curves/tests/test_groups.cpp \ - libsnark/algebra/fields/tests/test_bigint.cpp \ - libsnark/algebra/fields/tests/test_fields.cpp \ - libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ - libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ - libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp \ - libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ - libsnark/gtests.cpp +GTEST_SRCS = DOCS = README.html @@ -175,6 +173,7 @@ all: \ $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST) $(GTEST_TESTS)) \ $(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \ $(EXECUTABLES) \ + $(LIBSNARK_A) \ $(if $(NO_DOCS),,doc) doc: $(DOCS) diff --git a/src/snark/README.md b/src/snark/README.md index 89183b43a..d5aa34006 100644 --- a/src/snark/README.md +++ b/src/snark/README.md @@ -14,7 +14,7 @@ Copyright (c) 2012-2014 SCIPR Lab and contributors (see [AUTHORS] file). [TOC]