diff --git a/contrib/hush_supply b/contrib/hush_supply index 92e917055..fcf4460dc 100755 --- a/contrib/hush_supply +++ b/contrib/hush_supply @@ -1,33 +1,218 @@ #!/usr/bin/env perl -# Copyright 2019 The Hush developers +# Copyright 2019-2020 The Hush developers # Released under the GPLv3 use warnings; use strict; + my $supply = 0.0; -my $block = 0; -my $satoshis = 100_000_000; -my $amount = int(12.5*$satoshis); +my $block = 0; # Block 0 in Hush Smart chains is the BTC genesis block +my $puposhis = 100_000_000; +my $subsidy0 = 1_250_000_000; my $halvings = 0; +my $initial = 6178674 * $puposhis; +my $interval = 1_680_000; # ~4 years of 75s blocks +my $stop = shift || -1; +my $totalfr = 0; # total paid out to FR address -# Usage: ./hush_supply &> supply.csv -# Use this to calculate when supply hits a certain value -#while ($supply <= 21_000_000*$satoshis) { -# Use this to calculate when block rewards end -while ($halvings <= 64 && $amount >= 1) { - $block++; - if ($block < 5) { - $amount = 40_000 * $satoshis; - } else { - # Halving every 840000 blocks - if ($block % 840_000 == 0) { - $amount /= 2; - $halvings++; - } - $amount = int(12.5*$satoshis) / (2**$halvings); - } - $supply += $amount; - # block, current supply, block reward amount, number of halvings - printf "%s,%s,%s,%s\n", $block,$supply / $satoshis, $amount / $satoshis, $halvings; +if ($stop eq 'help' or $stop =~ m/-h/) { + die < supply.csv + ./hush_supply HEIGHT &> supply.csv # stop at HEIGHT +# This will generate CSV in the form of: +# block, supply, reward, subsidy, fr, totalfr, halvings +HELP +} + + +printf "# block, supply, reward, subsidy, fr, totalfr, halvings\n"; + +# Block Reward Amounts in puposhis +# The non-integral amounts cannot be represented exactly +# 12.5 * 100000000 = 1250000000 +# 12.5 * 100000000 / 2 = 625000000 +# 12.5 * 100000000 / 4 = 312500000 +# 12.5 * 100000000 / 8 = 156250000 +# 12.5 * 100000000 / 16 = 78125000 +# 12.5 * 100000000 / 32 = 39062500 +# 12.5 * 100000000 / 64 = 19531250 +# 12.5 * 100000000 / 128 = 9765625 +# 12.5 * 100000000 / 256 = 4882812.5 +# 12.5 * 100000000 / 512 = 2441406.25 +# 12.5 * 100000000 / 1024 = 1220703.125 +# 12.5 * 100000000 / 2048 = 610351.5625 +# 12.5 * 100000000 / 4096 = 305175.78125 +# 12.5 * 100000000 / 8192 = 152587.890625 +# 12.5 * 100000000 / 16384 = 76293.9453125 +# 12.5 * 100000000 / 32768 = 38146.97265625 +# 12.5 * 100000000 / 65536 = 19073.486328125 + +# Hush Halving Heights and Block Rewards +# 1,12500000000,340000 +# 2,312500000,2020000 +# 3,156250000,3700000 +# 4,78125000,5380000 +# 5,39062500,7060000 +# 6,19531250,8740000 +# 7,9765625,10420000 +# 8,4882812,12100000 +# 9,2441406,13780000 +# 10,1220703,15460000 +# 11,610351,17140000 +# 12,305175,18820000 +# 13,152587,20500000 +# 14,76293,22180000 +# 15,38146,23860000 +# 16,19073,25540000 +# 17,9536,27220000 +# 18,4768,28900000 +# 19,2384,30580000 +# 20,1192,32260000 +# 21,596,33940000 +# 22,298,35620000 +# 23,149,37300000 +# 24,74,38980000 +# 25,37,40660000 +# 26,18,42340000 +# 27,9,44020000 +# 28,4,45700000 +# 29,2,47380000 +# 30,1,49060000 +# 31,0,50740000 + + +sub hush_block_reward +{ + my $reward = 0; + my $height = shift; + my $halvings = 0; + + if ($height >= 50740000) { + $reward = 0; + $halvings = 31; + } elsif ($height >= 49060000) { + $reward = 1; + $halvings = 30; + } elsif ($height >= 47380000) { + $reward = 1; + $halvings = 29; + } elsif ($height >= 45700000) { + $reward = 2; + $halvings = 28; + } elsif ($height >= 44020000) { + $reward = 4; + $halvings = 27; + } elsif ($height >= 42340000) { + $reward = 9; + $halvings = 26; + } elsif ($height >= 40660000) { + $reward = 18; + $halvings = 25; + } elsif ($height >= 38980000) { + $reward = 37; + $halvings = 24; + } elsif ($height >= 37380000) { + $reward = 74; + $halvings = 23; + } elsif ($height >= 35620000) { + $reward = 149; + $halvings = 22; + } elsif ($height >= 33940000) { + $reward = 298; + $halvings = 21; + } elsif ($height >= 32260001) { + $reward = 596; + $halvings = 20; + } elsif ($height >= 30580000) { + $reward = 1192; + $halvings = 19; + } elsif ($height >= 28900000) { + $reward = 2384; + $halvings = 18; + } elsif ($height >= 27220000) { + $reward = 4768; + $halvings = 17; + } elsif ($height >= 25540000) { + $reward = 9536; + $halvings = 16; + } elsif ($height >= 23860000) { + $reward = 19073; # 0.486328125 deviation + $halvings = 15; + } elsif ($height >= 22180000) { + $reward = 38146; # 0.97265625 deviation + $halvings = 14; + } elsif ($height >= 20500000) { + $reward = 76293; # 0.9453125 deviation + $halvings = 13; + } elsif ($height >= 18820000) { + $reward = 152587; # 0.890625 deviation + $halvings = 12; + } elsif ($height >= 17140000) { + $reward = 305175; # 0.78125sat deviation + $halvings = 11; + } elsif ($height >= 15460000) { + $reward = 610351; # 0.5625sat deviation + $halvings = 10; + } elsif ($height >= 13780000) { + $reward = 1220703; # 0.125sat deviation + $halvings = 9 + } elsif ($height >= 12100000) { + $reward = 2441406; # 0.25sat deviation + $halvings = 8 + } elsif ($height >= 10420000) { + $reward = 4882812; # 0.5sat deviation + $halvings = 7; + } elsif ($height >= 8740000) { + $reward = 9765625; # last exact reward + $halvings = 6; + } elsif ($height >= 7060000) { + $reward = 19531250; # 0.1953125 HUSH + $halvings = 5; + } elsif ($height >= 5380000) { + $reward = 39062500; # 0.390625 HUSH + $halvings = 4; + } elsif ($height >= 3700000) { + $reward = 78125000; # 0.78125 HUSH + $halvings = 3; + } elsif ($height >= 2020000) { + $reward = 156250000; # 1.5625 HUSH + $halvings = 2; + } elsif ($height >= 340000) { + $reward = 312500000; # 3.125 HUSH + $halvings = 1; + } elsif ($height >= 128) { + $reward = 1250000000; # 12.5 HUSH + } + + return ($reward,$halvings); +} + +# Block reward is 0 at the 31st halving +while ($halvings <= 30) { + $block++; + my ($reward,$halvings) = hush_block_reward($block); + my $fr = int($reward / 10); + my $subsidy = $reward - $fr; + + if($block == 1) { + # initial airdrop of funds from HUSH v2 network @ Block 500000 + $reward = $initial; + $subsidy= $reward; + $fr = 0; + } + $supply += $reward; + $totalfr += $fr; + + # all values in puposhis + # block, current supply, block reward amount, fr, totalfr, number of halvings + printf "%d,%d,%d,%d,%d,%d,%d\n", $block, $supply, $reward, $subsidy, $fr, $totalfr, $halvings; + exit(0) if $block == $stop; + exit(0) if ($block > 128 && $reward == 0); + exit(-1) if ($supply >= 21_000_000*$puposhis); } diff --git a/contrib/hush_supply_old b/contrib/hush_supply_old new file mode 100755 index 000000000..674424073 --- /dev/null +++ b/contrib/hush_supply_old @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +# Copyright 2019-2020 The Hush developers +# Released under the GPLv3 +use warnings; +use strict; + +my $supply = 0.0; +my $block = 0; +my $satoshis = 100_000_000; +my $amount = int(12.5*$satoshis); +my $halvings = 0; + +# Usage: ./hush_supply &> supply.csv + +# Use this to calculate when supply hits a certain value +#while ($supply <= 21_000_000*$satoshis) { +# Use this to calculate when block rewards end +while ($halvings <= 64 && $amount >= 1) { + $block++; + if ($block < 5) { + $amount = 40_000 * $satoshis; + } else { + # Halving every 840000 blocks + if ($block % 840_000 == 0) { + $amount /= 2; + $halvings++; + } + $amount = int(12.5*$satoshis) / (2**$halvings); + } + $supply += $amount; + # block, current supply, block reward amount, number of halvings + printf "%s,%s,%s,%s\n", $block,$supply / $satoshis, $amount / $satoshis, $halvings; +} diff --git a/doc/man/hush-cli.1 b/doc/man/hush-cli.1 index 3e1ca3616..d091ac49f 100644 --- a/doc/man/hush-cli.1 +++ b/doc/man/hush-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSH-CLI "1" "July 2020" "hush-cli v3.5.0" "User Commands" +.TH HUSH-CLI "1" "September 2020" "hush-cli v3.5.0" "User Commands" .SH NAME hush-cli \- manual page for hush-cli v3.5.0 .SH DESCRIPTION -Komodo RPC client version v3.5.0\-beta6\-a59803c32\-dirty +Komodo RPC client version v3.5.0\-beta6\-fab0f9494\-dirty .PP In order to ensure you are adequately protecting your privacy when using Hush, please see . @@ -71,7 +71,7 @@ Timeout in seconds during HTTP requests, or 0 for no timeout. (default: Read extra arguments from standard input, one per line until EOF/Ctrl\-D (recommended for sensitive information such as passphrases) .SH COPYRIGHT -Hush Daemon version v3.5.0-beta6-a59803c32-dirty +Hush Daemon version v3.5.0-beta6-fab0f9494-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/doc/man/hush-tx.1 b/doc/man/hush-tx.1 index fa3162fda..99212c29b 100644 --- a/doc/man/hush-tx.1 +++ b/doc/man/hush-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSH-TX "1" "July 2020" "hush-tx v3.5.0" "User Commands" +.TH HUSH-TX "1" "September 2020" "hush-tx v3.5.0" "User Commands" .SH NAME hush-tx \- manual page for hush-tx v3.5.0 .SH DESCRIPTION -Hush komodo\-tx utility version v3.5.0\-beta6\-a59803c32\-dirty +Hush komodo\-tx utility version v3.5.0\-beta6\-fab0f9494\-dirty .SS "Usage:" .TP komodo\-tx [options] [commands] @@ -84,7 +84,7 @@ set=NAME:JSON\-STRING .IP Set register NAME to given JSON\-STRING .SH COPYRIGHT -Hush Daemon version v3.5.0-beta6-a59803c32-dirty +Hush Daemon version v3.5.0-beta6-fab0f9494-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/doc/man/hushd.1 b/doc/man/hushd.1 index 370986f0f..1d4d70cc3 100644 --- a/doc/man/hushd.1 +++ b/doc/man/hushd.1 @@ -1,10 +1,10 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSHD "1" "July 2020" "hushd v3.5.0" "User Commands" +.TH HUSHD "1" "September 2020" "hushd v3.5.0" "User Commands" .SH NAME hushd \- manual page for hushd v3.5.0 .SH DESCRIPTION Found binary: ./komodod -Hush Daemon version v3.5.0\-beta6\-a59803c32\-dirty +Hush Daemon version v3.5.0\-beta6\-fab0f9494\-dirty .PP In order to ensure you are adequately protecting your privacy when using Hush, please see . @@ -114,6 +114,11 @@ Create new files with system default permissions, instead of umask 077 Maintain a full transaction index, used by the getrawtransaction rpc call (default: 0) .HP +\fB\-txsend=\fR +.IP +Execute command to send a transaction instead of broadcasting (%s in cmd +is replaced by transaction hex) +.HP \fB\-addressindex\fR .IP Maintain a full address index, used to query for the balance, txids and @@ -346,7 +351,8 @@ Upgrade wallet to latest format on startup .HP \fB\-wallet=\fR .IP -Specify wallet file (within data directory) (default: wallet.dat) +Specify wallet file absolute path or a path relative to the data +directory (default: wallet.dat) .HP \fB\-walletbroadcast\fR .IP @@ -639,7 +645,7 @@ Starting supply, default is 0 .IP Enforce transaction\-rate limit, default 0 .SH COPYRIGHT -Hush Daemon version v3.5.0-beta6-a59803c32-dirty +Hush Daemon version v3.5.0-beta6-fab0f9494-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/qa/rpc-tests/feature_walletfile.py b/qa/rpc-tests/feature_walletfile.py new file mode 100755 index 000000000..f38403574 --- /dev/null +++ b/qa/rpc-tests/feature_walletfile.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Copyright (c) 2019-2020 The Hush developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://www.opensource.org/licenses/mit-license.php +"""Test wallet file location.""" + +import os + +from test_framework.util import start_node, stop_node, assert_start_raises_init_error + +from test_framework.test_framework import BitcoinTestFramework + +class WalletFileTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + + def run_test(self): + # test default wallet location + assert os.path.isfile(os.path.join(self.options.tmpdir, "node0", "regtest", "wallet.dat")) + + # test alternative wallet file name in datadir + stop_node(self.nodes[0], 0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-wallet=altwallet.dat"]) + assert os.path.isfile(os.path.join(self.options.tmpdir, "node0", "regtest", "altwallet.dat")) + + # test wallet file outside datadir + tempname = os.path.join(self.options.tmpdir, "outsidewallet.dat") + stop_node(self.nodes[0], 0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-wallet=%s" % tempname]) + assert os.path.isfile(tempname) + + # test the case where absolute path does not exist + assert not os.path.isdir("/this_directory_must_not_exist") + invalidpath = os.path.join("/this_directory_must_not_exist/", "foo.dat") + stop_node(self.nodes[0], 0) + assert_start_raises_init_error(0, "-wallet=%s" % invalidpath, + "Error: Absolute path %s does not exist") + + # relative path does not exist + invalidpath = os.path.join("wallet", "foo.dat") + assert_start_raises_init_error(0, "-wallet=%s" % invalidpath, + "Error: Relative path %s does not exist") + + # create dir and retry + os.mkdir(os.path.join(self.options.tmpdir, "node0", "regtest", "wallet")) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-wallet=%s" % invalidpath]) + +if __name__ == '__main__': + WalletFileTest().main() diff --git a/src/Makefile.am b/src/Makefile.am index 88e33df95..dc66cb4a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -462,7 +462,7 @@ libbitcoin_server_a_SOURCES += rpc/testtransactions.cpp endif -# cli: zcash-cli +# cli libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ diff --git a/src/addressindex.h b/src/addressindex.h index 643f06e13..d22426ed6 100644 --- a/src/addressindex.h +++ b/src/addressindex.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -79,4 +80,4 @@ struct CMempoolAddressDeltaKeyCompare } }; -#endif // BITCOIN_ADDRESSINDEX_H \ No newline at end of file +#endif // BITCOIN_ADDRESSINDEX_H diff --git a/src/alert.h b/src/alert.h index 16204c9c5..d8d762b00 100644 --- a/src/alert.h +++ b/src/alert.h @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/alertkeys.h b/src/alertkeys.h index 106576add..1c4bcbc2c 100644 --- a/src/alertkeys.h +++ b/src/alertkeys.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -16,7 +17,7 @@ #ifndef BITCOIN_ALERTKEYS_H #define BITCOIN_ALERTKEYS_H -// REMINDER: DO NOT COMMIT YOUR PRIVATE KEYS TO THE GIT REPOSITORY! +// REMINDER: DO NOT COMMIT YOUR PRIVATE KEYS TO THE GIT REPOSITORY, lulz const char* pszPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; const char* pszTestNetPrivKey = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; diff --git a/src/arith_uint256.h b/src/arith_uint256.h index b51f82f14..f7bc8a585 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/asyncrpcoperation.h b/src/asyncrpcoperation.h index 3fe966977..5dc102366 100644 --- a/src/asyncrpcoperation.h +++ b/src/asyncrpcoperation.h @@ -1,4 +1,5 @@ // Copyright (c) 2016 The Zcash developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/asyncrpcqueue.h b/src/asyncrpcqueue.h index 0d228564f..32e091aff 100644 --- a/src/asyncrpcqueue.h +++ b/src/asyncrpcqueue.h @@ -1,4 +1,5 @@ // Copyright (c) 2016 The Zcash developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/clientversion.h b/src/clientversion.h index fea7d0b05..ed24867a1 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -35,7 +35,7 @@ #define CLIENT_VERSION_MAJOR 3 #define CLIENT_VERSION_MINOR 5 #define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 5 +#define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/coincontrol.h b/src/coincontrol.h index 02d487a4c..2daa95919 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -1,4 +1,5 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/bip39/Makefile b/src/crypto/bip39/Makefile new file mode 100644 index 000000000..4a5dec3d8 --- /dev/null +++ b/src/crypto/bip39/Makefile @@ -0,0 +1,66 @@ +CC ?= gcc + +OPTFLAGS ?= -O3 -g + +CFLAGS += $(OPTFLAGS) \ + -std=gnu99 \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Werror + +VALGRIND ?= 1 + +CFLAGS += -I. +CFLAGS += -DVALGRIND=$(VALGRIND) +CFLAGS += $(shell pkg-config --cflags openssl) + +# disable certain optimizations and features when small footprint is required +ifdef SMALL +CFLAGS += -DUSE_PRECOMPUTED_CP=0 +endif + +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c base32.c +#SRCS += address.c +#SRCS += script.c +SRCS += ripemd160.c +SRCS += sha2.c +SRCS += sha3.c +SRCS += hasher.c +#SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c +#SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c +#SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c +#SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +#SRCS += blake256.c +#SRCS += blake2b.c blake2s.c +#SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c +SRCS += memzero.c + +OBJS = $(SRCS:.c=.o) + +TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm +TESTSSLLIBS = $(shell pkg-config --libs openssl) + +all: hasher.o bip39.o memzero.o pbkdf2.o base58.o base32.o + @echo "Created object files, donezo" + +%.o: %.c %.h options.h + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -rf *.o + diff --git a/src/crypto/bip39/README.md b/src/crypto/bip39/README.md new file mode 100644 index 000000000..b8e03fc93 --- /dev/null +++ b/src/crypto/bip39/README.md @@ -0,0 +1,3 @@ +# trezor-firmware bip39 + +Imported from https://github.com/trezor/trezor-firmware/commit/047fcffde1f8530d3aee279b731e5e5f5901590a diff --git a/src/crypto/bip39/base32.c b/src/crypto/bip39/base32.c new file mode 100644 index 000000000..06760ccae --- /dev/null +++ b/src/crypto/bip39/base32.c @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * 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, E1PRESS + * 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. + */ + +#include "base32.h" + +#include + +const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; + +static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet); +static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out); + +static inline int base32_encode_character(uint8_t decoded, const char *alphabet); +static inline int base32_decode_character(char encoded, const char *alphabet); + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { + size_t length = base32_encoded_length(inlen); + if (outlen <= length) { + return NULL; + } + + base32_encode_unsafe(in, inlen, (uint8_t *) out); + + for (size_t i = 0; i < length; i++) { + int ret = base32_encode_character(out[i], alphabet); + + if (ret == -1) { + return false; + } else { + out[i] = ret; + } + } + + out[length] = '\0'; + return &out[length]; +} + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) { + size_t length = base32_decoded_length(inlen); + if (outlen < length) { + return NULL; + } + + if (!base32_decode_unsafe((uint8_t *) in, inlen, (uint8_t *) out, alphabet)) { + return NULL; + } + + return &out[length]; +} + +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } + + if (remainder) base32_5to8(&in[i], remainder, &out[j]); +} + +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 8, j += 5) { + if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } + + if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } + + return true; +} + +size_t base32_encoded_length(size_t inlen) { + uint8_t remainder = inlen % 5; + + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; +} + +size_t base32_decoded_length(size_t inlen) { + uint8_t remainder = inlen % 8; + + return (inlen / 8) * 5 + (remainder * 5) / 8; +} + +void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if (length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if (length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if (length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if (length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } +} + +bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet) { + if (length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } + + if (alphabet) { + uint8_t decoded[length]; + + for (size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); + + if (ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } + + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } + + return true; +} + +void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if (length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if (length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if (length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if (length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } +} + +int base32_encode_character(uint8_t decoded, const char *alphabet) { + if (decoded >> 5) { + return -1; + } + + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; +} + +int base32_decode_character(char encoded, const char *alphabet) { + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if (encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if (encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char *occurrence = strchr(alphabet, encoded); + + if (occurrence) { + return occurrence - alphabet; + } else { + return -1; + } +} diff --git a/src/crypto/bip39/base32.h b/src/crypto/bip39/base32.h new file mode 100644 index 000000000..250997967 --- /dev/null +++ b/src/crypto/bip39/base32.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * 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 __BASE32_H__ +#define __BASE32_H__ + +#include +#include +#include + +extern const char *BASE32_ALPHABET_RFC4648; + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet); +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet); + +size_t base32_encoded_length(size_t inlen); +size_t base32_decoded_length(size_t inlen); + +#endif diff --git a/src/crypto/bip39/base58.c b/src/crypto/bip39/base58.c new file mode 100644 index 000000000..cd74617b8 --- /dev/null +++ b/src/crypto/bip39/base58.c @@ -0,0 +1,285 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +#include +#include +#include +#include "base58.h" +#include "sha2.h" +#include "ripemd160.h" +#include "memzero.h" + +const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const int8_t b58digits_map[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, + -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, + 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, + -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, + 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, +}; + +bool b58tobin(void *bin, size_t *binszp, const char *b58) +{ + size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + + const unsigned char *b58u = (const unsigned char*)b58; + unsigned char *binu = bin; + size_t outisz = (binsz + 3) / 4; + uint32_t outi[outisz]; + uint64_t t; + uint32_t c; + size_t i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + size_t b58sz; + + b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) + ++zerocount; + + for ( ; i < b58sz; ++i) + { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--; ) + { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + switch (bytesleft) { + case 3: + *(binu++) = (outi[0] & 0xff0000) >> 16; + //-fallthrough + case 2: + *(binu++) = (outi[0] & 0xff00) >> 8; + //-fallthrough + case 1: + *(binu++) = (outi[0] & 0xff); + ++j; + //-fallthrough + default: + break; + } + + for (; j < outisz; ++j) + { + *(binu++) = (outi[j] >> 0x18) & 0xff; + *(binu++) = (outi[j] >> 0x10) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; + } + + // Count canonical base58 byte count + binu = bin; + for (i = 0; i < binsz; ++i) + { + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } + break; + } + --*binszp; + } + *binszp += zerocount; + + return true; +} + +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + hasher_Raw(hasher_type, bin, binsz - 4, buf); + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) +{ + const uint8_t *bin = data; + int carry; + ssize_t i, j, high, zcount = 0; + size_t size; + + while (zcount < (ssize_t)binsz && !bin[zcount]) + ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) + { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) + { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + } + } + + for (j = 0; j < (ssize_t)size && !buf[j]; ++j); + + if (*b58sz <= zcount + size - j) + { + *b58sz = zcount + size - j + 1; + return false; + } + + if (zcount) + memset(b58, '1', zcount); + for (i = zcount; j < (ssize_t)size; ++i, ++j) + b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; +} + +int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + hasher_Raw(hasher_type, data, datalen, hash); + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen) +{ + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58check(nd, res, hasher_type, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} + +#if USE_GRAPHENE +int b58gphcheck(const void *bin, size_t binsz, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58gph_decode_check(const char *str, uint8_t *data, int datalen) +{ + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58gphcheck(nd, res, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} +#endif diff --git a/src/crypto/bip39/base58.h b/src/crypto/bip39/base58.h new file mode 100644 index 000000000..0fa9167bf --- /dev/null +++ b/src/crypto/bip39/base58.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __BASE58_H__ +#define __BASE58_H__ + +#include +#include +#include "hasher.h" +#include "options.h" + +extern const char b58digits_ordered[]; +extern const int8_t b58digits_map[]; + +int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); + +// Private +bool b58tobin(void *bin, size_t *binszp, const char *b58); +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str); +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); + +#if USE_GRAPHENE +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize); +int base58gph_decode_check(const char *str, uint8_t *data, int datalen); +int b58gphcheck(const void *bin, size_t binsz, const char *base58str); +#endif + +#endif diff --git a/src/crypto/bip39/bip32.h b/src/crypto/bip39/bip32.h new file mode 100644 index 000000000..c0a04b5f8 --- /dev/null +++ b/src/crypto/bip39/bip32.h @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __BIP32_H__ +#define __BIP32_H__ + +#include +#include +#include +#include "ecdsa.h" +#include "ed25519-donna/ed25519.h" +#include "options.h" + +typedef struct { + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 + + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; + HasherType hasher_script; +} curve_info; + +typedef struct { + uint32_t depth; + uint32_t child_num; + uint8_t chain_code[32]; + + uint8_t private_key[32]; + uint8_t private_key_extension[32]; + + uint8_t public_key[33]; + const curve_info *curve; +} HDNode; + +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); + +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); + +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out); + +#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) + +int hdnode_private_ckd(HDNode *inout, uint32_t i); + +#if USE_CARDANO +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out); +#endif + +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); + +int hdnode_public_ckd(HDNode *inout, uint32_t i); + +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat); + +#if USE_BIP32_CACHE +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); +#endif + +uint32_t hdnode_fingerprint(HDNode *node); + +void hdnode_fill_public_key(HDNode *node); + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); +int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +#endif + +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); + +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); + +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); + +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); + +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint); + +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); + +const curve_info *get_curve_by_name(const char *curve_name); + +#endif diff --git a/src/crypto/bip39/bip39.c b/src/crypto/bip39/bip39.c new file mode 100644 index 000000000..76e0792ad --- /dev/null +++ b/src/crypto/bip39/bip39.c @@ -0,0 +1,283 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +#include +#include + +#include "bip39.h" +#include "bip39_english.h" +#include "hmac.h" +#include "memzero.h" +#include "options.h" +#include "pbkdf2.h" +#include "rand.h" +#include "sha2.h" + +#if USE_BIP39_CACHE + +int BIP39_WORDS = 2048; + +static int bip39_cache_index = 0; + +static CONFIDENTIAL struct { + bool set; + char mnemonic[256]; + char passphrase[64]; + uint8_t seed[512 / 8]; +} bip39_cache[BIP39_CACHE_SIZE]; + +#endif + +const char *mnemonic_generate(int strength) { + if (strength % 32 || strength < 128 || strength > 256) { + return 0; + } + uint8_t data[32] = {0}; + random_buffer(data, 32); + const char *r = mnemonic_from_data(data, strength / 8); + memzero(data, sizeof(data)); + return r; +} + +static CONFIDENTIAL char mnemo[24 * 10]; + +const char *mnemonic_from_data(const uint8_t *data, int len) { + if (len % 4 || len < 16 || len > 32) { + return 0; + } + + uint8_t bits[32 + 1] = {0}; + + sha256_Raw(data, len, bits); + // checksum + bits[len] = bits[0]; + // data + memcpy(bits, data, len); + + int mlen = len * 3 / 4; + + int i = 0, j = 0, idx = 0; + char *p = mnemo; + for (i = 0; i < mlen; i++) { + idx = 0; + for (j = 0; j < 11; j++) { + idx <<= 1; + idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; + } + strcpy(p, wordlist[idx]); + p += strlen(wordlist[idx]); + *p = (i < mlen - 1) ? ' ' : 0; + p++; + } + memzero(bits, sizeof(bits)); + + return mnemo; +} + +void mnemonic_clear(void) { memzero(mnemo, sizeof(mnemo)); } + +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) { + if (!mnemonic) { + return 0; + } + + uint32_t i = 0, n = 0; + + while (mnemonic[i]) { + if (mnemonic[i] == ' ') { + n++; + } + i++; + } + n++; + + // check number of words + if (n != 12 && n != 18 && n != 24) { + return 0; + } + + char current_word[10] = {0}; + uint32_t j = 0, k = 0, ki = 0, bi = 0; + uint8_t bits[32 + 1] = {0}; + + memzero(bits, sizeof(bits)); + i = 0; + while (mnemonic[i]) { + j = 0; + while (mnemonic[i] != ' ' && mnemonic[i] != 0) { + if (j >= sizeof(current_word) - 1) { + return 0; + } + current_word[j] = mnemonic[i]; + i++; + j++; + } + current_word[j] = 0; + if (mnemonic[i] != 0) { + i++; + } + k = 0; + for (;;) { + if (!wordlist[k]) { // word not found + return 0; + } + if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k + for (ki = 0; ki < 11; ki++) { + if (k & (1 << (10 - ki))) { + bits[bi / 8] |= 1 << (7 - (bi % 8)); + } + bi++; + } + break; + } + k++; + } + } + if (bi != n * 11) { + return 0; + } + memcpy(entropy, bits, sizeof(bits)); + return n * 11; +} + +int mnemonic_check(const char *mnemonic) { + uint8_t bits[32 + 1] = {0}; + int seed_len = mnemonic_to_entropy(mnemonic, bits); + if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) { + return 0; + } + int words = seed_len / 11; + + uint8_t checksum = bits[words * 4 / 3]; + sha256_Raw(bits, words * 4 / 3, bits); + if (words == 12) { + return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits + } else if (words == 18) { + return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits + } else if (words == 24) { + return bits[0] == checksum; // compare 8 bits + } + return 0; +} + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, + uint8_t seed[512 / 8], + void (*progress_callback)(uint32_t current, + uint32_t total)) { + int mnemoniclen = strlen(mnemonic); + int passphraselen = strnlen(passphrase, 256); +#if USE_BIP39_CACHE + // check cache + if (mnemoniclen < 256 && passphraselen < 64) { + for (int i = 0; i < BIP39_CACHE_SIZE; i++) { + if (!bip39_cache[i].set) continue; + if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue; + if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue; + // found the correct entry + memcpy(seed, bip39_cache[i].seed, 512 / 8); + return; + } + } +#endif + uint8_t salt[8 + 256] = {0}; + memcpy(salt, "mnemonic", 8); + memcpy(salt + 8, passphrase, passphraselen); + static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, + passphraselen + 8, 1); + if (progress_callback) { + progress_callback(0, BIP39_PBKDF2_ROUNDS); + } + for (int i = 0; i < 16; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16); + if (progress_callback) { + progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, + BIP39_PBKDF2_ROUNDS); + } + } + pbkdf2_hmac_sha512_Final(&pctx, seed); + memzero(salt, sizeof(salt)); +#if USE_BIP39_CACHE + // store to cache + if (mnemoniclen < 256 && passphraselen < 64) { + bip39_cache[bip39_cache_index].set = true; + strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic); + strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase); + memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8); + bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE; + } +#endif +} + +// binary search for finding the word in the wordlist +int mnemonic_find_word(const char *word) { + int lo = 0, hi = BIP39_WORDS - 1; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + int cmp = strcmp(word, wordlist[mid]); + if (cmp == 0) { + return mid; + } + if (cmp > 0) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return -1; +} + +const char *mnemonic_complete_word(const char *prefix, int len) { + // we need to perform linear search, + // because we want to return the first match + for (const char *const *w = wordlist; *w != 0; w++) { + if (strncmp(*w, prefix, len) == 0) { + return *w; + } + } + return NULL; +} + +const char *mnemonic_get_word(int index) { + if (index >= 0 && index < BIP39_WORDS) { + return wordlist[index]; + } else { + return NULL; + } +} + +uint32_t mnemonic_word_completion_mask(const char *prefix, int len) { + if (len <= 0) { + return 0x3ffffff; // all letters (bits 1-26 set) + } + uint32_t res = 0; + for (const char *const *w = wordlist; *w != 0; w++) { + const char *word = *w; + if (strncmp(word, prefix, len) == 0 && word[len] >= 'a' && + word[len] <= 'z') { + res |= 1 << (word[len] - 'a'); + } + } + return res; +} diff --git a/src/crypto/bip39/bip39.h b/src/crypto/bip39/bip39.h new file mode 100644 index 000000000..ac76101d7 --- /dev/null +++ b/src/crypto/bip39/bip39.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __BIP39_H__ +#define __BIP39_H__ + +#include + +#define BIP39_PBKDF2_ROUNDS 2048 + +const char *mnemonic_generate(int strength); // strength in bits +const char *mnemonic_from_data(const uint8_t *data, int len); +void mnemonic_clear(void); + +int mnemonic_check(const char *mnemonic); + +int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy); + +// passphrase must be at most 256 characters otherwise it would be truncated +void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total)); + +const char * const *mnemonic_wordlist(void); + +#endif diff --git a/src/crypto/bip39/bip39_english.h b/src/crypto/bip39/bip39_english.h new file mode 100644 index 000000000..77607ba7f --- /dev/null +++ b/src/crypto/bip39/bip39_english.h @@ -0,0 +1,2074 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +static const char * const wordlist[] = { +"abandon", +"ability", +"able", +"about", +"above", +"absent", +"absorb", +"abstract", +"absurd", +"abuse", +"access", +"accident", +"account", +"accuse", +"achieve", +"acid", +"acoustic", +"acquire", +"across", +"act", +"action", +"actor", +"actress", +"actual", +"adapt", +"add", +"addict", +"address", +"adjust", +"admit", +"adult", +"advance", +"advice", +"aerobic", +"affair", +"afford", +"afraid", +"again", +"age", +"agent", +"agree", +"ahead", +"aim", +"air", +"airport", +"aisle", +"alarm", +"album", +"alcohol", +"alert", +"alien", +"all", +"alley", +"allow", +"almost", +"alone", +"alpha", +"already", +"also", +"alter", +"always", +"amateur", +"amazing", +"among", +"amount", +"amused", +"analyst", +"anchor", +"ancient", +"anger", +"angle", +"angry", +"animal", +"ankle", +"announce", +"annual", +"another", +"answer", +"antenna", +"antique", +"anxiety", +"any", +"apart", +"apology", +"appear", +"apple", +"approve", +"april", +"arch", +"arctic", +"area", +"arena", +"argue", +"arm", +"armed", +"armor", +"army", +"around", +"arrange", +"arrest", +"arrive", +"arrow", +"art", +"artefact", +"artist", +"artwork", +"ask", +"aspect", +"assault", +"asset", +"assist", +"assume", +"asthma", +"athlete", +"atom", +"attack", +"attend", +"attitude", +"attract", +"auction", +"audit", +"august", +"aunt", +"author", +"auto", +"autumn", +"average", +"avocado", +"avoid", +"awake", +"aware", +"away", +"awesome", +"awful", +"awkward", +"axis", +"baby", +"bachelor", +"bacon", +"badge", +"bag", +"balance", +"balcony", +"ball", +"bamboo", +"banana", +"banner", +"bar", +"barely", +"bargain", +"barrel", +"base", +"basic", +"basket", +"battle", +"beach", +"bean", +"beauty", +"because", +"become", +"beef", +"before", +"begin", +"behave", +"behind", +"believe", +"below", +"belt", +"bench", +"benefit", +"best", +"betray", +"better", +"between", +"beyond", +"bicycle", +"bid", +"bike", +"bind", +"biology", +"bird", +"birth", +"bitter", +"black", +"blade", +"blame", +"blanket", +"blast", +"bleak", +"bless", +"blind", +"blood", +"blossom", +"blouse", +"blue", +"blur", +"blush", +"board", +"boat", +"body", +"boil", +"bomb", +"bone", +"bonus", +"book", +"boost", +"border", +"boring", +"borrow", +"boss", +"bottom", +"bounce", +"box", +"boy", +"bracket", +"brain", +"brand", +"brass", +"brave", +"bread", +"breeze", +"brick", +"bridge", +"brief", +"bright", +"bring", +"brisk", +"broccoli", +"broken", +"bronze", +"broom", +"brother", +"brown", +"brush", +"bubble", +"buddy", +"budget", +"buffalo", +"build", +"bulb", +"bulk", +"bullet", +"bundle", +"bunker", +"burden", +"burger", +"burst", +"bus", +"business", +"busy", +"butter", +"buyer", +"buzz", +"cabbage", +"cabin", +"cable", +"cactus", +"cage", +"cake", +"call", +"calm", +"camera", +"camp", +"can", +"canal", +"cancel", +"candy", +"cannon", +"canoe", +"canvas", +"canyon", +"capable", +"capital", +"captain", +"car", +"carbon", +"card", +"cargo", +"carpet", +"carry", +"cart", +"case", +"cash", +"casino", +"castle", +"casual", +"cat", +"catalog", +"catch", +"category", +"cattle", +"caught", +"cause", +"caution", +"cave", +"ceiling", +"celery", +"cement", +"census", +"century", +"cereal", +"certain", +"chair", +"chalk", +"champion", +"change", +"chaos", +"chapter", +"charge", +"chase", +"chat", +"cheap", +"check", +"cheese", +"chef", +"cherry", +"chest", +"chicken", +"chief", +"child", +"chimney", +"choice", +"choose", +"chronic", +"chuckle", +"chunk", +"churn", +"cigar", +"cinnamon", +"circle", +"citizen", +"city", +"civil", +"claim", +"clap", +"clarify", +"claw", +"clay", +"clean", +"clerk", +"clever", +"click", +"client", +"cliff", +"climb", +"clinic", +"clip", +"clock", +"clog", +"close", +"cloth", +"cloud", +"clown", +"club", +"clump", +"cluster", +"clutch", +"coach", +"coast", +"coconut", +"code", +"coffee", +"coil", +"coin", +"collect", +"color", +"column", +"combine", +"come", +"comfort", +"comic", +"common", +"company", +"concert", +"conduct", +"confirm", +"congress", +"connect", +"consider", +"control", +"convince", +"cook", +"cool", +"copper", +"copy", +"coral", +"core", +"corn", +"correct", +"cost", +"cotton", +"couch", +"country", +"couple", +"course", +"cousin", +"cover", +"coyote", +"crack", +"cradle", +"craft", +"cram", +"crane", +"crash", +"crater", +"crawl", +"crazy", +"cream", +"credit", +"creek", +"crew", +"cricket", +"crime", +"crisp", +"critic", +"crop", +"cross", +"crouch", +"crowd", +"crucial", +"cruel", +"cruise", +"crumble", +"crunch", +"crush", +"cry", +"crystal", +"cube", +"culture", +"cup", +"cupboard", +"curious", +"current", +"curtain", +"curve", +"cushion", +"custom", +"cute", +"cycle", +"dad", +"damage", +"damp", +"dance", +"danger", +"daring", +"dash", +"daughter", +"dawn", +"day", +"deal", +"debate", +"debris", +"decade", +"december", +"decide", +"decline", +"decorate", +"decrease", +"deer", +"defense", +"define", +"defy", +"degree", +"delay", +"deliver", +"demand", +"demise", +"denial", +"dentist", +"deny", +"depart", +"depend", +"deposit", +"depth", +"deputy", +"derive", +"describe", +"desert", +"design", +"desk", +"despair", +"destroy", +"detail", +"detect", +"develop", +"device", +"devote", +"diagram", +"dial", +"diamond", +"diary", +"dice", +"diesel", +"diet", +"differ", +"digital", +"dignity", +"dilemma", +"dinner", +"dinosaur", +"direct", +"dirt", +"disagree", +"discover", +"disease", +"dish", +"dismiss", +"disorder", +"display", +"distance", +"divert", +"divide", +"divorce", +"dizzy", +"doctor", +"document", +"dog", +"doll", +"dolphin", +"domain", +"donate", +"donkey", +"donor", +"door", +"dose", +"double", +"dove", +"draft", +"dragon", +"drama", +"drastic", +"draw", +"dream", +"dress", +"drift", +"drill", +"drink", +"drip", +"drive", +"drop", +"drum", +"dry", +"duck", +"dumb", +"dune", +"during", +"dust", +"dutch", +"duty", +"dwarf", +"dynamic", +"eager", +"eagle", +"early", +"earn", +"earth", +"easily", +"east", +"easy", +"echo", +"ecology", +"economy", +"edge", +"edit", +"educate", +"effort", +"egg", +"eight", +"either", +"elbow", +"elder", +"electric", +"elegant", +"element", +"elephant", +"elevator", +"elite", +"else", +"embark", +"embody", +"embrace", +"emerge", +"emotion", +"employ", +"empower", +"empty", +"enable", +"enact", +"end", +"endless", +"endorse", +"enemy", +"energy", +"enforce", +"engage", +"engine", +"enhance", +"enjoy", +"enlist", +"enough", +"enrich", +"enroll", +"ensure", +"enter", +"entire", +"entry", +"envelope", +"episode", +"equal", +"equip", +"era", +"erase", +"erode", +"erosion", +"error", +"erupt", +"escape", +"essay", +"essence", +"estate", +"eternal", +"ethics", +"evidence", +"evil", +"evoke", +"evolve", +"exact", +"example", +"excess", +"exchange", +"excite", +"exclude", +"excuse", +"execute", +"exercise", +"exhaust", +"exhibit", +"exile", +"exist", +"exit", +"exotic", +"expand", +"expect", +"expire", +"explain", +"expose", +"express", +"extend", +"extra", +"eye", +"eyebrow", +"fabric", +"face", +"faculty", +"fade", +"faint", +"faith", +"fall", +"false", +"fame", +"family", +"famous", +"fan", +"fancy", +"fantasy", +"farm", +"fashion", +"fat", +"fatal", +"father", +"fatigue", +"fault", +"favorite", +"feature", +"february", +"federal", +"fee", +"feed", +"feel", +"female", +"fence", +"festival", +"fetch", +"fever", +"few", +"fiber", +"fiction", +"field", +"figure", +"file", +"film", +"filter", +"final", +"find", +"fine", +"finger", +"finish", +"fire", +"firm", +"first", +"fiscal", +"fish", +"fit", +"fitness", +"fix", +"flag", +"flame", +"flash", +"flat", +"flavor", +"flee", +"flight", +"flip", +"float", +"flock", +"floor", +"flower", +"fluid", +"flush", +"fly", +"foam", +"focus", +"fog", +"foil", +"fold", +"follow", +"food", +"foot", +"force", +"forest", +"forget", +"fork", +"fortune", +"forum", +"forward", +"fossil", +"foster", +"found", +"fox", +"fragile", +"frame", +"frequent", +"fresh", +"friend", +"fringe", +"frog", +"front", +"frost", +"frown", +"frozen", +"fruit", +"fuel", +"fun", +"funny", +"furnace", +"fury", +"future", +"gadget", +"gain", +"galaxy", +"gallery", +"game", +"gap", +"garage", +"garbage", +"garden", +"garlic", +"garment", +"gas", +"gasp", +"gate", +"gather", +"gauge", +"gaze", +"general", +"genius", +"genre", +"gentle", +"genuine", +"gesture", +"ghost", +"giant", +"gift", +"giggle", +"ginger", +"giraffe", +"girl", +"give", +"glad", +"glance", +"glare", +"glass", +"glide", +"glimpse", +"globe", +"gloom", +"glory", +"glove", +"glow", +"glue", +"goat", +"goddess", +"gold", +"good", +"goose", +"gorilla", +"gospel", +"gossip", +"govern", +"gown", +"grab", +"grace", +"grain", +"grant", +"grape", +"grass", +"gravity", +"great", +"green", +"grid", +"grief", +"grit", +"grocery", +"group", +"grow", +"grunt", +"guard", +"guess", +"guide", +"guilt", +"guitar", +"gun", +"gym", +"habit", +"hair", +"half", +"hammer", +"hamster", +"hand", +"happy", +"harbor", +"hard", +"harsh", +"harvest", +"hat", +"have", +"hawk", +"hazard", +"head", +"health", +"heart", +"heavy", +"hedgehog", +"height", +"hello", +"helmet", +"help", +"hen", +"hero", +"hidden", +"high", +"hill", +"hint", +"hip", +"hire", +"history", +"hobby", +"hockey", +"hold", +"hole", +"holiday", +"hollow", +"home", +"honey", +"hood", +"hope", +"horn", +"horror", +"horse", +"hospital", +"host", +"hotel", +"hour", +"hover", +"hub", +"huge", +"human", +"humble", +"humor", +"hundred", +"hungry", +"hunt", +"hurdle", +"hurry", +"hurt", +"husband", +"hybrid", +"ice", +"icon", +"idea", +"identify", +"idle", +"ignore", +"ill", +"illegal", +"illness", +"image", +"imitate", +"immense", +"immune", +"impact", +"impose", +"improve", +"impulse", +"inch", +"include", +"income", +"increase", +"index", +"indicate", +"indoor", +"industry", +"infant", +"inflict", +"inform", +"inhale", +"inherit", +"initial", +"inject", +"injury", +"inmate", +"inner", +"innocent", +"input", +"inquiry", +"insane", +"insect", +"inside", +"inspire", +"install", +"intact", +"interest", +"into", +"invest", +"invite", +"involve", +"iron", +"island", +"isolate", +"issue", +"item", +"ivory", +"jacket", +"jaguar", +"jar", +"jazz", +"jealous", +"jeans", +"jelly", +"jewel", +"job", +"join", +"joke", +"journey", +"joy", +"judge", +"juice", +"jump", +"jungle", +"junior", +"junk", +"just", +"kangaroo", +"keen", +"keep", +"ketchup", +"key", +"kick", +"kid", +"kidney", +"kind", +"kingdom", +"kiss", +"kit", +"kitchen", +"kite", +"kitten", +"kiwi", +"knee", +"knife", +"knock", +"know", +"lab", +"label", +"labor", +"ladder", +"lady", +"lake", +"lamp", +"language", +"laptop", +"large", +"later", +"latin", +"laugh", +"laundry", +"lava", +"law", +"lawn", +"lawsuit", +"layer", +"lazy", +"leader", +"leaf", +"learn", +"leave", +"lecture", +"left", +"leg", +"legal", +"legend", +"leisure", +"lemon", +"lend", +"length", +"lens", +"leopard", +"lesson", +"letter", +"level", +"liar", +"liberty", +"library", +"license", +"life", +"lift", +"light", +"like", +"limb", +"limit", +"link", +"lion", +"liquid", +"list", +"little", +"live", +"lizard", +"load", +"loan", +"lobster", +"local", +"lock", +"logic", +"lonely", +"long", +"loop", +"lottery", +"loud", +"lounge", +"love", +"loyal", +"lucky", +"luggage", +"lumber", +"lunar", +"lunch", +"luxury", +"lyrics", +"machine", +"mad", +"magic", +"magnet", +"maid", +"mail", +"main", +"major", +"make", +"mammal", +"man", +"manage", +"mandate", +"mango", +"mansion", +"manual", +"maple", +"marble", +"march", +"margin", +"marine", +"market", +"marriage", +"mask", +"mass", +"master", +"match", +"material", +"math", +"matrix", +"matter", +"maximum", +"maze", +"meadow", +"mean", +"measure", +"meat", +"mechanic", +"medal", +"media", +"melody", +"melt", +"member", +"memory", +"mention", +"menu", +"mercy", +"merge", +"merit", +"merry", +"mesh", +"message", +"metal", +"method", +"middle", +"midnight", +"milk", +"million", +"mimic", +"mind", +"minimum", +"minor", +"minute", +"miracle", +"mirror", +"misery", +"miss", +"mistake", +"mix", +"mixed", +"mixture", +"mobile", +"model", +"modify", +"mom", +"moment", +"monitor", +"monkey", +"monster", +"month", +"moon", +"moral", +"more", +"morning", +"mosquito", +"mother", +"motion", +"motor", +"mountain", +"mouse", +"move", +"movie", +"much", +"muffin", +"mule", +"multiply", +"muscle", +"museum", +"mushroom", +"music", +"must", +"mutual", +"myself", +"mystery", +"myth", +"naive", +"name", +"napkin", +"narrow", +"nasty", +"nation", +"nature", +"near", +"neck", +"need", +"negative", +"neglect", +"neither", +"nephew", +"nerve", +"nest", +"net", +"network", +"neutral", +"never", +"news", +"next", +"nice", +"night", +"noble", +"noise", +"nominee", +"noodle", +"normal", +"north", +"nose", +"notable", +"note", +"nothing", +"notice", +"novel", +"now", +"nuclear", +"number", +"nurse", +"nut", +"oak", +"obey", +"object", +"oblige", +"obscure", +"observe", +"obtain", +"obvious", +"occur", +"ocean", +"october", +"odor", +"off", +"offer", +"office", +"often", +"oil", +"okay", +"old", +"olive", +"olympic", +"omit", +"once", +"one", +"onion", +"online", +"only", +"open", +"opera", +"opinion", +"oppose", +"option", +"orange", +"orbit", +"orchard", +"order", +"ordinary", +"organ", +"orient", +"original", +"orphan", +"ostrich", +"other", +"outdoor", +"outer", +"output", +"outside", +"oval", +"oven", +"over", +"own", +"owner", +"oxygen", +"oyster", +"ozone", +"pact", +"paddle", +"page", +"pair", +"palace", +"palm", +"panda", +"panel", +"panic", +"panther", +"paper", +"parade", +"parent", +"park", +"parrot", +"party", +"pass", +"patch", +"path", +"patient", +"patrol", +"pattern", +"pause", +"pave", +"payment", +"peace", +"peanut", +"pear", +"peasant", +"pelican", +"pen", +"penalty", +"pencil", +"people", +"pepper", +"perfect", +"permit", +"person", +"pet", +"phone", +"photo", +"phrase", +"physical", +"piano", +"picnic", +"picture", +"piece", +"pig", +"pigeon", +"pill", +"pilot", +"pink", +"pioneer", +"pipe", +"pistol", +"pitch", +"pizza", +"place", +"planet", +"plastic", +"plate", +"play", +"please", +"pledge", +"pluck", +"plug", +"plunge", +"poem", +"poet", +"point", +"polar", +"pole", +"police", +"pond", +"pony", +"pool", +"popular", +"portion", +"position", +"possible", +"post", +"potato", +"pottery", +"poverty", +"powder", +"power", +"practice", +"praise", +"predict", +"prefer", +"prepare", +"present", +"pretty", +"prevent", +"price", +"pride", +"primary", +"print", +"priority", +"prison", +"private", +"prize", +"problem", +"process", +"produce", +"profit", +"program", +"project", +"promote", +"proof", +"property", +"prosper", +"protect", +"proud", +"provide", +"public", +"pudding", +"pull", +"pulp", +"pulse", +"pumpkin", +"punch", +"pupil", +"puppy", +"purchase", +"purity", +"purpose", +"purse", +"push", +"put", +"puzzle", +"pyramid", +"quality", +"quantum", +"quarter", +"question", +"quick", +"quit", +"quiz", +"quote", +"rabbit", +"raccoon", +"race", +"rack", +"radar", +"radio", +"rail", +"rain", +"raise", +"rally", +"ramp", +"ranch", +"random", +"range", +"rapid", +"rare", +"rate", +"rather", +"raven", +"raw", +"razor", +"ready", +"real", +"reason", +"rebel", +"rebuild", +"recall", +"receive", +"recipe", +"record", +"recycle", +"reduce", +"reflect", +"reform", +"refuse", +"region", +"regret", +"regular", +"reject", +"relax", +"release", +"relief", +"rely", +"remain", +"remember", +"remind", +"remove", +"render", +"renew", +"rent", +"reopen", +"repair", +"repeat", +"replace", +"report", +"require", +"rescue", +"resemble", +"resist", +"resource", +"response", +"result", +"retire", +"retreat", +"return", +"reunion", +"reveal", +"review", +"reward", +"rhythm", +"rib", +"ribbon", +"rice", +"rich", +"ride", +"ridge", +"rifle", +"right", +"rigid", +"ring", +"riot", +"ripple", +"risk", +"ritual", +"rival", +"river", +"road", +"roast", +"robot", +"robust", +"rocket", +"romance", +"roof", +"rookie", +"room", +"rose", +"rotate", +"rough", +"round", +"route", +"royal", +"rubber", +"rude", +"rug", +"rule", +"run", +"runway", +"rural", +"sad", +"saddle", +"sadness", +"safe", +"sail", +"salad", +"salmon", +"salon", +"salt", +"salute", +"same", +"sample", +"sand", +"satisfy", +"satoshi", +"sauce", +"sausage", +"save", +"say", +"scale", +"scan", +"scare", +"scatter", +"scene", +"scheme", +"school", +"science", +"scissors", +"scorpion", +"scout", +"scrap", +"screen", +"script", +"scrub", +"sea", +"search", +"season", +"seat", +"second", +"secret", +"section", +"security", +"seed", +"seek", +"segment", +"select", +"sell", +"seminar", +"senior", +"sense", +"sentence", +"series", +"service", +"session", +"settle", +"setup", +"seven", +"shadow", +"shaft", +"shallow", +"share", +"shed", +"shell", +"sheriff", +"shield", +"shift", +"shine", +"ship", +"shiver", +"shock", +"shoe", +"shoot", +"shop", +"short", +"shoulder", +"shove", +"shrimp", +"shrug", +"shuffle", +"shy", +"sibling", +"sick", +"side", +"siege", +"sight", +"sign", +"silent", +"silk", +"silly", +"silver", +"similar", +"simple", +"since", +"sing", +"siren", +"sister", +"situate", +"six", +"size", +"skate", +"sketch", +"ski", +"skill", +"skin", +"skirt", +"skull", +"slab", +"slam", +"sleep", +"slender", +"slice", +"slide", +"slight", +"slim", +"slogan", +"slot", +"slow", +"slush", +"small", +"smart", +"smile", +"smoke", +"smooth", +"snack", +"snake", +"snap", +"sniff", +"snow", +"soap", +"soccer", +"social", +"sock", +"soda", +"soft", +"solar", +"soldier", +"solid", +"solution", +"solve", +"someone", +"song", +"soon", +"sorry", +"sort", +"soul", +"sound", +"soup", +"source", +"south", +"space", +"spare", +"spatial", +"spawn", +"speak", +"special", +"speed", +"spell", +"spend", +"sphere", +"spice", +"spider", +"spike", +"spin", +"spirit", +"split", +"spoil", +"sponsor", +"spoon", +"sport", +"spot", +"spray", +"spread", +"spring", +"spy", +"square", +"squeeze", +"squirrel", +"stable", +"stadium", +"staff", +"stage", +"stairs", +"stamp", +"stand", +"start", +"state", +"stay", +"steak", +"steel", +"stem", +"step", +"stereo", +"stick", +"still", +"sting", +"stock", +"stomach", +"stone", +"stool", +"story", +"stove", +"strategy", +"street", +"strike", +"strong", +"struggle", +"student", +"stuff", +"stumble", +"style", +"subject", +"submit", +"subway", +"success", +"such", +"sudden", +"suffer", +"sugar", +"suggest", +"suit", +"summer", +"sun", +"sunny", +"sunset", +"super", +"supply", +"supreme", +"sure", +"surface", +"surge", +"surprise", +"surround", +"survey", +"suspect", +"sustain", +"swallow", +"swamp", +"swap", +"swarm", +"swear", +"sweet", +"swift", +"swim", +"swing", +"switch", +"sword", +"symbol", +"symptom", +"syrup", +"system", +"table", +"tackle", +"tag", +"tail", +"talent", +"talk", +"tank", +"tape", +"target", +"task", +"taste", +"tattoo", +"taxi", +"teach", +"team", +"tell", +"ten", +"tenant", +"tennis", +"tent", +"term", +"test", +"text", +"thank", +"that", +"theme", +"then", +"theory", +"there", +"they", +"thing", +"this", +"thought", +"three", +"thrive", +"throw", +"thumb", +"thunder", +"ticket", +"tide", +"tiger", +"tilt", +"timber", +"time", +"tiny", +"tip", +"tired", +"tissue", +"title", +"toast", +"tobacco", +"today", +"toddler", +"toe", +"together", +"toilet", +"token", +"tomato", +"tomorrow", +"tone", +"tongue", +"tonight", +"tool", +"tooth", +"top", +"topic", +"topple", +"torch", +"tornado", +"tortoise", +"toss", +"total", +"tourist", +"toward", +"tower", +"town", +"toy", +"track", +"trade", +"traffic", +"tragic", +"train", +"transfer", +"trap", +"trash", +"travel", +"tray", +"treat", +"tree", +"trend", +"trial", +"tribe", +"trick", +"trigger", +"trim", +"trip", +"trophy", +"trouble", +"truck", +"true", +"truly", +"trumpet", +"trust", +"truth", +"try", +"tube", +"tuition", +"tumble", +"tuna", +"tunnel", +"turkey", +"turn", +"turtle", +"twelve", +"twenty", +"twice", +"twin", +"twist", +"two", +"type", +"typical", +"ugly", +"umbrella", +"unable", +"unaware", +"uncle", +"uncover", +"under", +"undo", +"unfair", +"unfold", +"unhappy", +"uniform", +"unique", +"unit", +"universe", +"unknown", +"unlock", +"until", +"unusual", +"unveil", +"update", +"upgrade", +"uphold", +"upon", +"upper", +"upset", +"urban", +"urge", +"usage", +"use", +"used", +"useful", +"useless", +"usual", +"utility", +"vacant", +"vacuum", +"vague", +"valid", +"valley", +"valve", +"van", +"vanish", +"vapor", +"various", +"vast", +"vault", +"vehicle", +"velvet", +"vendor", +"venture", +"venue", +"verb", +"verify", +"version", +"very", +"vessel", +"veteran", +"viable", +"vibrant", +"vicious", +"victory", +"video", +"view", +"village", +"vintage", +"violin", +"virtual", +"virus", +"visa", +"visit", +"visual", +"vital", +"vivid", +"vocal", +"voice", +"void", +"volcano", +"volume", +"vote", +"voyage", +"wage", +"wagon", +"wait", +"walk", +"wall", +"walnut", +"want", +"warfare", +"warm", +"warrior", +"wash", +"wasp", +"waste", +"water", +"wave", +"way", +"wealth", +"weapon", +"wear", +"weasel", +"weather", +"web", +"wedding", +"weekend", +"weird", +"welcome", +"west", +"wet", +"whale", +"what", +"wheat", +"wheel", +"when", +"where", +"whip", +"whisper", +"wide", +"width", +"wife", +"wild", +"will", +"win", +"window", +"wine", +"wing", +"wink", +"winner", +"winter", +"wire", +"wisdom", +"wise", +"wish", +"witness", +"wolf", +"woman", +"wonder", +"wood", +"wool", +"word", +"work", +"world", +"worry", +"worth", +"wrap", +"wreck", +"wrestle", +"wrist", +"write", +"wrong", +"yard", +"year", +"yellow", +"you", +"young", +"youth", +"zebra", +"zero", +"zone", +"zoo", +0, +}; diff --git a/src/crypto/bip39/bip39_mnemonic.c b/src/crypto/bip39/bip39_mnemonic.c new file mode 100644 index 000000000..a4dc27b86 --- /dev/null +++ b/src/crypto/bip39/bip39_mnemonic.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include "bip39.h" +#include + +// NOTE: We must override this to implement actual RNG! +void random_buffer(uint8_t *buf, size_t len) { + if( len > 0 ) { + randombytes_buf(buf, len); + } +} + +int main(int argc, char **argv) +{ + char *this = argv[0]; + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", this); + return 1; + } + if (sodium_init() == -1) { + fprintf(stderr, "libsodium init failed! :(\n"); + return 1; + } + int strength = 256; + const char *mnemonic = mnemonic_generate(strength); + printf("%s\n", mnemonic); + return 0; +} diff --git a/src/crypto/bip39/bip39bruteforce.c b/src/crypto/bip39/bip39bruteforce.c new file mode 100644 index 000000000..10fd69da7 --- /dev/null +++ b/src/crypto/bip39/bip39bruteforce.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include "bip39.h" +#include "bip32.h" +#include "ecdsa.h" +#include "curves.h" + +char iter[256]; +uint8_t seed[512 / 8]; +uint8_t addr[21], pubkeyhash[20]; +int count = 0, found = 0; +HDNode node; +clock_t start; + +// around 280 tries per second + +// testing data: +// +// mnemonic: "all all all all all all all all all all all all" +// address: "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL" +// passphrase: "" +// +// mnemonic: "all all all all all all all all all all all all" +// address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" +// passphrase: "testing" + +int main(int argc, char **argv) +{ + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); + return 1; + } + const char *address = argv[1]; + const char *mnemonic, *item; + if (argc == 3) { + mnemonic = argv[2]; + item = "passphrase"; + } else { + mnemonic = NULL; + item = "mnemonic"; + } + if (mnemonic && !mnemonic_check(mnemonic)) { + fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); + return 2; + } + if (!ecdsa_address_decode(address, 0, HASHER_SHA2, addr)) { + fprintf(stderr, "\"%s\" is not a valid address\n", address); + return 3; + } + printf("Reading %ss from stdin ...\n", item); + start = clock(); + for (;;) { + if (fgets(iter, 256, stdin) == NULL) break; + int len = strlen(iter); + if (len <= 0) { + continue; + } + count++; + iter[len - 1] = 0; + if (mnemonic) { + mnemonic_to_seed(mnemonic, iter, seed, NULL); + } else { + mnemonic_to_seed(iter, "", seed, NULL); + } + hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); + hdnode_private_ckd_prime(&node, 44); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_fill_public_key(&node); + ecdsa_get_pubkeyhash(node.public_key, HASHER_SHA2, pubkeyhash); + if (memcmp(addr + 1, pubkeyhash, 20) == 0) { + found = 1; + break; + } + } + float dur = (float)(clock() - start) / CLOCKS_PER_SEC; + printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, (float)count/dur); + if (found) { + printf("Correct %s found! :-)\n\"%s\"\n", item, iter); + return 0; + } + printf("Correct %s not found. :-(\n", item); + return 4; +} diff --git a/src/crypto/bip39/blake256.h b/src/crypto/bip39/blake256.h new file mode 100644 index 000000000..313b6260e --- /dev/null +++ b/src/crypto/bip39/blake256.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// 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. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __BLAKE256_H__ +#define __BLAKE256_H__ + +#include +#include + +#define BLAKE256_DIGEST_LENGTH 32 +#define BLAKE256_BLOCK_LENGTH 64 + +typedef struct { + uint32_t h[8], s[4], t[2]; + size_t buflen; + uint8_t nullt; + uint8_t buf[64]; +} BLAKE256_CTX; + +void blake256_Init(BLAKE256_CTX *); +void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); +void blake256_Final(BLAKE256_CTX *, uint8_t *); + +void blake256(const uint8_t *, size_t, uint8_t *); + +#endif /* __BLAKE256_H__ */ diff --git a/src/crypto/bip39/blake2_common.h b/src/crypto/bip39/blake2_common.h new file mode 100644 index 000000000..40c6da3b5 --- /dev/null +++ b/src/crypto/bip39/blake2_common.h @@ -0,0 +1,39 @@ +static inline uint32_t load32( const void *src ) +{ + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline uint64_t load64( const void *src ) +{ + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline void store16( void *dst, uint16_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store32( void *dst, uint32_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store64( void *dst, uint64_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static inline uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + diff --git a/src/crypto/bip39/blake2b.h b/src/crypto/bip39/blake2b.h new file mode 100644 index 000000000..1a43e92d1 --- /dev/null +++ b/src/crypto/bip39/blake2b.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +enum blake2b_constant +{ + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state +{ + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +} blake2b_state; + +#define BLAKE2B_CTX blake2b_state +#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES +#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES +#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES + +int blake2b_Init(blake2b_state *S, size_t outlen); +int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); +int blake2b_Final(blake2b_state *S, void *out, size_t outlen); + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/src/crypto/bip39/blake2s.h b/src/crypto/bip39/blake2s.h new file mode 100644 index 000000000..57991bc91 --- /dev/null +++ b/src/crypto/bip39/blake2s.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2S_H__ +#define __BLAKE2S_H__ + +#include +#include + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct __blake2s_state +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + uint32_t buflen; + uint8_t outlen; + uint8_t last_node; +} blake2s_state; + +#define BLAKE2S_CTX blake2s_state +#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES +#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES +#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES + +int blake2s_Init(blake2s_state *S, size_t outlen); +int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); +int blake2s_InitPersonal(blake2s_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); +int blake2s_Final(blake2s_state *S, void *out, size_t outlen); + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/src/crypto/bip39/hasher.c b/src/crypto/bip39/hasher.c new file mode 100644 index 000000000..dac3e9bf5 --- /dev/null +++ b/src/crypto/bip39/hasher.c @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * 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. + */ + +#include "hasher.h" +#include "ripemd160.h" + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size) { + hasher->type = type; + hasher->param = param; + hasher->param_size = param_size; + + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Init(&hasher->ctx.sha2); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_256_Init(&hasher->ctx.sha3); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Init(&hasher->ctx.blake); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Init(&hasher->ctx.groestl); + break; + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); + break; + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size); + break; + } +} + +void hasher_Init(Hasher *hasher, HasherType type) { + hasher_InitParam(hasher, type, NULL, 0); +} + +void hasher_Reset(Hasher *hasher) { + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); +} + +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_Update(&hasher->ctx.sha3, data, length); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Update(&hasher->ctx.blake, data, length); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; + } +} + +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + case HASHER_SHA2D: + sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; +#if USE_KECCAK + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; +#endif + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; + case HASHER_BLAKED: + blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); + break; + } +} + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/src/crypto/bip39/hasher.h b/src/crypto/bip39/hasher.h new file mode 100644 index 000000000..0cde1df8b --- /dev/null +++ b/src/crypto/bip39/hasher.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * 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 __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "sha2.h" +#include "sha3.h" +#include "blake256.h" +#include "groestl.h" +#include "blake2b.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, + HASHER_SHA2D, + HASHER_SHA2_RIPEMD, + + HASHER_SHA3, +#if USE_KECCAK + HASHER_SHA3K, +#endif + + HASHER_BLAKE, + HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, + + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} + } ctx; + + const void *param; + uint32_t param_size; +} Hasher; + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size); +void hasher_Init(Hasher *hasher, HasherType type); +void hasher_Reset(Hasher *hasher); +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif diff --git a/src/crypto/bip39/hmac.c b/src/crypto/bip39/hmac.c new file mode 100644 index 000000000..654f2d6e8 --- /dev/null +++ b/src/crypto/bip39/hmac.c @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +#include + +#include "hmac.h" +#include "memzero.h" +#include "options.h" + +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; + memzero(i_key_pad, SHA256_BLOCK_LENGTH); + if (keylen > SHA256_BLOCK_LENGTH) { + sha256_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha256_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) { + sha256_Final(&(hctx->ctx), hmac); + sha256_Init(&(hctx->ctx)); + sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH); + sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH); + sha256_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA256_CTX)); +} + +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + static CONFIDENTIAL HMAC_SHA256_CTX hctx; + hmac_sha256_Init(&hctx, key, keylen); + hmac_sha256_Update(&hctx, msg, msglen); + hmac_sha256_Final(&hctx, hmac); +} + +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, + uint32_t *opad_digest, uint32_t *ipad_digest) { + static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA256_BLOCK_LENGTH) { + static CONFIDENTIAL SHA256_CTX context; + sha256_Init(&context); + sha256_Update(&context, key, keylen); + sha256_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + uint32_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} + +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, + const uint32_t keylen) { + static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH]; + memzero(i_key_pad, SHA512_BLOCK_LENGTH); + if (keylen > SHA512_BLOCK_LENGTH) { + sha512_Raw(key, keylen, i_key_pad); + } else { + memcpy(i_key_pad, key, keylen); + } + for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) { + hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c; + i_key_pad[i] ^= 0x36; + } + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH); + memzero(i_key_pad, sizeof(i_key_pad)); +} + +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, + const uint32_t msglen) { + sha512_Update(&(hctx->ctx), msg, msglen); +} + +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) { + sha512_Final(&(hctx->ctx), hmac); + sha512_Init(&(hctx->ctx)); + sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH); + sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH); + sha512_Final(&(hctx->ctx), hmac); + memzero(hctx, sizeof(HMAC_SHA512_CTX)); +} + +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, + const uint32_t msglen, uint8_t *hmac) { + HMAC_SHA512_CTX hctx = {0}; + hmac_sha512_Init(&hctx, key, keylen); + hmac_sha512_Update(&hctx, msg, msglen); + hmac_sha512_Final(&hctx, hmac); +} + +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, + uint64_t *opad_digest, uint64_t *ipad_digest) { + static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + + memzero(key_pad, sizeof(key_pad)); + if (keylen > SHA512_BLOCK_LENGTH) { + static CONFIDENTIAL SHA512_CTX context; + sha512_Init(&context); + sha512_Update(&context, key, keylen); + sha512_Final(&context, (uint8_t *)key_pad); + } else { + memcpy(key_pad, key, keylen); + } + + /* compute o_key_pad and its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + uint64_t data = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE64(key_pad[i], data); +#else + data = key_pad[i]; +#endif + key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c; + } + sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest); + + /* convert o_key_pad to i_key_pad and compute its digest */ + for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) { + key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636; + } + sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest); + memzero(key_pad, sizeof(key_pad)); +} diff --git a/src/crypto/bip39/hmac.h b/src/crypto/bip39/hmac.h new file mode 100644 index 000000000..3cfc0cd0f --- /dev/null +++ b/src/crypto/bip39/hmac.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 HMAC_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 __HMAC_H__ +#define __HMAC_H__ + +#include +#include "sha2.h" + +typedef struct _HMAC_SHA256_CTX { + uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; + SHA256_CTX ctx; +} HMAC_SHA256_CTX; + +typedef struct _HMAC_SHA512_CTX { + uint8_t o_key_pad[SHA512_BLOCK_LENGTH]; + SHA512_CTX ctx; +} HMAC_SHA512_CTX; + +void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen); +void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac); +void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest); + +void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen); +void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen); +void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest); + +#endif diff --git a/src/crypto/bip39/hmac_drbg.c b/src/crypto/bip39/hmac_drbg.c new file mode 100644 index 000000000..1ed1401b8 --- /dev/null +++ b/src/crypto/bip39/hmac_drbg.c @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * 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. + */ + +#include "hmac_drbg.h" +#include +#include "memzero.h" +#include "sha2.h" + +static void update_k(HMAC_DRBG_CTX *ctx, uint8_t domain, const uint8_t *data1, + size_t len1, const uint8_t *data2, size_t len2) { + // Computes K = HMAC(K, V || domain || data1 || data 2). + + // First hash operation of HMAC. + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + if (len1 + len2 == 0) { + ctx->v[8] = 0x00800000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Transform(ctx->idig, ctx->v, h); + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + } else { + SHA256_CTX sha_ctx = {0}; + memcpy(sha_ctx.state, ctx->idig, SHA256_DIGEST_LENGTH); + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) { +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(ctx->v[i], sha_ctx.buffer[i]); +#else + sha_ctx.buffer[i] = ctx->v[i]; +#endif + } + ((uint8_t *)sha_ctx.buffer)[SHA256_DIGEST_LENGTH] = domain; + sha_ctx.bitcount = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH + 1) * 8; + sha256_Update(&sha_ctx, data1, len1); + sha256_Update(&sha_ctx, data2, len2); + sha256_Final(&sha_ctx, (uint8_t *)h); +#if BYTE_ORDER == LITTLE_ENDIAN + for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) + REVERSE32(h[i], h[i]); +#endif + } + + // Second hash operation of HMAC. + h[8] = 0x80000000; + h[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + sha256_Transform(ctx->odig, h, h); + + // Precompute the inner digest and outer digest of K. + h[8] = 0; + h[15] = 0; + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] ^= 0x36363636; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + + for (size_t i = 0; i < SHA256_BLOCK_LENGTH / sizeof(uint32_t); i++) { + h[i] = h[i] ^ 0x36363636 ^ 0x5c5c5c5c; + } + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + memzero(h, sizeof(h)); +} + +static void update_v(HMAC_DRBG_CTX *ctx) { + sha256_Transform(ctx->idig, ctx->v, ctx->v); + sha256_Transform(ctx->odig, ctx->v, ctx->v); +} + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, + size_t entropy_len, const uint8_t *nonce, + size_t nonce_len) { + uint32_t h[SHA256_BLOCK_LENGTH / sizeof(uint32_t)] = {0}; + + // Precompute the inner digest and outer digest of K = 0x00 ... 0x00. + memset(h, 0x36, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->idig); + memset(h, 0x5c, sizeof(h)); + sha256_Transform(sha256_initial_hash_value, h, ctx->odig); + + // Let V = 0x01 ... 0x01. + memset(ctx->v, 1, SHA256_DIGEST_LENGTH); + for (size_t i = 9; i < 15; i++) ctx->v[i] = 0; + ctx->v[8] = 0x80000000; + ctx->v[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + hmac_drbg_reseed(ctx, entropy, entropy_len, nonce, nonce_len); + + memzero(h, sizeof(h)); +} + +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *entropy, size_t len, + const uint8_t *addin, size_t addin_len) { + update_k(ctx, 0, entropy, len, addin, addin_len); + update_v(ctx); + if (len == 0) return; + update_k(ctx, 1, entropy, len, addin, addin_len); + update_v(ctx); +} + +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len) { + size_t i = 0; + while (i < len) { + update_v(ctx); + for (size_t j = 0; j < 8 && i < len; j++) { + uint32_t r = ctx->v[j]; + for (int k = 24; k >= 0 && i < len; k -= 8) { + buf[i++] = (r >> k) & 0xFF; + } + } + } + update_k(ctx, 0, NULL, 0, NULL, 0); + update_v(ctx); +} diff --git a/src/crypto/bip39/hmac_drbg.h b/src/crypto/bip39/hmac_drbg.h new file mode 100644 index 000000000..4b969dedb --- /dev/null +++ b/src/crypto/bip39/hmac_drbg.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 Andrew R. Kozlik + * + * 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 __HMAC_DRBG_H__ +#define __HMAC_DRBG_H__ + +#include +#include + +// HMAC based Deterministic Random Bit Generator with SHA-256 + +typedef struct _HMAC_DRBG_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t v[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; +} HMAC_DRBG_CTX; + +void hmac_drbg_init(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *nonce, size_t nonce_len); +void hmac_drbg_reseed(HMAC_DRBG_CTX *ctx, const uint8_t *buf, size_t len, + const uint8_t *addin, size_t addin_len); +void hmac_drbg_generate(HMAC_DRBG_CTX *ctx, uint8_t *buf, size_t len); + +#endif diff --git a/src/crypto/bip39/memzero.c b/src/crypto/bip39/memzero.c new file mode 100644 index 000000000..3c3a7383d --- /dev/null +++ b/src/crypto/bip39/memzero.c @@ -0,0 +1,66 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined( __NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} diff --git a/src/crypto/bip39/memzero.h b/src/crypto/bip39/memzero.h new file mode 100644 index 000000000..a7797d2b3 --- /dev/null +++ b/src/crypto/bip39/memzero.h @@ -0,0 +1,8 @@ +#ifndef __MEMZERO_H__ +#define __MEMZERO_H__ + +#include + +void memzero(void * const pnt, const size_t len); + +#endif diff --git a/src/crypto/bip39/options.h b/src/crypto/bip39/options.h new file mode 100644 index 000000000..e57654e6c --- /dev/null +++ b/src/crypto/bip39/options.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __OPTIONS_H__ +#define __OPTIONS_H__ + +// use precomputed Curve Points (some scalar multiples of curve base point G) +#ifndef USE_PRECOMPUTED_CP +#define USE_PRECOMPUTED_CP 1 +#endif + +// use fast inverse method +#ifndef USE_INVERSE_FAST +#define USE_INVERSE_FAST 1 +#endif + +// support for printing bignum256 structures via printf +#ifndef USE_BN_PRINT +#define USE_BN_PRINT 0 +#endif + +// use deterministic signatures +#ifndef USE_RFC6979 +#define USE_RFC6979 1 +#endif + +// implement BIP32 caching +#ifndef USE_BIP32_CACHE +#define USE_BIP32_CACHE 1 +#define BIP32_CACHE_SIZE 10 +#define BIP32_CACHE_MAXDEPTH 8 +#endif + +// support constructing BIP32 nodes from ed25519 and curve25519 curves. +#ifndef USE_BIP32_25519_CURVES +#define USE_BIP32_25519_CURVES 1 +#endif + +// implement BIP39 caching +#ifndef USE_BIP39_CACHE +#define USE_BIP39_CACHE 1 +#define BIP39_CACHE_SIZE 4 +#endif + +// support Ethereum operations +#ifndef USE_ETHEREUM +#define USE_ETHEREUM 0 +#endif + +// support Graphene operations (STEEM, BitShares) +#ifndef USE_GRAPHENE +#define USE_GRAPHENE 0 +#endif + +// support NEM operations +#ifndef USE_NEM +#define USE_NEM 0 +#endif + +// support MONERO operations +#ifndef USE_MONERO +#define USE_MONERO 0 +#endif + +// support CARDANO operations +#ifndef USE_CARDANO +#define USE_CARDANO 0 +#endif + +// support Keccak hashing +#ifndef USE_KECCAK +#define USE_KECCAK 1 +#endif + +// add way how to mark confidential data +#ifndef CONFIDENTIAL +#define CONFIDENTIAL +#endif + +#endif diff --git a/src/crypto/bip39/pbkdf2.c b/src/crypto/bip39/pbkdf2.c new file mode 100644 index 000000000..d9e142297 --- /dev/null +++ b/src/crypto/bip39/pbkdf2.c @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +#include "pbkdf2.h" +#include +#include "hmac.h" +#include "memzero.h" +#include "sha2.h" + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA256_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x80000000; + pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount = SHA256_BLOCK_LENGTH * 8; + sha256_Update(&ctx, salt, saltlen); + sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha256_Final(&ctx, (uint8_t *)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->g[k], pctx->g[k]); + } +#endif + sha256_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha256_Transform(pctx->idig, pctx->g, pctx->g); + sha256_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) { + REVERSE32(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA256_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX)); +} + +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA256_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA256_CTX pctx = {0}; + pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha256_Update(&pctx, iterations); + uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha256_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, + int passlen, const uint8_t *salt, int saltlen, + uint32_t blocknr) { + SHA512_CTX ctx = {0}; +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(blocknr, blocknr); +#endif + + hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig); + memzero(pctx->g, sizeof(pctx->g)); + pctx->g[8] = 0x8000000000000000; + pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8; + + memcpy(ctx.state, pctx->idig, sizeof(pctx->idig)); + ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8; + ctx.bitcount[1] = 0; + sha512_Update(&ctx, salt, saltlen); + sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr)); + sha512_Final(&ctx, (uint8_t *)pctx->g); +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->g[k], pctx->g[k]); + } +#endif + sha512_Transform(pctx->odig, pctx->g, pctx->g); + memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH); + pctx->first = 1; +} + +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, + uint32_t iterations) { + for (uint32_t i = pctx->first; i < iterations; i++) { + sha512_Transform(pctx->idig, pctx->g, pctx->g); + sha512_Transform(pctx->odig, pctx->g, pctx->g); + for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) { + pctx->f[j] ^= pctx->g[j]; + } + } + pctx->first = 0; +} + +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) { +#if BYTE_ORDER == LITTLE_ENDIAN + for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) { + REVERSE64(pctx->f[k], pctx->f[k]); + } +#endif + memcpy(key, pctx->f, SHA512_DIGEST_LENGTH); + memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX)); +} + +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, + int saltlen, uint32_t iterations, uint8_t *key, + int keylen) { + uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH; + uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH; + if (last_block_size) { + blocks_count++; + } else { + last_block_size = SHA512_DIGEST_LENGTH; + } + for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) { + PBKDF2_HMAC_SHA512_CTX pctx = {0}; + pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr); + pbkdf2_hmac_sha512_Update(&pctx, iterations); + uint8_t digest[SHA512_DIGEST_LENGTH] = {0}; + pbkdf2_hmac_sha512_Final(&pctx, digest); + uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH; + if (blocknr < blocks_count) { + memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH); + } else { + memcpy(key + key_offset, digest, last_block_size); + } + } +} diff --git a/src/crypto/bip39/pbkdf2.h b/src/crypto/bip39/pbkdf2.h new file mode 100644 index 000000000..e3f440c8f --- /dev/null +++ b/src/crypto/bip39/pbkdf2.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __PBKDF2_H__ +#define __PBKDF2_H__ + +#include +#include "sha2.h" + +typedef struct _PBKDF2_HMAC_SHA256_CTX { + uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; + uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)]; + char first; +} PBKDF2_HMAC_SHA256_CTX; + +typedef struct _PBKDF2_HMAC_SHA512_CTX { + uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)]; + uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; + char first; +} PBKDF2_HMAC_SHA512_CTX; + +void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); +void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); + +void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr); +void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations); +void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key); +void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen); + +#endif diff --git a/src/crypto/bip39/rand.c b/src/crypto/bip39/rand.c new file mode 100644 index 000000000..ea95d143b --- /dev/null +++ b/src/crypto/bip39/rand.c @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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. + */ + +#include "rand.h" + +#ifndef RAND_PLATFORM_INDEPENDENT + +#pragma message( \ + "NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.") + +// The following code is not supposed to be used in a production environment. +// It's included only to make the library testable. +// The message above tries to prevent any accidental use outside of the test +// environment. +// +// You are supposed to replace the random8() and random32() function with your +// own secure code. There is also a possibility to replace the random_buffer() +// function as it is defined as a weak symbol. + +static uint32_t seed = 0; + +void random_reseed(const uint32_t value) { seed = value; } + +uint32_t random32(void) { + // Linear congruential generator from Numerical Recipes + // https://en.wikipedia.org/wiki/Linear_congruential_generator + seed = 1664525 * seed + 1013904223; + return seed; +} + +#endif /* RAND_PLATFORM_INDEPENDENT */ + +// +// The following code is platform independent +// + +void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) { + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + if (i % 4 == 0) { + r = random32(); + } + buf[i] = (r >> ((i % 4) * 8)) & 0xFF; + } +} + +uint32_t random_uniform(uint32_t n) { + uint32_t x = 0, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max) + ; + return x / (max / n); +} + +void random_permute(char *str, size_t len) { + for (int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; + str[j] = str[i]; + str[i] = t; + } +} diff --git a/src/crypto/bip39/rand.h b/src/crypto/bip39/rand.h new file mode 100644 index 000000000..49d9cfaf2 --- /dev/null +++ b/src/crypto/bip39/rand.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __RAND_H__ +#define __RAND_H__ + +#include +#include + +void random_reseed(const uint32_t value); +uint32_t random32(void); +void random_buffer(uint8_t *buf, size_t len); + +uint32_t random_uniform(uint32_t n); +void random_permute(char *buf, size_t len); + +#endif diff --git a/src/crypto/bip39/secp256k1.h b/src/crypto/bip39/secp256k1.h new file mode 100644 index 000000000..234ca97a9 --- /dev/null +++ b/src/crypto/bip39/secp256k1.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * 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 __SECP256K1_H__ +#define __SECP256K1_H__ + +#include + +#include "ecdsa.h" +#include "bip32.h" + +extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; +extern const curve_info secp256k1_decred_info; +extern const curve_info secp256k1_groestl_info; +extern const curve_info secp256k1_smart_info; + +#endif diff --git a/src/crypto/bip39/sha2.c b/src/crypto/bip39/sha2.c new file mode 100644 index 000000000..b37e5cb41 --- /dev/null +++ b/src/crypto/bip39/sha2.c @@ -0,0 +1,1283 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 CONTRIBUTOR(S) 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. + */ + +#include +#include +#include "sha2.h" +#include "memzero.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ + +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA1_SHORT_BLOCK_LENGTH (SHA1_BLOCK_LENGTH - 8) +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: In the original SHA-256/384/512 document, the shift-right + * function was named R and the rotate-right function was called S. + * (See: http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf on the + * web.) + * + * The newer NIST FIPS 180-2 document uses a much clearer naming + * scheme, SHR for shift-right, ROTR for rotate-right, and ROTL for + * rotate-left. (See: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + * on the web.) + * + * WARNING: These macros must be used cautiously, since they reference + * supplied parameters sometimes more than once, and thus could have + * unexpected side-effects if used without taking this into account. + */ + +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define SHR(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define ROTR32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define ROTR64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) +/* 32-bit Rotate-left (used in SHA-1): */ +#define ROTL32(b,x) (((x) << (b)) | ((x) >> (32 - (b)))) + +/* Two of six logical functions used in SHA-1, SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Function used in SHA-1: */ +#define Parity(x,y,z) ((x) ^ (y) ^ (z)) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (ROTR32(2, (x)) ^ ROTR32(13, (x)) ^ ROTR32(22, (x))) +#define Sigma1_256(x) (ROTR32(6, (x)) ^ ROTR32(11, (x)) ^ ROTR32(25, (x))) +#define sigma0_256(x) (ROTR32(7, (x)) ^ ROTR32(18, (x)) ^ SHR(3 , (x))) +#define sigma1_256(x) (ROTR32(17, (x)) ^ ROTR32(19, (x)) ^ SHR(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (ROTR64(28, (x)) ^ ROTR64(34, (x)) ^ ROTR64(39, (x))) +#define Sigma1_512(x) (ROTR64(14, (x)) ^ ROTR64(18, (x)) ^ ROTR64(41, (x))) +#define sigma0_512(x) (ROTR64( 1, (x)) ^ ROTR64( 8, (x)) ^ SHR( 7, (x))) +#define sigma1_512(x) (ROTR64(19, (x)) ^ ROTR64(61, (x)) ^ SHR( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +static void sha512_Last(SHA512_CTX*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ + +/* Hash constant words K for SHA-1: */ +#define K1_0_TO_19 0x5a827999UL +#define K1_20_TO_39 0x6ed9eba1UL +#define K1_40_TO_59 0x8f1bbcdcUL +#define K1_60_TO_79 0xca62c1d6UL + +/* Initial hash value H for SHA-1: */ +const sha2_word32 sha1_initial_hash_value[SHA1_DIGEST_LENGTH / sizeof(sha2_word32)] = { + 0x67452301UL, + 0xefcdab89UL, + 0x98badcfeUL, + 0x10325476UL, + 0xc3d2e1f0UL +}; + +/* Hash constant words K for SHA-256: */ +static const sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +static const sha2_word64 K512[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 +}; + +/* Initial hash value H for SHA-512 */ +const sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-1: ***********************************************************/ +void sha1_Init(SHA1_CTX* context) { + MEMCPY_BCOPY(context->state, sha1_initial_hash_value, SHA1_DIGEST_LENGTH); + memzero(context->buffer, SHA1_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-1 round macros: */ + +#define ROUND1_0_TO_15(a,b,c,d,e) \ + (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ + K1_0_TO_19 + ( W1[j] = *data++ ); \ + (b) = ROTL32(30, (b)); \ + j++; + +#define ROUND1_16_TO_19(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_20_TO_39(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_40_TO_59(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +#define ROUND1_60_TO_79(a,b,c,d,e) \ + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ + (e) = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + ( W1[j&0x0f] = ROTL32(1, T1) ); \ + (b) = ROTL32(30, b); \ + j++; + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + + j = 0; + + /* Rounds 0 to 15 unrolled: */ + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + ROUND1_0_TO_15(e,a,b,c,d); + ROUND1_0_TO_15(d,e,a,b,c); + ROUND1_0_TO_15(c,d,e,a,b); + ROUND1_0_TO_15(b,c,d,e,a); + ROUND1_0_TO_15(a,b,c,d,e); + + /* Rounds 16 to 19 unrolled: */ + ROUND1_16_TO_19(e,a,b,c,d); + ROUND1_16_TO_19(d,e,a,b,c); + ROUND1_16_TO_19(c,d,e,a,b); + ROUND1_16_TO_19(b,c,d,e,a); + + /* Rounds 20 to 39 unrolled: */ + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + ROUND1_20_TO_39(a,b,c,d,e); + ROUND1_20_TO_39(e,a,b,c,d); + ROUND1_20_TO_39(d,e,a,b,c); + ROUND1_20_TO_39(c,d,e,a,b); + ROUND1_20_TO_39(b,c,d,e,a); + + /* Rounds 40 to 59 unrolled: */ + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + ROUND1_40_TO_59(a,b,c,d,e); + ROUND1_40_TO_59(e,a,b,c,d); + ROUND1_40_TO_59(d,e,a,b,c); + ROUND1_40_TO_59(c,d,e,a,b); + ROUND1_40_TO_59(b,c,d,e,a); + + /* Rounds 60 to 79 unrolled: */ + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + ROUND1_60_TO_79(a,b,c,d,e); + ROUND1_60_TO_79(e,a,b,c,d); + ROUND1_60_TO_79(d,e,a,b,c); + ROUND1_60_TO_79(c,d,e,a,b); + ROUND1_60_TO_79(b,c,d,e,a); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + j = 0; + do { + T1 = ROTL32(5, a) + Ch(b, c, d) + e + K1_0_TO_19 + (W1[j] = *data++); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 16); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Ch(b,c,d) + e + K1_0_TO_19 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 20); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_20_TO_39 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 40); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Maj(b,c,d) + e + K1_40_TO_59 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 60); + + do { + T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; + T1 = ROTL32(5, a) + Parity(b,c,d) + e + K1_60_TO_79 + (W1[j&0x0f] = ROTL32(1, T1)); + e = d; + d = c; + c = ROTL32(30, b); + b = a; + a = T1; + j++; + } while (j < 80); + + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + + /* Clean up */ + a = b = c = d = e = T1 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA1_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA1_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA1_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha1_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA1_BLOCK_LENGTH << 3; + len -= SHA1_BLOCK_LENGTH; + data += SHA1_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA1_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA1_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha1_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA1_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha1_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 5; j++) { + REVERSE32(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA1_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA1_CTX)); + usedspace = 0; +} + +char *sha1_End(SHA1_CTX* context, char buffer[]) { + sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha1_Final(context, digest); + + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA1_CTX)); + } + memzero(digest, SHA1_DIGEST_LENGTH); + return buffer; +} + +void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { + SHA1_CTX context = {0}; + sha1_Init(&context); + sha1_Update(&context, data, len); + sha1_Final(&context, digest); +} + +char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { + SHA1_CTX context = {0}; + + sha1_Init(&context); + sha1_Update(&context, data, len); + return sha1_End(&context, digest); +} + +/*** SHA-256: *********************************************************/ +void sha256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + memzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0; + sha2_word32 W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0, T2 = 0 , W256[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + sha256_Transform(context->state, context->buffer, context->state); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { + unsigned int usedspace = 0; + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha256_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA256_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE32(context->buffer[j],context->buffer[j]); + } +#endif + /* Set the bit count: */ + context->buffer[14] = context->bitcount >> 32; + context->buffer[15] = context->bitcount & 0xffffffff; + + /* Final transform: */ + sha256_Transform(context->state, context->buffer, context->state); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA256_DIGEST_LENGTH); + } + + /* Clean up state data: */ + memzero(context, sizeof(SHA256_CTX)); + usedspace = 0; +} + +char *sha256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha256_Final(context, digest); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA256_CTX)); + } + memzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { + SHA256_CTX context = {0}; + sha256_Init(&context); + sha256_Update(&context, data, len); + sha256_Final(&context, digest); +} + +char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context = {0}; + + sha256_Init(&context); + sha256_Update(&context, data, len); + return sha256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void sha512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + memzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, T2 = 0, W512[16] = {0}; + int j = 0; + + /* Initialize registers with the prev. intermediate value */ + a = state_in[0]; + b = state_in[1]; + c = state_in[2]; + d = state_in[3]; + e = state_in[4]; + f = state_in[5]; + g = state_in[6]; + h = state_in[7]; + + j = 0; + do { + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + state_out[0] = state_in[0] + a; + state_out[1] = state_in[1] + b; + state_out[2] = state_in[2] + c; + state_out[3] = state_in[3] + d; + state_out[4] = state_in[4] + e; + state_out[5] = state_in[5] + f; + state_out[6] = state_in[6] + g; + state_out[7] = state_in[7] + h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace = 0, usedspace = 0; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(((uint8_t*)context->buffer) + usedspace, data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + sha512_Transform(context->state, context->buffer, context->state); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +static void sha512_Last(SHA512_CTX* context) { + unsigned int usedspace = 0; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + /* Begin padding with a 1 bit: */ + ((uint8_t*)context->buffer)[usedspace++] = 0x80; + + if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 16; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + /* Do second-to-last transform: */ + sha512_Transform(context->state, context->buffer, context->state); + + /* And prepare the last transform: */ + usedspace = 0; + } + /* Set-up for the last transform: */ + memzero(((uint8_t*)context->buffer) + usedspace, SHA512_SHORT_BLOCK_LENGTH - usedspace); + +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + for (int j = 0; j < 14; j++) { + REVERSE64(context->buffer[j],context->buffer[j]); + } +#endif + /* Store the length of input data (in bits): */ + context->buffer[14] = context->bitcount[1]; + context->buffer[15] = context->bitcount[0]; + + /* Final transform: */ + sha512_Transform(context->state, context->buffer, context->state); +} + +void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + sha512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + for (int j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + } +#endif + MEMCPY_BCOPY(digest, context->state, SHA512_DIGEST_LENGTH); + } + + /* Zero out state data */ + memzero(context, sizeof(SHA512_CTX)); +} + +char *sha512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; + + if (buffer != (char*)0) { + sha512_Final(context, digest); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + memzero(context, sizeof(SHA512_CTX)); + } + memzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { + SHA512_CTX context = {0}; + sha512_Init(&context); + sha512_Update(&context, data, len); + sha512_Final(&context, digest); +} + +char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context = {0}; + + sha512_Init(&context); + sha512_Update(&context, data, len); + return sha512_End(&context, digest); +} diff --git a/src/crypto/bip39/sha2.h b/src/crypto/bip39/sha2.h new file mode 100644 index 000000000..7f519c50b --- /dev/null +++ b/src/crypto/bip39/sha2.h @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013-2014 Pavol Rusnak + * 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. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 CONTRIBUTOR(S) 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. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#include +#include + +#define SHA1_BLOCK_LENGTH 64 +#define SHA1_DIGEST_LENGTH 20 +#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + +typedef struct _SHA1_CTX { + uint32_t state[5]; + uint64_t bitcount; + uint32_t buffer[SHA1_BLOCK_LENGTH/sizeof(uint32_t)]; +} SHA1_CTX; +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint32_t buffer[SHA256_BLOCK_LENGTH/sizeof(uint32_t)]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint64_t buffer[SHA512_BLOCK_LENGTH/sizeof(uint64_t)]; +} SHA512_CTX; + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#endif + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +extern const uint32_t sha256_initial_hash_value[8]; +extern const uint64_t sha512_initial_hash_value[8]; + +void sha1_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha1_Init(SHA1_CTX *); +void sha1_Update(SHA1_CTX*, const uint8_t*, size_t); +void sha1_Final(SHA1_CTX*, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_End(SHA1_CTX*, char[SHA1_DIGEST_STRING_LENGTH]); +void sha1_Raw(const uint8_t*, size_t, uint8_t[SHA1_DIGEST_LENGTH]); +char* sha1_Data(const uint8_t*, size_t, char[SHA1_DIGEST_STRING_LENGTH]); + +void sha256_Transform(const uint32_t* state_in, const uint32_t* data, uint32_t* state_out); +void sha256_Init(SHA256_CTX *); +void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); +void sha256_Final(SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); +void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); +char* sha256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); + +void sha512_Transform(const uint64_t* state_in, const uint64_t* data, uint64_t* state_out); +void sha512_Init(SHA512_CTX*); +void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); +void sha512_Final(SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); +void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); +char* sha512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); + +#endif diff --git a/src/crypto/bip39/sha3.c b/src/crypto/bip39/sha3.c new file mode 100644 index 000000000..80ac28ff6 --- /dev/null +++ b/src/crypto/bip39/sha3.c @@ -0,0 +1,397 @@ +/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * 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. + * + * 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. Use this program at your own risk! + */ + +#include +#include + +#include "sha3.h" +#include "memzero.h" + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ +#define NumberOfRounds 24 + +/* SHA3 (Keccak) constants for 24 rounds */ +static uint64_t keccak_round_constants[NumberOfRounds] = { + I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000), + I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009), + I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A), + I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003), + I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A), + I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008) +}; + +/* Initializing a sha3 context for given number of output bits */ +static void keccak_Init(SHA3_CTX *ctx, unsigned bits) +{ + /* NB: The Keccak capacity parameter = bits * 2 */ + unsigned rate = 1600 - bits * 2; + + memzero(ctx, sizeof(SHA3_CTX)); + ctx->block_size = rate / 8; + assert(rate <= 1600 && (rate % 64) == 0); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_224_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 224); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_256_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 256); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_384_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 384); +} + +/** + * Initialize context before calculating hash. + * + * @param ctx context to initialize + */ +void sha3_512_Init(SHA3_CTX *ctx) +{ + keccak_Init(ctx, 512); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) +{ + unsigned int x = 0; + uint64_t C[5] = {0}, D[5] = {0}; + + for (x = 0; x < 5; x++) { + C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + } + D[0] = ROTL64(C[1], 1) ^ C[4]; + D[1] = ROTL64(C[2], 1) ^ C[0]; + D[2] = ROTL64(C[3], 1) ^ C[1]; + D[3] = ROTL64(C[4], 1) ^ C[2]; + D[4] = ROTL64(C[0], 1) ^ C[3]; + + for (x = 0; x < 5; x++) { + A[x] ^= D[x]; + A[x + 5] ^= D[x]; + A[x + 10] ^= D[x]; + A[x + 15] ^= D[x]; + A[x + 20] ^= D[x]; + } +} + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) +{ + uint64_t A1 = 0; + A1 = A[1]; + A[ 1] = A[ 6]; + A[ 6] = A[ 9]; + A[ 9] = A[22]; + A[22] = A[14]; + A[14] = A[20]; + A[20] = A[ 2]; + A[ 2] = A[12]; + A[12] = A[13]; + A[13] = A[19]; + A[19] = A[23]; + A[23] = A[15]; + A[15] = A[ 4]; + A[ 4] = A[24]; + A[24] = A[21]; + A[21] = A[ 8]; + A[ 8] = A[16]; + A[16] = A[ 5]; + A[ 5] = A[ 3]; + A[ 3] = A[18]; + A[18] = A[17]; + A[17] = A[11]; + A[11] = A[ 7]; + A[ 7] = A[10]; + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) +{ + int i = 0; + for (i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + +static void sha3_permutation(uint64_t *state) +{ + int round = 0; + for (round = 0; round < NumberOfRounds; round++) + { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + state[ 1] = ROTL64(state[ 1], 1); + state[ 2] = ROTL64(state[ 2], 62); + state[ 3] = ROTL64(state[ 3], 28); + state[ 4] = ROTL64(state[ 4], 27); + state[ 5] = ROTL64(state[ 5], 36); + state[ 6] = ROTL64(state[ 6], 44); + state[ 7] = ROTL64(state[ 7], 6); + state[ 8] = ROTL64(state[ 8], 55); + state[ 9] = ROTL64(state[ 9], 20); + state[10] = ROTL64(state[10], 3); + state[11] = ROTL64(state[11], 10); + state[12] = ROTL64(state[12], 43); + state[13] = ROTL64(state[13], 25); + state[14] = ROTL64(state[14], 39); + state[15] = ROTL64(state[15], 41); + state[16] = ROTL64(state[16], 45); + state[17] = ROTL64(state[17], 15); + state[18] = ROTL64(state[18], 21); + state[19] = ROTL64(state[19], 8); + state[20] = ROTL64(state[20], 18); + state[21] = ROTL64(state[21], 2); + state[22] = ROTL64(state[22], 61); + state[23] = ROTL64(state[23], 56); + state[24] = ROTL64(state[24], 14); + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= keccak_round_constants[round]; + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size) +{ + /* expanded loop */ + hash[ 0] ^= le2me_64(block[ 0]); + hash[ 1] ^= le2me_64(block[ 1]); + hash[ 2] ^= le2me_64(block[ 2]); + hash[ 3] ^= le2me_64(block[ 3]); + hash[ 4] ^= le2me_64(block[ 4]); + hash[ 5] ^= le2me_64(block[ 5]); + hash[ 6] ^= le2me_64(block[ 6]); + hash[ 7] ^= le2me_64(block[ 7]); + hash[ 8] ^= le2me_64(block[ 8]); + /* if not sha3-512 */ + if (block_size > 72) { + hash[ 9] ^= le2me_64(block[ 9]); + hash[10] ^= le2me_64(block[10]); + hash[11] ^= le2me_64(block[11]); + hash[12] ^= le2me_64(block[12]); + /* if not sha3-384 */ + if (block_size > 104) { + hash[13] ^= le2me_64(block[13]); + hash[14] ^= le2me_64(block[14]); + hash[15] ^= le2me_64(block[15]); + hash[16] ^= le2me_64(block[16]); + /* if not sha3-256 */ + if (block_size > 136) { + hash[17] ^= le2me_64(block[17]); +#ifdef FULL_SHA3_FAMILY_SUPPORT + /* if not sha3-224 */ + if (block_size > 144) { + hash[18] ^= le2me_64(block[18]); + hash[19] ^= le2me_64(block[19]); + hash[20] ^= le2me_64(block[20]); + hash[21] ^= le2me_64(block[21]); + hash[22] ^= le2me_64(block[22]); + hash[23] ^= le2me_64(block[23]); + hash[24] ^= le2me_64(block[24]); + } +#endif + } + } + } + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +#define SHA3_FINALIZED 0x80000000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void sha3_Update(SHA3_CTX *ctx, const unsigned char *msg, size_t size) +{ + size_t idx = (size_t)ctx->rest; + size_t block_size = (size_t)ctx->block_size; + + if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % block_size); + + /* fill partial block */ + if (idx) { + size_t left = block_size - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + msg += left; + size -= left; + } + while (size >= block_size) { + uint64_t *aligned_message_block = NULL; + if (IS_ALIGNED_64(msg)) { + /* the most common case is processing of an already aligned message + without copying it */ + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, block_size); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block, block_size); + msg += block_size; + size -= block_size; + } + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** + * Store calculated hash into the given array. + * + * @param ctx the algorithm context containing current hashing state + * @param result calculated hash in binary form + */ +void sha3_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x06; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +#if USE_KECCAK +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_Final(SHA3_CTX *ctx, unsigned char* result) +{ + size_t digest_length = 100 - ctx->block_size / 2; + const size_t block_size = ctx->block_size; + + if (!(ctx->rest & SHA3_FINALIZED)) + { + /* clear the rest of the data queue */ + memzero((char*)ctx->message + ctx->rest, block_size - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[block_size - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message, block_size); + ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ + } + + assert(block_size > digest_length); + if (result) me64_to_le_str(result, ctx->hash, digest_length); + memzero(ctx, sizeof(SHA3_CTX)); +} + +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_256_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} + +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + keccak_512_Init(&ctx); + keccak_Update(&ctx, data, len); + keccak_Final(&ctx, digest); +} +#endif /* USE_KECCAK */ + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_256_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} + +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest) +{ + SHA3_CTX ctx = {0}; + sha3_512_Init(&ctx); + sha3_Update(&ctx, data, len); + sha3_Final(&ctx, digest); +} diff --git a/src/crypto/bip39/sha3.h b/src/crypto/bip39/sha3.h new file mode 100644 index 000000000..367369d4d --- /dev/null +++ b/src/crypto/bip39/sha3.h @@ -0,0 +1,89 @@ +/* sha3.h - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * 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. + * + * 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. Use this program at your own risk! + */ + +#ifndef __SHA3_H__ +#define __SHA3_H__ + +#include +#include "options.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +#define SHA3_224_BLOCK_LENGTH 144 +#define SHA3_256_BLOCK_LENGTH 136 +#define SHA3_384_BLOCK_LENGTH 104 +#define SHA3_512_BLOCK_LENGTH 72 + +#define SHA3_224_DIGEST_LENGTH sha3_224_hash_size +#define SHA3_256_DIGEST_LENGTH sha3_256_hash_size +#define SHA3_384_DIGEST_LENGTH sha3_384_hash_size +#define SHA3_512_DIGEST_LENGTH sha3_512_hash_size + +/** + * SHA3 Algorithm context. + */ +typedef struct SHA3_CTX +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} SHA3_CTX; + +/* methods for calculating the hash function */ + +void sha3_224_Init(SHA3_CTX *ctx); +void sha3_256_Init(SHA3_CTX *ctx); +void sha3_384_Init(SHA3_CTX *ctx); +void sha3_512_Init(SHA3_CTX *ctx); +void sha3_Update(SHA3_CTX *ctx, const unsigned char* msg, size_t size); +void sha3_Final(SHA3_CTX *ctx, unsigned char* result); + +#if USE_KECCAK +#define keccak_224_Init sha3_224_Init +#define keccak_256_Init sha3_256_Init +#define keccak_384_Init sha3_384_Init +#define keccak_512_Init sha3_512_Init +#define keccak_Update sha3_Update +void keccak_Final(SHA3_CTX *ctx, unsigned char* result); +void keccak_256(const unsigned char* data, size_t len, unsigned char* digest); +void keccak_512(const unsigned char* data, size_t len, unsigned char* digest); +#endif + +void sha3_256(const unsigned char* data, size_t len, unsigned char* digest); +void sha3_512(const unsigned char* data, size_t len, unsigned char* digest); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __SHA3_H__ */ diff --git a/src/crypto/ctaes/COPYING b/src/crypto/ctaes/COPYING new file mode 100644 index 000000000..415b202a2 --- /dev/null +++ b/src/crypto/ctaes/COPYING @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 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/crypto/ctaes/README.md b/src/crypto/ctaes/README.md new file mode 100644 index 000000000..0e7fe1775 --- /dev/null +++ b/src/crypto/ctaes/README.md @@ -0,0 +1,41 @@ +ctaes +===== + +Simple C module for constant-time AES encryption and decryption. + +Features: +* Simple, pure C code without any dependencies. +* No tables or data-dependent branches whatsoever, but using bit sliced approach from https://eprint.iacr.org/2009/129.pdf. +* Very small object code: slightly over 4k of executable code when compiled with -Os. +* Slower than implementations based on precomputed tables or specialized instructions, but can do ~15 MB/s on modern CPUs. + +Performance +----------- + +Compiled with GCC 5.3.1 with -O3, on an Intel(R) Core(TM) i7-4800MQ CPU, numbers in CPU cycles: + +| Algorithm | Key schedule | Encryption per byte | Decryption per byte | +| --------- | ------------:| -------------------:| -------------------:| +| AES-128 | 2.8k | 154 | 161 | +| AES-192 | 3.1k | 169 | 181 | +| AES-256 | 4.0k | 191 | 203 | + +Build steps +----------- + +Object code: + + $ gcc -O3 ctaes.c -c -o ctaes.o + +Tests: + + $ gcc -O3 ctaes.c test.c -o test + +Benchmark: + + $ gcc -O3 ctaes.c bench.c -o bench + +Review +------ + +Results of a formal review of the code can be found in http://bitcoin.sipa.be/ctaes/review.zip diff --git a/src/crypto/ctaes/bench.c b/src/crypto/ctaes/bench.c new file mode 100644 index 000000000..a86df496c --- /dev/null +++ b/src/crypto/ctaes/bench.c @@ -0,0 +1,170 @@ +#include +#include +#include "sys/time.h" + +#include "ctaes.h" + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +static void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) { + y = -y; + } + while (y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +static 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 * 1000000000.0 / iter); + printf("ns / avg "); + print_number((sum / count) * 1000000000.0 / iter); + printf("ns / max "); + print_number(max * 1000000000.0 / iter); + printf("ns\n"); +} + +static void bench_AES128_init(void* data) { + AES128_ctx* ctx = (AES128_ctx*)data; + int i; + for (i = 0; i < 50000; i++) { + AES128_init(ctx, (unsigned char*)ctx); + } +} + +static void bench_AES128_encrypt_setup(void* data) { + AES128_ctx* ctx = (AES128_ctx*)data; + static const unsigned char key[16] = {0}; + AES128_init(ctx, key); +} + +static void bench_AES128_encrypt(void* data) { + const AES128_ctx* ctx = (const AES128_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES128_encrypt(ctx, 1, scratch, scratch); + } +} + +static void bench_AES128_decrypt(void* data) { + const AES128_ctx* ctx = (const AES128_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES128_decrypt(ctx, 1, scratch, scratch); + } +} + +static void bench_AES192_init(void* data) { + AES192_ctx* ctx = (AES192_ctx*)data; + int i; + for (i = 0; i < 50000; i++) { + AES192_init(ctx, (unsigned char*)ctx); + } +} + +static void bench_AES192_encrypt_setup(void* data) { + AES192_ctx* ctx = (AES192_ctx*)data; + static const unsigned char key[16] = {0}; + AES192_init(ctx, key); +} + +static void bench_AES192_encrypt(void* data) { + const AES192_ctx* ctx = (const AES192_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES192_encrypt(ctx, 1, scratch, scratch); + } +} + +static void bench_AES192_decrypt(void* data) { + const AES192_ctx* ctx = (const AES192_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES192_decrypt(ctx, 1, scratch, scratch); + } +} + +static void bench_AES256_init(void* data) { + AES256_ctx* ctx = (AES256_ctx*)data; + int i; + for (i = 0; i < 50000; i++) { + AES256_init(ctx, (unsigned char*)ctx); + } +} + + +static void bench_AES256_encrypt_setup(void* data) { + AES256_ctx* ctx = (AES256_ctx*)data; + static const unsigned char key[16] = {0}; + AES256_init(ctx, key); +} + +static void bench_AES256_encrypt(void* data) { + const AES256_ctx* ctx = (const AES256_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES256_encrypt(ctx, 1, scratch, scratch); + } +} + +static void bench_AES256_decrypt(void* data) { + const AES256_ctx* ctx = (const AES256_ctx*)data; + unsigned char scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + AES256_decrypt(ctx, 1, scratch, scratch); + } +} + +int main(void) { + AES128_ctx ctx128; + AES192_ctx ctx192; + AES256_ctx ctx256; + run_benchmark("aes128_init", bench_AES128_init, NULL, NULL, &ctx128, 20, 50000); + run_benchmark("aes128_encrypt_byte", bench_AES128_encrypt, bench_AES128_encrypt_setup, NULL, &ctx128, 20, 4000000); + run_benchmark("aes128_decrypt_byte", bench_AES128_decrypt, bench_AES128_encrypt_setup, NULL, &ctx128, 20, 4000000); + run_benchmark("aes192_init", bench_AES192_init, NULL, NULL, &ctx192, 20, 50000); + run_benchmark("aes192_encrypt_byte", bench_AES192_encrypt, bench_AES192_encrypt_setup, NULL, &ctx192, 20, 4000000); + run_benchmark("aes192_decrypt_byte", bench_AES192_decrypt, bench_AES192_encrypt_setup, NULL, &ctx192, 20, 4000000); + run_benchmark("aes256_init", bench_AES256_init, NULL, NULL, &ctx256, 20, 50000); + run_benchmark("aes256_encrypt_byte", bench_AES256_encrypt, bench_AES256_encrypt_setup, NULL, &ctx256, 20, 4000000); + run_benchmark("aes256_decrypt_byte", bench_AES256_decrypt, bench_AES256_encrypt_setup, NULL, &ctx256, 20, 4000000); + return 0; +} diff --git a/src/crypto/ctaes/ctaes.c b/src/crypto/ctaes/ctaes.c new file mode 100644 index 000000000..55962bf25 --- /dev/null +++ b/src/crypto/ctaes/ctaes.c @@ -0,0 +1,556 @@ + /********************************************************************* + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/* Constant time, unoptimized, concise, plain C, AES implementation + * Based On: + * Emilia Kasper and Peter Schwabe, Faster and Timing-Attack Resistant AES-GCM + * http://www.iacr.org/archive/ches2009/57470001/57470001.pdf + * But using 8 16-bit integers representing a single AES state rather than 8 128-bit + * integers representing 8 AES states. + */ + +#include "ctaes.h" + +/* Slice variable slice_i contains the i'th bit of the 16 state variables in this order: + * 0 1 2 3 + * 4 5 6 7 + * 8 9 10 11 + * 12 13 14 15 + */ + +/** Convert a byte to sliced form, storing it corresponding to given row and column in s */ +static void LoadByte(AES_state* s, unsigned char byte, int r, int c) { + int i; + for (i = 0; i < 8; i++) { + s->slice[i] |= (byte & 1) << (r * 4 + c); + byte >>= 1; + } +} + +/** Load 16 bytes of data into 8 sliced integers */ +static void LoadBytes(AES_state *s, const unsigned char* data16) { + int c; + for (c = 0; c < 4; c++) { + int r; + for (r = 0; r < 4; r++) { + LoadByte(s, *(data16++), r, c); + } + } +} + +/** Convert 8 sliced integers into 16 bytes of data */ +static void SaveBytes(unsigned char* data16, const AES_state *s) { + int c; + for (c = 0; c < 4; c++) { + int r; + for (r = 0; r < 4; r++) { + int b; + uint8_t v = 0; + for (b = 0; b < 8; b++) { + v |= ((s->slice[b] >> (r * 4 + c)) & 1) << b; + } + *(data16++) = v; + } + } +} + +/* S-box implementation based on the gate logic from: + * Joan Boyar and Rene Peralta, A depth-16 circuit for the AES S-box. + * https://eprint.iacr.org/2011/332.pdf +*/ +static void SubBytes(AES_state *s, int inv) { + /* Load the bit slices */ + uint16_t U0 = s->slice[7], U1 = s->slice[6], U2 = s->slice[5], U3 = s->slice[4]; + uint16_t U4 = s->slice[3], U5 = s->slice[2], U6 = s->slice[1], U7 = s->slice[0]; + + uint16_t T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16; + uint16_t T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, D; + uint16_t M1, M6, M11, M13, M15, M20, M21, M22, M23, M25, M37, M38, M39, M40; + uint16_t M41, M42, M43, M44, M45, M46, M47, M48, M49, M50, M51, M52, M53, M54; + uint16_t M55, M56, M57, M58, M59, M60, M61, M62, M63; + + if (inv) { + uint16_t R5, R13, R17, R18, R19; + /* Undo linear postprocessing */ + T23 = U0 ^ U3; + T22 = ~(U1 ^ U3); + T2 = ~(U0 ^ U1); + T1 = U3 ^ U4; + T24 = ~(U4 ^ U7); + R5 = U6 ^ U7; + T8 = ~(U1 ^ T23); + T19 = T22 ^ R5; + T9 = ~(U7 ^ T1); + T10 = T2 ^ T24; + T13 = T2 ^ R5; + T3 = T1 ^ R5; + T25 = ~(U2 ^ T1); + R13 = U1 ^ U6; + T17 = ~(U2 ^ T19); + T20 = T24 ^ R13; + T4 = U4 ^ T8; + R17 = ~(U2 ^ U5); + R18 = ~(U5 ^ U6); + R19 = ~(U2 ^ U4); + D = U0 ^ R17; + T6 = T22 ^ R17; + T16 = R13 ^ R19; + T27 = T1 ^ R18; + T15 = T10 ^ T27; + T14 = T10 ^ R18; + T26 = T3 ^ T16; + } else { + /* Linear preprocessing. */ + T1 = U0 ^ U3; + T2 = U0 ^ U5; + T3 = U0 ^ U6; + T4 = U3 ^ U5; + T5 = U4 ^ U6; + T6 = T1 ^ T5; + T7 = U1 ^ U2; + T8 = U7 ^ T6; + T9 = U7 ^ T7; + T10 = T6 ^ T7; + T11 = U1 ^ U5; + T12 = U2 ^ U5; + T13 = T3 ^ T4; + T14 = T6 ^ T11; + T15 = T5 ^ T11; + T16 = T5 ^ T12; + T17 = T9 ^ T16; + T18 = U3 ^ U7; + T19 = T7 ^ T18; + T20 = T1 ^ T19; + T21 = U6 ^ U7; + T22 = T7 ^ T21; + T23 = T2 ^ T22; + T24 = T2 ^ T10; + T25 = T20 ^ T17; + T26 = T3 ^ T16; + T27 = T1 ^ T12; + D = U7; + } + + /* Non-linear transformation (shared between the forward and backward case) */ + M1 = T13 & T6; + M6 = T3 & T16; + M11 = T1 & T15; + M13 = (T4 & T27) ^ M11; + M15 = (T2 & T10) ^ M11; + M20 = T14 ^ M1 ^ (T23 & T8) ^ M13; + M21 = (T19 & D) ^ M1 ^ T24 ^ M15; + M22 = T26 ^ M6 ^ (T22 & T9) ^ M13; + M23 = (T20 & T17) ^ M6 ^ M15 ^ T25; + M25 = M22 & M20; + M37 = M21 ^ ((M20 ^ M21) & (M23 ^ M25)); + M38 = M20 ^ M25 ^ (M21 | (M20 & M23)); + M39 = M23 ^ ((M22 ^ M23) & (M21 ^ M25)); + M40 = M22 ^ M25 ^ (M23 | (M21 & M22)); + M41 = M38 ^ M40; + M42 = M37 ^ M39; + M43 = M37 ^ M38; + M44 = M39 ^ M40; + M45 = M42 ^ M41; + M46 = M44 & T6; + M47 = M40 & T8; + M48 = M39 & D; + M49 = M43 & T16; + M50 = M38 & T9; + M51 = M37 & T17; + M52 = M42 & T15; + M53 = M45 & T27; + M54 = M41 & T10; + M55 = M44 & T13; + M56 = M40 & T23; + M57 = M39 & T19; + M58 = M43 & T3; + M59 = M38 & T22; + M60 = M37 & T20; + M61 = M42 & T1; + M62 = M45 & T4; + M63 = M41 & T2; + + if (inv){ + /* Undo linear preprocessing */ + uint16_t P0 = M52 ^ M61; + uint16_t P1 = M58 ^ M59; + uint16_t P2 = M54 ^ M62; + uint16_t P3 = M47 ^ M50; + uint16_t P4 = M48 ^ M56; + uint16_t P5 = M46 ^ M51; + uint16_t P6 = M49 ^ M60; + uint16_t P7 = P0 ^ P1; + uint16_t P8 = M50 ^ M53; + uint16_t P9 = M55 ^ M63; + uint16_t P10 = M57 ^ P4; + uint16_t P11 = P0 ^ P3; + uint16_t P12 = M46 ^ M48; + uint16_t P13 = M49 ^ M51; + uint16_t P14 = M49 ^ M62; + uint16_t P15 = M54 ^ M59; + uint16_t P16 = M57 ^ M61; + uint16_t P17 = M58 ^ P2; + uint16_t P18 = M63 ^ P5; + uint16_t P19 = P2 ^ P3; + uint16_t P20 = P4 ^ P6; + uint16_t P22 = P2 ^ P7; + uint16_t P23 = P7 ^ P8; + uint16_t P24 = P5 ^ P7; + uint16_t P25 = P6 ^ P10; + uint16_t P26 = P9 ^ P11; + uint16_t P27 = P10 ^ P18; + uint16_t P28 = P11 ^ P25; + uint16_t P29 = P15 ^ P20; + s->slice[7] = P13 ^ P22; + s->slice[6] = P26 ^ P29; + s->slice[5] = P17 ^ P28; + s->slice[4] = P12 ^ P22; + s->slice[3] = P23 ^ P27; + s->slice[2] = P19 ^ P24; + s->slice[1] = P14 ^ P23; + s->slice[0] = P9 ^ P16; + } else { + /* Linear postprocessing */ + uint16_t L0 = M61 ^ M62; + uint16_t L1 = M50 ^ M56; + uint16_t L2 = M46 ^ M48; + uint16_t L3 = M47 ^ M55; + uint16_t L4 = M54 ^ M58; + uint16_t L5 = M49 ^ M61; + uint16_t L6 = M62 ^ L5; + uint16_t L7 = M46 ^ L3; + uint16_t L8 = M51 ^ M59; + uint16_t L9 = M52 ^ M53; + uint16_t L10 = M53 ^ L4; + uint16_t L11 = M60 ^ L2; + uint16_t L12 = M48 ^ M51; + uint16_t L13 = M50 ^ L0; + uint16_t L14 = M52 ^ M61; + uint16_t L15 = M55 ^ L1; + uint16_t L16 = M56 ^ L0; + uint16_t L17 = M57 ^ L1; + uint16_t L18 = M58 ^ L8; + uint16_t L19 = M63 ^ L4; + uint16_t L20 = L0 ^ L1; + uint16_t L21 = L1 ^ L7; + uint16_t L22 = L3 ^ L12; + uint16_t L23 = L18 ^ L2; + uint16_t L24 = L15 ^ L9; + uint16_t L25 = L6 ^ L10; + uint16_t L26 = L7 ^ L9; + uint16_t L27 = L8 ^ L10; + uint16_t L28 = L11 ^ L14; + uint16_t L29 = L11 ^ L17; + s->slice[7] = L6 ^ L24; + s->slice[6] = ~(L16 ^ L26); + s->slice[5] = ~(L19 ^ L28); + s->slice[4] = L6 ^ L21; + s->slice[3] = L20 ^ L22; + s->slice[2] = L25 ^ L29; + s->slice[1] = ~(L13 ^ L27); + s->slice[0] = ~(L6 ^ L23); + } +} + +#define BIT_RANGE(from,to) (((1 << ((to) - (from))) - 1) << (from)) + +#define BIT_RANGE_LEFT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) << (shift)) +#define BIT_RANGE_RIGHT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) >> (shift)) + +static void ShiftRows(AES_state* s) { + int i; + for (i = 0; i < 8; i++) { + uint16_t v = s->slice[i]; + s->slice[i] = + (v & BIT_RANGE(0, 4)) | + BIT_RANGE_LEFT(v, 4, 5, 3) | BIT_RANGE_RIGHT(v, 5, 8, 1) | + BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) | + BIT_RANGE_LEFT(v, 12, 15, 1) | BIT_RANGE_RIGHT(v, 15, 16, 3); + } +} + +static void InvShiftRows(AES_state* s) { + int i; + for (i = 0; i < 8; i++) { + uint16_t v = s->slice[i]; + s->slice[i] = + (v & BIT_RANGE(0, 4)) | + BIT_RANGE_LEFT(v, 4, 7, 1) | BIT_RANGE_RIGHT(v, 7, 8, 3) | + BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) | + BIT_RANGE_LEFT(v, 12, 13, 3) | BIT_RANGE_RIGHT(v, 13, 16, 1); + } +} + +#define ROT(x,b) (((x) >> ((b) * 4)) | ((x) << ((4-(b)) * 4))) + +static void MixColumns(AES_state* s, int inv) { + /* The MixColumns transform treats the bytes of the columns of the state as + * coefficients of a 3rd degree polynomial over GF(2^8) and multiplies them + * by the fixed polynomial a(x) = {03}x^3 + {01}x^2 + {01}x + {02}, modulo + * x^4 + {01}. + * + * In the inverse transform, we multiply by the inverse of a(x), + * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. This is equal to + * a(x) * ({04}x^2 + {05}), so we can reuse the forward transform's code + * (found in OpenSSL's bsaes-x86_64.pl, attributed to Jussi Kivilinna) + * + * In the bitsliced representation, a multiplication of every column by x + * mod x^4 + 1 is simply a right rotation. + */ + + /* Shared for both directions is a multiplication by a(x), which can be + * rewritten as (x^3 + x^2 + x) + {02}*(x^3 + {01}). + * + * First compute s into the s? variables, (x^3 + {01}) * s into the s?_01 + * variables and (x^3 + x^2 + x)*s into the s?_123 variables. + */ + uint16_t s0 = s->slice[0], s1 = s->slice[1], s2 = s->slice[2], s3 = s->slice[3]; + uint16_t s4 = s->slice[4], s5 = s->slice[5], s6 = s->slice[6], s7 = s->slice[7]; + uint16_t s0_01 = s0 ^ ROT(s0, 1), s0_123 = ROT(s0_01, 1) ^ ROT(s0, 3); + uint16_t s1_01 = s1 ^ ROT(s1, 1), s1_123 = ROT(s1_01, 1) ^ ROT(s1, 3); + uint16_t s2_01 = s2 ^ ROT(s2, 1), s2_123 = ROT(s2_01, 1) ^ ROT(s2, 3); + uint16_t s3_01 = s3 ^ ROT(s3, 1), s3_123 = ROT(s3_01, 1) ^ ROT(s3, 3); + uint16_t s4_01 = s4 ^ ROT(s4, 1), s4_123 = ROT(s4_01, 1) ^ ROT(s4, 3); + uint16_t s5_01 = s5 ^ ROT(s5, 1), s5_123 = ROT(s5_01, 1) ^ ROT(s5, 3); + uint16_t s6_01 = s6 ^ ROT(s6, 1), s6_123 = ROT(s6_01, 1) ^ ROT(s6, 3); + uint16_t s7_01 = s7 ^ ROT(s7, 1), s7_123 = ROT(s7_01, 1) ^ ROT(s7, 3); + /* Now compute s = s?_123 + {02} * s?_01. */ + s->slice[0] = s7_01 ^ s0_123; + s->slice[1] = s7_01 ^ s0_01 ^ s1_123; + s->slice[2] = s1_01 ^ s2_123; + s->slice[3] = s7_01 ^ s2_01 ^ s3_123; + s->slice[4] = s7_01 ^ s3_01 ^ s4_123; + s->slice[5] = s4_01 ^ s5_123; + s->slice[6] = s5_01 ^ s6_123; + s->slice[7] = s6_01 ^ s7_123; + if (inv) { + /* In the reverse direction, we further need to multiply by + * {04}x^2 + {05}, which can be written as {04} * (x^2 + {01}) + {01}. + * + * First compute (x^2 + {01}) * s into the t?_02 variables: */ + uint16_t t0_02 = s->slice[0] ^ ROT(s->slice[0], 2); + uint16_t t1_02 = s->slice[1] ^ ROT(s->slice[1], 2); + uint16_t t2_02 = s->slice[2] ^ ROT(s->slice[2], 2); + uint16_t t3_02 = s->slice[3] ^ ROT(s->slice[3], 2); + uint16_t t4_02 = s->slice[4] ^ ROT(s->slice[4], 2); + uint16_t t5_02 = s->slice[5] ^ ROT(s->slice[5], 2); + uint16_t t6_02 = s->slice[6] ^ ROT(s->slice[6], 2); + uint16_t t7_02 = s->slice[7] ^ ROT(s->slice[7], 2); + /* And then update s += {04} * t?_02 */ + s->slice[0] ^= t6_02; + s->slice[1] ^= t6_02 ^ t7_02; + s->slice[2] ^= t0_02 ^ t7_02; + s->slice[3] ^= t1_02 ^ t6_02; + s->slice[4] ^= t2_02 ^ t6_02 ^ t7_02; + s->slice[5] ^= t3_02 ^ t7_02; + s->slice[6] ^= t4_02; + s->slice[7] ^= t5_02; + } +} + +static void AddRoundKey(AES_state* s, const AES_state* round) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] ^= round->slice[b]; + } +} + +/** column_0(s) = column_c(a) */ +static void GetOneColumn(AES_state* s, const AES_state* a, int c) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] = (a->slice[b] >> c) & 0x1111; + } +} + +/** column_c1(r) |= (column_0(s) ^= column_c2(a)) */ +static void KeySetupColumnMix(AES_state* s, AES_state* r, const AES_state* a, int c1, int c2) { + int b; + for (b = 0; b < 8; b++) { + r->slice[b] |= ((s->slice[b] ^= ((a->slice[b] >> c2) & 0x1111)) & 0x1111) << c1; + } +} + +/** Rotate the rows in s one position upwards, and xor in r */ +static void KeySetupTransform(AES_state* s, const AES_state* r) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] = ((s->slice[b] >> 4) | (s->slice[b] << 12)) ^ r->slice[b]; + } +} + +/* Multiply the cells in s by x, as polynomials over GF(2) mod x^8 + x^4 + x^3 + x + 1 */ +static void MultX(AES_state* s) { + uint16_t top = s->slice[7]; + s->slice[7] = s->slice[6]; + s->slice[6] = s->slice[5]; + s->slice[5] = s->slice[4]; + s->slice[4] = s->slice[3] ^ top; + s->slice[3] = s->slice[2] ^ top; + s->slice[2] = s->slice[1]; + s->slice[1] = s->slice[0] ^ top; + s->slice[0] = top; +} + +/** Expand the cipher key into the key schedule. + * + * state must be a pointer to an array of size nrounds + 1. + * key must be a pointer to 4 * nkeywords bytes. + * + * AES128 uses nkeywords = 4, nrounds = 10 + * AES192 uses nkeywords = 6, nrounds = 12 + * AES256 uses nkeywords = 8, nrounds = 14 + */ +static void AES_setup(AES_state* rounds, const uint8_t* key, int nkeywords, int nrounds) +{ + int i; + + /* The one-byte round constant */ + AES_state rcon = {{1,0,0,0,0,0,0,0}}; + /* The number of the word being generated, modulo nkeywords */ + int pos = 0; + /* The column representing the word currently being processed */ + AES_state column; + + for (i = 0; i < nrounds + 1; i++) { + int b; + for (b = 0; b < 8; b++) { + rounds[i].slice[b] = 0; + } + } + + /* The first nkeywords round columns are just taken from the key directly. */ + for (i = 0; i < nkeywords; i++) { + int r; + for (r = 0; r < 4; r++) { + LoadByte(&rounds[i >> 2], *(key++), r, i & 3); + } + } + + GetOneColumn(&column, &rounds[(nkeywords - 1) >> 2], (nkeywords - 1) & 3); + + for (i = nkeywords; i < 4 * (nrounds + 1); i++) { + /* Transform column */ + if (pos == 0) { + SubBytes(&column, 0); + KeySetupTransform(&column, &rcon); + MultX(&rcon); + } else if (nkeywords > 6 && pos == 4) { + SubBytes(&column, 0); + } + if (++pos == nkeywords) pos = 0; + KeySetupColumnMix(&column, &rounds[i >> 2], &rounds[(i - nkeywords) >> 2], i & 3, (i - nkeywords) & 3); + } +} + +static void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cipher16, const unsigned char* plain16) { + AES_state s = {{0}}; + int round; + + LoadBytes(&s, plain16); + AddRoundKey(&s, rounds++); + + for (round = 1; round < nrounds; round++) { + SubBytes(&s, 0); + ShiftRows(&s); + MixColumns(&s, 0); + AddRoundKey(&s, rounds++); + } + + SubBytes(&s, 0); + ShiftRows(&s); + AddRoundKey(&s, rounds); + + SaveBytes(cipher16, &s); +} + +static void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16) { + /* Most AES decryption implementations use the alternate scheme + * (the Equivalent Inverse Cipher), which allows for more code reuse between + * the encryption and decryption code, but requires separate setup for both. + */ + AES_state s = {{0}}; + int round; + + rounds += nrounds; + + LoadBytes(&s, cipher16); + AddRoundKey(&s, rounds--); + + for (round = 1; round < nrounds; round++) { + InvShiftRows(&s); + SubBytes(&s, 1); + AddRoundKey(&s, rounds--); + MixColumns(&s, 1); + } + + InvShiftRows(&s); + SubBytes(&s, 1); + AddRoundKey(&s, rounds); + + SaveBytes(plain16, &s); +} + +void AES128_init(AES128_ctx* ctx, const unsigned char* key16) { + AES_setup(ctx->rk, key16, 4, 10); +} + +void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 10, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 10, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES192_init(AES192_ctx* ctx, const unsigned char* key24) { + AES_setup(ctx->rk, key24, 6, 12); +} + +void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 12, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } + +} + +void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 12, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES256_init(AES256_ctx* ctx, const unsigned char* key32) { + AES_setup(ctx->rk, key32, 8, 14); +} + +void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 14, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 14, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} diff --git a/src/crypto/ctaes/ctaes.h b/src/crypto/ctaes/ctaes.h new file mode 100644 index 000000000..2f0af0421 --- /dev/null +++ b/src/crypto/ctaes/ctaes.h @@ -0,0 +1,41 @@ + /********************************************************************* + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _CTAES_H_ +#define _CTAES_H_ 1 + +#include +#include + +typedef struct { + uint16_t slice[8]; +} AES_state; + +typedef struct { + AES_state rk[11]; +} AES128_ctx; + +typedef struct { + AES_state rk[13]; +} AES192_ctx; + +typedef struct { + AES_state rk[15]; +} AES256_ctx; + +void AES128_init(AES128_ctx* ctx, const unsigned char* key16); +void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +void AES192_init(AES192_ctx* ctx, const unsigned char* key24); +void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +void AES256_init(AES256_ctx* ctx, const unsigned char* key32); +void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +#endif diff --git a/src/crypto/ctaes/test.c b/src/crypto/ctaes/test.c new file mode 100644 index 000000000..21439a16f --- /dev/null +++ b/src/crypto/ctaes/test.c @@ -0,0 +1,110 @@ + /********************************************************************* + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "ctaes.h" + +#include +#include +#include + +typedef struct { + int keysize; + const char* key; + const char* plain; + const char* cipher; +} ctaes_test; + +static const ctaes_test ctaes_tests[] = { + /* AES test vectors from FIPS 197. */ + {128, "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"}, + {192, "000102030405060708090a0b0c0d0e0f1011121314151617", "00112233445566778899aabbccddeeff", "dda97ca4864cdfe06eaf70a0ec0d7191"}, + {256, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089"}, + + /* AES-ECB test vectors from NIST sp800-38a. */ + {128, "2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97"}, + {128, "2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"}, + {128, "2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688"}, + {128, "2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4"}, + {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "6bc1bee22e409f96e93d7e117393172a", "bd334f1d6e45f25ff712a214571fa5cc"}, + {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "ae2d8a571e03ac9c9eb76fac45af8e51", "974104846d0ad3ad7734ecb3ecee4eef"}, + {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "30c81c46a35ce411e5fbc1191a0a52ef", "ef7afd2270e2e60adce0ba2face6444e"}, + {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f69f2445df4f9b17ad2b417be66c3710", "9a4b41ba738d6c72fb16691603c18e0e"}, + {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8"}, + {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870"}, + {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d"}, + {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7"} +}; + +static void from_hex(unsigned char* data, int len, const char* hex) { + int p; + for (p = 0; p < len; p++) { + int v = 0; + int n; + for (n = 0; n < 2; n++) { + assert((*hex >= '0' && *hex <= '9') || (*hex >= 'a' && *hex <= 'f')); + if (*hex >= '0' && *hex <= '9') { + v |= (*hex - '0') << (4 * (1 - n)); + } else { + v |= (*hex - 'a' + 10) << (4 * (1 - n)); + } + hex++; + } + *(data++) = v; + } + assert(*hex == 0); +} + +int main(void) { + int i; + int fail = 0; + for (i = 0; i < sizeof(ctaes_tests) / sizeof(ctaes_tests[0]); i++) { + unsigned char key[32], plain[16], cipher[16], ciphered[16], deciphered[16]; + const ctaes_test* test = &ctaes_tests[i]; + assert(test->keysize == 128 || test->keysize == 192 || test->keysize == 256); + from_hex(plain, 16, test->plain); + from_hex(cipher, 16, test->cipher); + switch (test->keysize) { + case 128: { + AES128_ctx ctx; + from_hex(key, 16, test->key); + AES128_init(&ctx, key); + AES128_encrypt(&ctx, 1, ciphered, plain); + AES128_decrypt(&ctx, 1, deciphered, cipher); + break; + } + case 192: { + AES192_ctx ctx; + from_hex(key, 24, test->key); + AES192_init(&ctx, key); + AES192_encrypt(&ctx, 1, ciphered, plain); + AES192_decrypt(&ctx, 1, deciphered, cipher); + break; + } + case 256: { + AES256_ctx ctx; + from_hex(key, 32, test->key); + AES256_init(&ctx, key); + AES256_encrypt(&ctx, 1, ciphered, plain); + AES256_decrypt(&ctx, 1, deciphered, cipher); + break; + } + } + if (memcmp(cipher, ciphered, 16)) { + fprintf(stderr, "E(key=\"%s\", plain=\"%s\") != \"%s\"\n", test->key, test->plain, test->cipher); + fail++; + } + if (memcmp(plain, deciphered, 16)) { + fprintf(stderr, "D(key=\"%s\", cipher=\"%s\") != \"%s\"\n", test->key, test->cipher, test->plain); + fail++; + } + } + if (fail == 0) { + fprintf(stderr, "All tests successful\n"); + } else { + fprintf(stderr, "%i tests failed\n", fail); + } + return (fail != 0); +} diff --git a/src/hushd b/src/hushd index b5b504ea4..ca3f28319 100755 --- a/src/hushd +++ b/src/hushd @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2019 Hush developers +# Copyright (c) 2019-2020 Hush developers # set working directory to the location of this script # readlink -f does not always exist @@ -8,31 +8,41 @@ cd $DIR DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )" cd $DIR +# Chain parameters NAME=HUSH3 + # this corresponds to FR address RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn SCRIPT=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac -# Chain parameters +# First Pure Sapling Zcash Protocol chain! +SAPLING=1 + +# We use 3 "eras" of different supply curves ERAS=3 -BLOCKTIME=150 -# 6250000 - (sprout pool at block 500,000) + +# These values are historical and over-ridden by internals! +# Do not change these values, change internals. +BLOCKTIME=150 # Hush goes to 75s blocktime at Block 340K +REWARD=0,1125000000,562500000 +HALVING=129,340000,840000 +PERC=11111111 +END=128,340000,5422111 + +# 6250000 - (Sprout pool at block 500,000) SUPPLY=6178674 FOUNDERS=1 -REWARD=0,1125000000,562500000 -PERC=11111111 -HALVING=129,340000,840000 -# NOTE: keep in sync with komodo_bitcoind.h -END=128,340000,5422111 CLIENTNAME=GoldenSandtrout NODE1=188.165.212.101 # EU NODE2=64.120.113.130 # AR NODE3=209.58.144.205 # NA NODE4=94.130.35.94 # EU CCLIB=hush3 -# First Pure Sapling Zcash Protocol chain! -SAPLING=1 # CryptoConditions/Custom Consensus params +# CCs will effectively be turned off at Block 340K +# since transparent outputs will not be allowed, except +# for mining and dpow. CCs can be used on Hush Smart +# Chains that do not define ac_private=1 FAUCET=228 HEIR=234 CHANNEL=235 @@ -53,7 +63,6 @@ else fi fi - $KMD -ac_name=$NAME \ -ac_sapling=$SAPLING \ -ac_reward=$REWARD \ diff --git a/src/hushd-testnet b/src/hushd-testnet index c9da8c1ee..67d724fce 100755 --- a/src/hushd-testnet +++ b/src/hushd-testnet @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2019 Hush developers +# Copyright (c) 2019-2020 Hush developers # set working directory to the location of this script DIR="$( cd "$( dirname "$( readlink -f "${BASH_SOURCE[0]}" )" )" && pwd )" diff --git a/src/init.cpp b/src/init.cpp index d52888503..9f92999c4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -392,6 +392,7 @@ 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("-txsend=", _("Execute command to send a transaction instead of broadcasting (%s in cmd is replaced by transaction hex)")); 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)); @@ -454,7 +455,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), CURRENCY_UNIT, FormatMoney(maxTxFee))); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); - strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat")); + strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file absolute path or a path relative to the data directory") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true)); strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); strUsage += HelpMessageOpt("-whitelistaddress=", _("Enable the wallet filter for notary nodes and add one Raddress to the whitelist of the wallet filter. If -whitelistaddress= is used, then the wallet filter is automatically activated. Several Raddresses can be defined using several -whitelistaddress= (similar to -addnode). The wallet filter will filter the utxo to only ones coming from my own Raddress (derived from pubkey) and each Raddress defined using -whitelistaddress= this option is mostly for Notary Nodes).")); @@ -1118,6 +1119,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif } + if (mapArgs.count("-txsend")) { + if (GetBoolArg("-walletbroadcast", true)) { + if (SoftSetBoolArg("-walletbroadcast", false)) { + LogPrintf("%s: parameter interaction: -txsend= -> setting -walletbroadcast=0\n", __func__); + } else { + return InitError(_("Wallet transaction broadcasting is incompatible with -txsend (for privacy).")); + } + } + } + // ********************************************************* Step 3: parameter-to-internal-flags fZdebug=GetBoolArg("-zdebug", false); diff --git a/src/init.h b/src/init.h index c68d59419..0d8145a41 100644 --- a/src/init.h +++ b/src/init.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,8 +24,6 @@ #include -//#include "zcash/JoinSplit.hpp" - class CScheduler; class CWallet; @@ -34,7 +33,6 @@ class thread_group; } // namespace boost extern CWallet* pwalletMain; -//extern ZCJoinSplit* pzcashParams; void StartShutdown(); bool ShutdownRequested(); diff --git a/src/komodo.h b/src/komodo.h index 9816eb20b..1cfbd283b 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 930d7ddf8..e8eadbd09 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -15,12 +15,11 @@ * * ******************************************************************************/ -// komodo functions that interact with bitcoind C++ +// Hush + Komodo functions that interact with bitcoind C++ #include #include #include "consensus/params.h" -//#include "primitives/nonce.h" #include "komodo_defs.h" #include "script/standard.h" #include "cc/CCinclude.h" @@ -1234,69 +1233,116 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); +// This function defines the Hush Founders Reward (AKA Dev Tax) +// 10% of all block rewards go towards Hush core team +// If you do not like this, you are encouraged to fork the chain +// or start your own Hush Smart Chain: https://github.com/myhush/hush-smart-chains +// HUSH supply curve cannot be exactly represented via KMD AC CLI args, so we do it ourselves. +// You specify the BR, and the FR % gets added so 10% of 12.5 is 1.25 +// but to tell the AC params, I need to say "11% of 11.25" is 1.25 +// 11% ie. 1/9th cannot be exactly represented and so the FR has tiny amounts of error unless done manually +// Do not change this code unless you really know what you are doing. +// Here Be Dragons! -- Duke Leto +uint64_t hush_commission(int height) +{ + // BR_END is the 31st halving + int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), + INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129, BR_END = 50740000; + int32_t commisions[] = {starting_commission, 31250000, 15625000, 78125000, 39062500, 19531250, 9765625, // these are exact + 4882812, 2441406, 1220703, 610351 // these have deviation from ideal BR + // Just like BTC, BRs in the far future will be slightly less than + // they should be because exact values are not integers, causing + // slightly less coins to be actually mined + }; + uint64_t commission = 0; + + //TODO: Likely a bug hiding here or at the next halving :) + //if( height >= HALVING1) { + if( height > HALVING1) { + // Block time going from 150s to 75s (half) means the interval between halvings + // must be twice as often, i.e. 840000*2=1680000 + // 840000 is 4 years worth of 150s blocks + // With 150s blocks, we have 210,000 blocks per year + // With 75s blocks, we have 420,000 blocks per year + INTERVAL = GetArg("-ac_halving2",1680000); // 4 years worth of 75s blocks + fprintf(stderr,"%s: height=%d increasing interval to %d\n", __func__, height, INTERVAL); + } + + // Transition period of 128 blocks has BR=FR=0 + if (height < TRANSITION) { + commission = 0; + } else if (height < HALVING1) { // before 1st Halving @ Block 340000 (Nov 2020) + commission = commisions[0]; + } else if (height < HALVING1+1*INTERVAL) { // before 2nd Halving @ Block 2020000 + commission = commisions[1]; + } else if (height < HALVING1+2*INTERVAL) { // before 3rd Halving @ Block 3700000 + commission = commisions[2]; + } else if (height < HALVING1+3*INTERVAL) { // before 4th Halving @ Block 5380000 + commission = commisions[3]; + } else if (height < HALVING1+4*INTERVAL) { // before 5th Halving @ Block 7060000 + commission = commisions[4]; + } else if (height < HALVING1+5*INTERVAL) { // before 6th Halving @ Block 8740000 + commission = commisions[5]; + } else if (height < HALVING1+6*INTERVAL) { // before 7th Halving @ Block 10420000 + commission = commisions[6]; + } else if (height < HALVING1+7*INTERVAL) { // before 8th Halving @ Block 12100000 + // TODO: Still true??? Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting + commission = commisions[7]; + } else if (height < HALVING1+8*INTERVAL) { // before 9th Halving @ Block 13780000 + // BR should be zero before this halving happens + commission = commisions[8]; + } + // Explicitly set the last block reward + // BR_END is the block with first zero block reward, which overrides + // the -ac_end param on HUSH3 + if(height >= BR_END) { + fprintf(stderr,"%s: HUSH block reward has gone to zero at height %d!!! It was a good run folks\n", __func__, height); + commission = 0; + } + if(fDebug) + fprintf(stderr,"%s: commission=%lu,interval=%d at height %d\n", __func__, commission, INTERVAL, height); + return commission; +} + uint64_t komodo_commission(const CBlock *pblock,int32_t height) { - static bool didinit = false,ishush3 = false; - // LABS fungible chains, cannot have any block reward! - if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 ) - return(0); + //fprintf(stderr,"%s at height=%d\n",__func__,height); + static bool didinit = false, ishush3 = false; if (!didinit) { ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; didinit = true; + fprintf(stderr,"%s: didinit ishush3=%d\n", __func__, ishush3); } int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0; if ( ASSETCHAINS_FOUNDERS != 0 ) { nSubsidy = GetBlockSubsidy(height,Params().GetConsensus()); - //fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); + if(fDebug) + fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); if (ishush3) { - int32_t starting_commission = 125000000, HALVING1 = 340000, INTERVAL = 840000, TRANSITION = 129, BR_END = 5422111; - // HUSH supply curve cannot be exactly represented via KMD AC CLI args, so we do it ourselves. - // You specify the BR, and the FR % gets added so 10% of 12.5 is 1.25 - // but to tell the AC params, I need to say "11% of 11.25" is 1.25 - // 11% ie. 1/9th cannot be exactly represented and so the FR has tiny amounts of error unless done manually - // Transition period of 128 blocks has BR=FR=0 - if (height < TRANSITION) { - commission = 0; - } else if (height < HALVING1) { - commission = starting_commission; - } else if (height < HALVING1+1*INTERVAL) { - commission = starting_commission / 2; - } else if (height < HALVING1+2*INTERVAL) { - commission = starting_commission / 4; - } else if (height < HALVING1+3*INTERVAL) { - commission = starting_commission / 8; - } else if (height < HALVING1+4*INTERVAL) { - commission = starting_commission / 16; - } else if (height < HALVING1+5*INTERVAL) { - commission = starting_commission / 32; - } else if (height < HALVING1+6*INTERVAL) { // Block 5380000 - // Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting - commission = starting_commission / 64; - } else if (height < HALVING1+7*INTERVAL) { - // Block reward will be zero before this is ever reached - commission = starting_commission / 128; // Block 6220000 - } + commission = hush_commission(height); } if ( ASSETCHAINS_FOUNDERS > 1 ) { if ( (height % ASSETCHAINS_FOUNDERS) == 0 ) { - if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) + if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) { commission = commission * ASSETCHAINS_FOUNDERS; - else + } else { commission = ASSETCHAINS_FOUNDERS_REWARD; + } + if(fDebug) + fprintf(stderr,"%s: set commission=%lu at height %d with\n",__func__,commission, height); + } else { + commission = 0; } - else commission = 0; } - } - else if ( pblock != 0 ) - { + } else if ( pblock != 0 ) { txn_count = pblock->vtx.size(); for (i=0; i %.8f\n",(double)commission/COIN); + if(fDebug) + fprintf(stderr,"%s: commission=%.8f at height=%d\n",__func__, (double)commission/COIN, height); return(commission); } @@ -1968,20 +2015,22 @@ void GetKomodoEarlytxidScriptPub() int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { + if(fDebug) + fprintf(stderr,"%s at height=%d\n",__func__,height); int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0; static bool didinit = false; if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 ) { checktoshis = komodo_commission(pblock,height); if ( checktoshis >= 10000 && pblock->vtx[0].vout.size() < 2 ) { - //fprintf(stderr,"komodo_checkcommission vsize.%d height.%d commission %.8f\n",(int32_t)pblock->vtx[0].vout.size(),height,(double)checktoshis/COIN); + fprintf(stderr,"ERROR: komodo_checkcommission vsize.%d height.%d commission %.8f has checktoshis <10000 or not enough vouts\n",(int32_t)pblock->vtx[0].vout.size(),height,(double)checktoshis/COIN); return(-1); } else if ( checktoshis != 0 ) { script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0]; scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size(); - if ( 0 ) + if ( fDebug ) { int32_t i; for (i=0; ivtx[0].vout[1].nValue != checktoshis ) { - fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue)); + fprintf(stderr,"ERROR: ht.%d checktoshis %.8f vs actual vout[1] %.8f !!!\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue)); return(-1); } } } + if(fDebug) + fprintf(stderr,"%s checktoshis=%li at height=%d\n",__func__,checktoshis, height); return(checktoshis); } diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 0a1634348..e1449c170 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1534,24 +1534,48 @@ char *argv0names[] = (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH" }; + +// Large total supplies lead to numerical errors, beware! uint64_t komodo_max_money() { return komodo_current_supply(10000000); } + +// This implements the Hush Emission Curve +uint64_t hush_block_subsidy(int nHeight) +{ + uint64_t subsidy=0; + //TODO: Cover all halvings until BR=0 + //if (nHeight >= 3700000) { + // subsidy = ASSETCHAINS_REWARD[4]; + //} else + if (nHeight >= 2020000) { + subsidy = 140625000; + } else if (nHeight >= GetArg("-z2zheight",340000)) { + subsidy = 281250000; + } else if (nHeight >= 128) { + subsidy = 1125000000; + } + return subsidy; +} + +// wrapper for more general supply curves of Hush Smart Chains uint64_t komodo_ac_block_subsidy(int nHeight) { - // we have to find our era, start from beginning reward, and determine current subsidy + //fprintf(stderr,"%s: ht.%d\n", __func__, nHeight); + // Find current era, start from beginning reward, and determine current subsidy int64_t numerator, denominator, subsidy = 0; int64_t subsidyDifference; - int32_t numhalvings, curEra = 0, sign = 1; + int32_t numhalvings = 0, curEra = 0, sign = 1; static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era; + bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; // check for backwards compat, older chains with no explicit rewards had 0.0001 block reward - if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) + if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) { + fprintf(stderr,"%s: defaulting to 0.0001 subsidy\n",__func__); subsidy = 10000; - else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 ) - { + } else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 ) { // if we have an end block in the first era, find our current era if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 ) { @@ -1561,26 +1585,32 @@ uint64_t komodo_ac_block_subsidy(int nHeight) break; } } + if ( curEra <= ASSETCHAINS_LASTERA ) { int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; subsidy = (int64_t)ASSETCHAINS_REWARD[curEra]; + if(fDebug) + fprintf(stderr,"%s: nStart.%ld subsidy.%ld curEra.%d\n",__func__,nStart,subsidy,curEra); + if ( subsidy || (curEra != ASSETCHAINS_LASTERA && ASSETCHAINS_REWARD[curEra + 1] != 0) ) { if ( ASSETCHAINS_HALVING[curEra] != 0 ) { - if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) - { - if ( ASSETCHAINS_DECAY[curEra] == 0 ) + if (ishush3) { + subsidy = hush_block_subsidy(nHeight); + if(fDebug) + fprintf(stderr,"%s: HUSH3 subsidy=%ld at height=%d\n",__func__,subsidy,nHeight); + } else if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) { + // The code below is not compatible with HUSH3 mainnet + if ( ASSETCHAINS_DECAY[curEra] == 0 ) { subsidy >>= numhalvings; - else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 ) - { + fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart); + } else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 ) { if ( curEra == ASSETCHAINS_LASTERA ) { subsidyDifference = subsidy; - } - else - { + } 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 = subsidy - ASSETCHAINS_REWARD[curEra + 1]; if (subsidyDifference < 0) @@ -1592,13 +1622,10 @@ uint64_t komodo_ac_block_subsidy(int nHeight) denominator = ASSETCHAINS_ENDSUBSIDY[curEra] - nStart; numerator = denominator - ((ASSETCHAINS_ENDSUBSIDY[curEra] - nHeight) + ((nHeight - nStart) % ASSETCHAINS_HALVING[curEra])); subsidy = subsidy - sign * ((subsidyDifference * numerator) / denominator); - } - else - { - if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings ) + } else { + if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings ) { subsidy = cached_subsidy; - else - { + } else { for (int i=0; i < numhalvings && subsidy != 0; i++) subsidy = (subsidy * ASSETCHAINS_DECAY[curEra]) / 100000000; cached_subsidy = subsidy; @@ -1609,28 +1636,28 @@ uint64_t komodo_ac_block_subsidy(int nHeight) } } } + } else { + fprintf(stderr,"%s: curEra.%d > lastEra.%lu\n", __func__, curEra, ASSETCHAINS_LASTERA); } } uint32_t magicExtra = ASSETCHAINS_STAKED ? ASSETCHAINS_MAGIC : (ASSETCHAINS_MAGIC & 0xffffff); if ( ASSETCHAINS_SUPPLY > 10000000000 ) // over 10 billion? { + fprintf(stderr,"%s: Detected supply over 10 billion, danger zone!\n",__func__); if ( nHeight <= ASSETCHAINS_SUPPLY/1000000000 ) { subsidy += (uint64_t)1000000000 * COIN; if ( nHeight == 1 ) subsidy += (ASSETCHAINS_SUPPLY % 1000000000)*COIN + magicExtra; } - } - else if ( nHeight == 1 ) - { + } else if ( nHeight == 1 ) { if ( ASSETCHAINS_LASTERA == 0 ) subsidy = ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; else subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; } - else if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 ) - return(0); - // LABS fungible chains, cannot have any block reward! + if(fDebug) + fprintf(stderr,"%s: ht.%d curEra.%d lastEra.%lu subsidy.%ld magicExtra.%u\n",__func__,nHeight,curEra,ASSETCHAINS_LASTERA,subsidy,magicExtra); return(subsidy); } @@ -1798,6 +1825,8 @@ void komodo_args(char *argv0) printf("ASSETCHAINS_LASTERA, if specified, must be between 1 and %u. ASSETCHAINS_LASTERA set to %lu\n", ASSETCHAINS_MAX_ERAS, ASSETCHAINS_LASTERA); } ASSETCHAINS_LASTERA -= 1; + if(fDebug) + fprintf(stderr,"%s: lastEra=%lu maxEras=%d\n", __func__, ASSETCHAINS_LASTERA, ASSETCHAINS_MAX_ERAS); ASSETCHAINS_TIMELOCKGTE = (uint64_t)GetArg("-ac_timelockgte", _ASSETCHAINS_TIMELOCKOFF); ASSETCHAINS_TIMEUNLOCKFROM = GetArg("-ac_timeunlockfrom", 0); @@ -1805,13 +1834,33 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_TIMEUNLOCKFROM > ASSETCHAINS_TIMEUNLOCKTO ) { printf("ASSETCHAINS_TIMELOCKGTE - must specify valid ac_timeunlockfrom and ac_timeunlockto\n"); - ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF; + ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF; ASSETCHAINS_TIMEUNLOCKFROM = ASSETCHAINS_TIMEUNLOCKTO = 0; } Split(GetArg("-ac_end",""), sizeof(ASSETCHAINS_ENDSUBSIDY)/sizeof(*ASSETCHAINS_ENDSUBSIDY), ASSETCHAINS_ENDSUBSIDY, 0); - Split(GetArg("-ac_reward",""), sizeof(ASSETCHAINS_REWARD)/sizeof(*ASSETCHAINS_REWARD), ASSETCHAINS_REWARD, 0); Split(GetArg("-ac_halving",""), sizeof(ASSETCHAINS_HALVING)/sizeof(*ASSETCHAINS_HALVING), ASSETCHAINS_HALVING, 0); + Split(GetArg("-ac_reward",""), sizeof(ASSETCHAINS_REWARD)/sizeof(*ASSETCHAINS_REWARD), ASSETCHAINS_REWARD, 0); + + bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; + + if(ishush3) { + fprintf(stderr,"%s: Setting custom HUSH3 reward,halving,subsidy chain values...\n",__func__); + // Over-ride HUSH3 values from CLI params. Changing our blocktime to 75s changes things + ASSETCHAINS_REWARD[0] = 0; + ASSETCHAINS_REWARD[1] = 1125000000; + ASSETCHAINS_REWARD[2] = 281250000; // 2.8125 HUSH goes to miners per block after 1st halving at Block 340K + ASSETCHAINS_REWARD[3] = 140625000; // 1.40625 HUSH after 2nd halving at Block 2020000 + ASSETCHAINS_HALVING[0] = 129; + ASSETCHAINS_HALVING[1] = GetArg("-z2zheight",340000); + ASSETCHAINS_HALVING[2] = 2020000; // 2020000 = 340000 + 1680000 (1st halving block plus new halving interval) + ASSETCHAINS_HALVING[3] = 3700000; // ASSETCHAINS_HALVING[2] + 1680000; + ASSETCHAINS_ENDSUBSIDY[0] = 129; + ASSETCHAINS_ENDSUBSIDY[1] = GetArg("-z2zheight",340000); + ASSETCHAINS_ENDSUBSIDY[2] = 2*5422111; // TODO: Fix this, twice the previous end of rewards is an estimate + // TODO: fill in all possible values for each halving/reward interval + // based on simple halving schedule + } Split(GetArg("-ac_decay",""), sizeof(ASSETCHAINS_DECAY)/sizeof(*ASSETCHAINS_DECAY), ASSETCHAINS_DECAY, 0); Split(GetArg("-ac_notarypay",""), sizeof(ASSETCHAINS_NOTARY_PAY)/sizeof(*ASSETCHAINS_NOTARY_PAY), ASSETCHAINS_NOTARY_PAY, 0); diff --git a/src/main.cpp b/src/main.cpp index d58edff19..6bed1c0e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1750,7 +1750,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // and edge cases. This empty mempool assures there will be no transactions involving taddrs // stuck in the mempool, when the z2z rule takes effect. // Thanks to jl777 for helping design this - fprintf(stderr,"%s: rejecting all tx's during z2z transition window at height=%d\n", __func__,nHeight); + fprintf(stderr,"%s: rejecting all tx's during z2z transition window. Please retry after Block %d !!!\n", __func__,nHeight); return false; } } @@ -2402,49 +2402,9 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW) return true; } -//uint64_t komodo_moneysupply(int32_t height); - CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { - int32_t numhalvings,i; uint64_t numerator; CAmount nSubsidy = 3 * COIN; - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - { - if ( nHeight == 1 ) - return(100000000 * COIN); // ICO allocation - else if ( nHeight < KOMODO_ENDOFERA ) - return(3 * COIN); - else if ( nHeight < 2*KOMODO_ENDOFERA ) - return(2 * COIN); - else return(COIN); - } - 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;*/ - // 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; + return komodo_ac_block_subsidy(nHeight); } bool IsInitialBlockDownload() @@ -4829,9 +4789,10 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl nShieldedOutputsInBlock += nShieldedOutputs; nShieldedSpendsInBlock += nShieldedSpends; if (fZdebug) { - fprintf(stderr,"%s: tx=%s has zspends=%d zouts=%d\n", __FUNCTION__, tx.GetHash().ToString().c_str(), nShieldedSpendsInBlock, nShieldedOutputsInBlock ); + fprintf(stderr,"%s: tx=%s has zspends=%d zouts=%d\n", __FUNCTION__, tx.GetHash().ToString().c_str(), nShieldedSpends, nShieldedOutputs ); } } + fprintf(stderr,"%s: block %s has total zspends=%d zouts=%d\n", __FUNCTION__, block.GetHash().ToString().c_str(), nShieldedSpendsInBlock, nShieldedOutputsInBlock ); pindexNew->nSproutValue = sproutValue; pindexNew->nChainSproutValue = boost::none; diff --git a/src/miner.cpp b/src/miner.cpp index 4ab19638b..edd3a04f4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -610,7 +610,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 int32_t stakeHeight = chainActive.Height() + 1; - //LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x stake.%i\n", nBlockSize,blocktime,pblock->nBits,isStake); + LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x stake.%i\n", nBlockSize,blocktime,pblock->nBits,isStake); // Create coinbase tx CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, nHeight); @@ -621,7 +621,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nValue = GetBlockSubsidy(nHeight,consensusParams) + nFees; - //fprintf(stderr,"mine ht.%d with %.8f\n",nHeight,(double)txNew.vout[0].nValue/COIN); + fprintf(stderr,"mine ht.%d with %.8f\n",nHeight,(double)txNew.vout[0].nValue/COIN); txNew.nExpiryHeight = 0; if ( ASSETCHAINS_ADAPTIVEPOW <= 0 ) txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetTime()); diff --git a/src/miner.h b/src/miner.h index a3bedd292..c42c2ad54 100644 --- a/src/miner.h +++ b/src/miner.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/notaries_staked.cpp b/src/notaries_staked.cpp index db1696ed5..6bc458078 100644 --- a/src/notaries_staked.cpp +++ b/src/notaries_staked.cpp @@ -9,125 +9,30 @@ extern pthread_mutex_t staked_mutex; int8_t is_STAKED(const char *chain_name) { - static int8_t STAKED,doneinit; - if ( chain_name[0] == 0 ) - return(0); - if (doneinit == 1 && ASSETCHAINS_SYMBOL[0] != 0) - return(STAKED); - else STAKED = 0; - if ( (strcmp(chain_name, "LABS") == 0) ) - STAKED = 1; // These chains are allowed coin emissions. - else if ( (strncmp(chain_name, "LABS", 4) == 0) ) - STAKED = 2; // These chains have no coin emission, block subsidy is always 0, and comission is 0. Notary pay is allowed. - else if ( (strcmp(chain_name, "CFEK") == 0) || (strncmp(chain_name, "CFEK", 4) == 0) ) - STAKED = 3; // These chains have no speical rules at all. - else if ( (strcmp(chain_name, "TEST") == 0) || (strncmp(chain_name, "TEST", 4) == 0) ) - STAKED = 4; // These chains are for testing consensus to create a chain etc. Not meant to be actually used for anything important. - else if ( (strcmp(chain_name, "THIS_CHAIN_IS_BANNED") == 0) ) - STAKED = 255; // Any chain added to this group is banned, no notarisations are valid, as a consensus rule. Can be used to remove a chain from cluster if needed. - doneinit = 1; + static int8_t STAKED=0; return(STAKED); }; int32_t STAKED_era(int timestamp) { - int8_t era = 0; - if (timestamp <= STAKED_NOTARIES_TIMESTAMP[0]) - return(1); - for (int32_t i = 1; i < NUM_STAKED_ERAS; i++) - { - if (timestamp <= STAKED_NOTARIES_TIMESTAMP[i] && timestamp >= (STAKED_NOTARIES_TIMESTAMP[i-1] + STAKED_ERA_GAP)) - return(i+1); - } - // if we are in a gap, return era 0, this allows to invalidate notarizations when in GAP. return(0); }; int8_t StakedNotaryID(std::string ¬aryname, char *Raddress) { - if ( STAKED_ERA != 0 ) - { - for (int8_t i = 0; i < num_notaries_STAKED[STAKED_ERA-1]; i++) { - if ( strcmp(Raddress,NOTARYADDRS[i]) == 0 ) { - notaryname.assign(notaries_STAKED[STAKED_ERA-1][i][0]); - return(i); - } - } - } return(-1); } int8_t numStakedNotaries(uint8_t pubkeys[64][33],int8_t era) { int i; int8_t retval = 0; - static uint8_t staked_pubkeys[NUM_STAKED_ERAS][64][33],didinit[NUM_STAKED_ERAS]; - static char ChainName[65]; - - if ( ChainName[0] == 0 ) - { - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - strcpy(ChainName,"KMD"); - else - strcpy(ChainName,ASSETCHAINS_SYMBOL); - } - - if ( era == 0 ) - { - // era is zero so we need to null out the pubkeys. - memset(pubkeys,0,64 * 33); - printf("%s is a STAKED chain and is in an ERA GAP.\n",ChainName); - return(64); - } - else - { - if ( didinit[era-1] == 0 ) - { - for (i=0; i +#include + #include +#include #include @@ -82,65 +85,6 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.push_back(Pair("addresses", a)); } -UniValue TxJoinSplitToJSON(const CTransaction& tx) { - bool useGroth = tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION; - UniValue vjoinsplit(UniValue::VARR); - for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) { - const JSDescription& jsdescription = tx.vjoinsplit[i]; - UniValue joinsplit(UniValue::VOBJ); - - joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); - joinsplit.push_back(Pair("vpub_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())); - - { - UniValue nullifiers(UniValue::VARR); - BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) { - nullifiers.push_back(nf.GetHex()); - } - joinsplit.push_back(Pair("nullifiers", nullifiers)); - } - - { - UniValue commitments(UniValue::VARR); - BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) { - commitments.push_back(commitment.GetHex()); - } - joinsplit.push_back(Pair("commitments", commitments)); - } - - joinsplit.push_back(Pair("onetimePubKey", jsdescription.ephemeralKey.GetHex())); - joinsplit.push_back(Pair("randomSeed", jsdescription.randomSeed.GetHex())); - - { - UniValue macs(UniValue::VARR); - BOOST_FOREACH(const uint256 mac, jsdescription.macs) { - macs.push_back(mac.GetHex()); - } - joinsplit.push_back(Pair("macs", macs)); - } - - CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); - auto ps = SproutProofSerializer(ssProof, useGroth); - boost::apply_visitor(ps, jsdescription.proof); - joinsplit.push_back(Pair("proof", HexStr(ssProof.begin(), ssProof.end()))); - - { - UniValue ciphertexts(UniValue::VARR); - for (const ZCNoteEncryption::Ciphertext ct : jsdescription.ciphertexts) { - ciphertexts.push_back(HexStr(ct.begin(), ct.end())); - } - joinsplit.push_back(Pair("ciphertexts", ciphertexts)); - } - - vjoinsplit.push_back(joinsplit); - } - return vjoinsplit; -} - uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); UniValue TxShieldedSpendsToJSON(const CTransaction& tx) { @@ -306,9 +250,6 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -390,9 +331,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -478,33 +416,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp, const CPubKey& my " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value\n" - " \"vpub_new\" : x.xxx, (numeric) public output value\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" " \"blockhash\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of notarized DPoW confirmations\n" " \"rawconfirmations\" : n, (numeric) The number of raw confirmations\n" @@ -933,33 +844,6 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp, const CPubKey& " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value in HUSH\n" - " \"vpub_new\" : x.xxx, (numeric) public output value in HUSH\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" "}\n" "\nExamples:\n" @@ -1373,6 +1257,19 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + std::string strCmd = GetArg("-txsend", ""); + if (!strCmd.empty()) { + if (fHaveChain) { + throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); + } + boost::replace_all(strCmd, "%s", EncodeHexTx(tx)); + boost::thread t(runCommand, strCmd); // thread runs free + // Return here so we don't add to our mempool or broadcast to peers + return hashTx.GetHex(); + } if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 56c038596..16b25ae81 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -652,6 +652,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, { "wallet", "z_listreceivedbyaddress",&z_listreceivedbyaddress,false }, + { "wallet", "z_listreceivedaddress", &z_listreceivedaddress, false }, { "wallet", "z_getbalance", &z_getbalance, false }, { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, { "wallet", "z_mergetoaddress", &z_mergetoaddress, false }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 6568977d7..15c982d81 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -480,6 +480,7 @@ extern UniValue z_listnullifiers(const UniValue& params, bool fHelp, const CPubK extern UniValue z_exportwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp extern UniValue z_importwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp extern UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp +extern UniValue z_listreceivedaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_getbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 08aba3225..2e1223b8e 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -66,9 +66,10 @@ void CScheduler::serviceQueue() // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { - // Keep waiting until timeout + while (!shouldStop() && !taskQueue.empty()) { + boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) + break; // Exit loop after timeout, it means we reached the time of the event } // If there are multiple threads, the queue can empty while we're waiting (another diff --git a/src/sendalert.cpp b/src/sendalert.cpp index 7b8ca4589..b626f5b05 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers // Copyright (c) 2016 The Zcash developers // Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44 @@ -74,9 +75,9 @@ void ThreadSendAlert() if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) return; + //TODO: wait until KOMODO_IN_SYNC MilliSleep(60*1000); // Wait a minute so we get connected - // // Alerts are relayed around the network until nRelayUntil, flood // filling to every node. // After the relay time is past, new nodes are told about alerts @@ -87,7 +88,7 @@ void ThreadSendAlert() CAlert alert; alert.nRelayUntil = GetTime() + 15 * 60; alert.nExpiration = GetTime() + 10 * 365 * 24 * 60 * 60; - alert.nID = 1005; // use https://github.com/zcash/zcash/wiki/specification#assigned-numbers to keep track of alert IDs + alert.nID = 1005; // HUSH3 has never had any alert id's alert.nCancel = 1004; // cancels previous messages up to this ID number // These versions are protocol versions @@ -103,12 +104,12 @@ void ThreadSendAlert() // 4000 or higher will put the RPC into safe mode alert.nPriority = 4000; alert.strComment = ""; - alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Hush (3.2.0 or later)."; + alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Hush (3.5.0 or later)."; alert.strRPCError = alert.strStatusBar; // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // alert.setSubVer.insert(std::string("/MagicBean:0.7.2/")); - const std::vector useragents = {}; //{"MagicBean", "BeanStalk", "AppleSeed", "EleosZcash"}; + const std::vector useragents = {}; //{"MagicBean", "BeanStalk", "AppleSeed" }; BOOST_FOREACH(const std::string& useragent, useragents) { } diff --git a/src/sietch.h b/src/sietch.h index 65908e2c9..d68716bb1 100644 --- a/src/sietch.h +++ b/src/sietch.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2019-2020 The Hush developers * + * Copyright © 2019-2020 The Hush developers * * * * See the AUTHORS and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -10,6 +10,7 @@ * or distributed except according to the terms contained in the GPLv3 * * * * Removal or modification of this copyright notice is prohibited. * + * https://myhush.org * * * ******************************************************************************/ @@ -24,6 +25,7 @@ string newSietchZaddr() { SendManyRecipient newSietchRecipient(string zaddr) { int nAmount = 0; + // TODO: Should we randomize length of data, perhaps into buckets? // Sietch zouts have random data in their memos so they are indistinguishable from // encrypted data being stored in the memo field char hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; @@ -36,223 +38,11 @@ SendManyRecipient newSietchRecipient(string zaddr) { return SendManyRecipient( zaddr, nAmount, string(str) ); } - -// The network essentially DoS's these addresses and reduces their privacy slightly -// by making them public, but in return, the rest of the shielded pool benefits -// and so it's a large benefit for a small cost. string randomSietchZaddr() { - std::vector SietchShieldedPool1 = { - "zs1qqj4aw35ku9yn72g3tha588mxk66mhl5smnn99as40887xvdg49d4yqf43hhqnj9rpsq7qaqqhx", - "zs1qywzq2cutvg6rkynjljtssz246easagumg3hlwjluz4g7qttg9kqrld7s43ewutpph56jmn2zu6", - "zs1qx7swmw28dj992f6zs0aqucds9kag88mnca5u73dddeqek4m97pg7h9qsaxxwwkgqxht6zujaxc", - "zs1q82pkqu58uemrm2749x6g2ta5shnsra9p5jgk0qqzxd3e08ke6vyeezz7lhldj32jxtsuemskk7", - "zs1qvah5w05qq4yhrsqrt73ckgntkmwdv9mntxep8clnxqfph8xggqad96a5nvwg4evfr9pc5ruvc8", - "zs1qwrkjcmnrwrqqkz3dyfjvdvdppe0ndnm8fhhpsz8stje4qcfc54jtuygz2jfwc3aag69wsjcm8h", - "zs1q5pd7h4x7dtnpa4ace7tytye5sd0j4043t4f3jdntyxvg9ex258nu6pw9tthn6t5gmjq5gv0lhc", - "zs1q6vjrpsuf468an545q7fh9cx0xlkwh75a7qjpemjh3ymuqqzxz5ts2n2dcth3yfnlv6vqpjyglr", - "zs1qmsvwtxkwlh3tkh0lqtwqv2mxy94jt778f7j74a8067nejkt4j3m2rkmypccju7cfuw7xyg0gg8", - "zs1qu3jxrw5qwuvl7zfvnsdvywr4a9cn4h00me65te29platx5agek072f5rvxgt8kdt630qs4tgtr", - "zs1qamxwddwrl5xn56alffruk69p304cqf7uf5nhqpwfc374l9ph00m78xv2kzwymyz0fhxcku7v5k", - "zs1q7gv479e6q7d8fxc35v5s27em66mmm5gz50excudf95rzjgnwdy5pnwdfytvm7gt8kt6wpkfphq", - "zs1pqvxd9a2zcsh2v8gaswh3jp2qkzz5umrucl5k4gx0rkvmq68krpx3jesavxftd8t0z56v8whllj", - "zs1ppn2mdznaa2pd9mavfnxrcjtv0c9un8pg6jaa9ww4wy6wdfs8xxwquqk5umtcjwm6vr4zrqy5x7", - "zs1pz9c9ydyrm7e876cvae9ha45ww77ru5fhys2yz33kjy8ej9230wjy8yupfxkynwqr6nfupgmf94", - "zs1p83g95avpsgr847eu3rm3xcmgurt9hc77wtndnmpypa046n529aqdc9ptz04ugsuhvum2ztzwe3", - "zs1p83jle2p8awu4peevq389y5kyrs5tqxxyrk32zy0t98d4cfepmme0myxp68nrq60xwzc5teulvg", - "zs1pg5ggzwx4yaa7g83yuhay8kzh78nahxfe7cgavn88f7rxlnuckhl2vznv0f33yuqhhs3sh62vl6", - "zs1p2nrefmqfhnwrxqfsz4ruvu8wl7742j5rv2fmwlpmpudwqpdn2yrha9rwsu5gc0fdv2j73tfk6a", - "zs1pw29hkrvszxpe2e4tjpj5h9pszjhql2p4tzcj2c5lf67m7d8jtgc22vehftxdnqze33mgtjc25k", - "zs1p0ggg024alu2l5x8df8ucu4lz8r453su56w2mmshru49uh9a0p6ufy3qfj8a9n7xeu8dxxjrk4p", - "zs1psaydszvszu4mar7ef9gk8atmwpnfjjsh8plajn6ttlgdk44jfud5zv8l3uyq73qk3eskec96ut", - "zs1pjf3kczvrwduuy4x99t03wfrgwstueyw0ypvwa44fz2tukux8kqqqs48uag4y39ed4rux8etvv0", - "zs1pnwzzh4mhehkvf4ys9x70q6meq9mgqj6mgl9ddzwvf8excswrj54lfgu4m9slmc90s37q8e63du", - "zs1pnndevupuakjcqyqzu4sfcgdmdzrhutp8ygxwsl5wvq5hgu20u55auu8p08wphvz9mu3k8ynyr5", - "zs1pmy6tvt9p3xxp5edt70mkwfqk0ljgaranzdnluh5ln36g9g3v2udquleuz5974q2mamywmrxl7j", - "zs1pau6lddk3uapms7v7rsmxvxeekqh52z795kzy9z3dv9qvzq3jwh4pr2adg5cf8fw2e3mzqmgstq", - "zs1zpy6wuvy3jlrfmj0363tx6cuume6j0mqfakk7ydw4f6zvn4s7plewk0gtm7r34pjtppvkp8rzl0", - "zs1zpvkccety206ww6c344ehughuyklc3v02q07j4p72pqewxl0n50zugtje6lclj3m292t6vs56fl", - "zs1zzucdg9kalcjnnknt98gpg42qm9aqpkc6qf5ewgr29udu55r0zt862z3zt23sd4mj9t47k7k6w4", - "zs1z9agq4vq7eswwynhmzdsy58nxq3azhn66y853yw9kvercmve8vv6d5pawpwwpwpuyedmzpcqk8q", - "zs1zvddl2e0pve5kl0hu7fcum30lyhx4pdq64jztq2vp09lqtu5gclfg4fe9fqvnm8k2d5svydg7s4", - "zs1zvsmkn6a4celtcg8ece6exnkvnr2u06ej8kjt6mrpm0983e86dr9al6gd5g73k24j0a0zkpjs3w", - "zs1zv33kglx4n5572dg2pez2k3m7tgtz08a70ndpfj6x204pphlm0pzcppetsnjlat3qflswqfmu83", - "zs1zsz5c9xua7arkvd60vsl559d4dvnjz8ejq4rlmmm9cnz942fdmjmvsgrdl7d5ddxh4y9258jk2l", - "zs1z5n6qvch0wfymumxjflezekxa2j5t978eqzh9ldxsl39h2jjrlzdv9rf00wdrvg0t6afq7mq0us", - "zs1z4ymm3gt22f3pcj9p9l2yg00e2m39kfexgaz99s9y4nsuxhlk6u0sl9lsx9awzywumxyuxv9vuw", - "zs1zkjnhz96xepc97rfyven23epymd5s558yqhp488gcxcj794z6p37h5ej5m5waqxfupmc538mej3", - "zs1zcqdekyq656yj2y86lh08u8zpetfanj5u4rhfpcphne9xw7esce8asux2rdr4yjxzds56fuda5r", - "zs1zceru3jt9m3jqzacnffetvrg8zch6le0zactl7ssfky2vwy7pcffkg3pmauqqpkv5v7nv3uzc5a", - "zs1zellp4tdmxdsd6hmg2c4qlx96m39c0cjlqupw085z87lvzcnx2r0gs7plc0wp4m4upk3zcs35e8", - "zs1zm2pcg2d3hnyxufn8cyshjn742gmffwaqdc0nt5uf9gsytdjywsqaasfdxf4sysfu0sgxjwjp0g", - "zs1za9nk7fpgnfetjulq6t8jgfyks06xg4q8rfwpgsfrkn49k34nc7xhm27dnjuzztgnwkww28ztyw", - "zs1zaaz6j6z7z748mck4v55s3fd4htl4f478kulnwr84m8vn4m0r227juddyq0ncu3cyvc765z9gm4", - "zs1zlz59lgwc8pqq33508v5ygk9e58f7fs4rpj3achhwnkcyn2dku44yfjghdf5l2v50nu2gjzgl2l", - "zs1zlgenma0yuqxmqgns2avpnauclxgfvgd6rf0jt09fmfyaflwlhsscem9ypmrvewl9l356dn3jtr", - "zs1rzu2yg2328l2wlfstu27dl024ucqsjx6g635yxmyhs0wr3lduutkc3peuhqe83uueh5n5q624rd", - "zs1rr9jpeemn9ek30x4h65rx0ddul7xet6cc8atwrjftmq9sdrvj9f5zdc9xg7amtc6dv5fxjyhu54", - "zs1rrgccr0yvfn5fdek39x09y2ylyf42xkydcwzq67wdrzyjj2mv874easa4h4tymz5gj852aqpffk", - "zs1rynh7vl05weafzwkp0p5eafuzzqph04prgg74emqq0sx6xudtrs2380v3ycxgp5lzudw6tmc2zd", - "zs1rxqz0a59zx3yduncc3azyzexwu8xl6cc0zu83hfd28mksrgahhvx8604uhf0u5mna9m4znnj4gr", - "zs1rxr2xff2vcv0y9s6ux6c6t9y7r3zvcvrqmwkvsnxj39t0qv7qwyhncnykhzcqg0ggpu423ykzxe", - "zs1r8chvye5uzlskv8jvt6j8nxnyz4lshy3u46yjhc8w9ekhjhneg402knft3t943t5nrhs6d0d5um", - "zs1rgu6mz58xrqxpyl5xw7ss2szz29cg98s8xl25hu7fy4lcxw58zr93a8rgyha52vwxx7hxj2emkw", - "zs1rveutz8ftruljrlctum42kakjqk4cm8dm2807nqm974dz0rptlxcs999ttsvwp65vc9e59vv9fe", - "zs1rwfqhlezm5ln7kq8wp8hkl08ddn74ryr8cs4cu8qc23spdx79xgfqj4lju4u2yqdrkxkwfvk3ed", - "zs1rwklllsk9jwhhf0fedvlzsqfqdkwer05zh8c8hwypl4tls2hdal54lexhca7kghhum5hycurvfe", - "zs1r0ulehrcg9xz0lfdcukjm3qlvqy74t0u8raqf4zn88vdsta8mzp8t8p9ul8jragssvs9qaqpw2e", - "zs1r3t0cve050wufwl8r2tly05vn7w79v53fe6dagjtt2ese0qm6vgjp3rrsfu4n0am840sq5thn72", - "zs1rnd8zwan2xlrnfwylm9khkeutnzg2v9vjdnyellyuzkwmed94uvd2dq8ceumxwspz037zp2ctqa", - "zs1r4tphfnf3zy34dqyjuld2kgtyg88hrxpv756pkkkmrfdeun0cqzpepac4ma9qrjrvdqxg2z5fuv", - "zs1rcpywy0v4sfej85wdaslfwsp4pe9sa87xgzv24ywhps2l4c9jlrqttv0wl9zkc5e7rsekf42wvp", - "zs1r66et0z9xw3qqhzyc2aht294y7yqyz8wx2l2t63unca4k4zh4v9t44kpmg52z9va5968y45fdkx", - "zs1rat3szdulwxwmx7y4rdphvlpjj5phadvz0fsvj7mtg9ggzwd22sn30hzsh27h7t6cvca6a8wu2n", - "zs1rau4jcth66jsg098ucclp9tfa5qe6jmtmfkcluaqnyj3uatkt9dsrgx44xtmxr3e9xuxv6sy208", - "zs1ypf2v2yu4p4mnlmw0wd3mpztpjlhl39jnn6hkvf77ell0h5u6yg2pgeusvku5y5sykyy6kk6yyh", - "zs1yzkt8catgk6slwj7azu79tvwv6tkd6agcykvvht4rxlevtsh99u036jf5503pju3h05w7x02cm8", - "zs1yrty5fmnyaartpcyjnpal0w44g4mt2ey5tyzcmgq4g6qtsfjmxae7fvy2zsw7t0zvseuwcfwt2e", - "zs1y9p5gazcx04kke96xudep0edzkqr06gdjnr5vm99a6qxzatqz5katput4q9nx95e8965sg7d3pl", - "zs1y9vpfgkxwh3xm3j9d38zkeqql2lh8w3ucgerkww2asdv89p87emdavkzurnqpkrmu7e3xv5myue", - "zs1yfa9gwmn0xe4myrg0rf8kmu36243u8773ukeev0set2yv0z9vpxm6ratee52e9zmpvvx7w2xy28", - "zs1ytpjrujfsgs69smqerxeaf8m38jwxc4ejgxxe4pzc5qu4auqrgy8tf7zxc402pxf9uku646kc0q", - "zs1ytvtdwmcn8tnka6w6wa8n3ghnkf7gp2qaudd4233y6m509ntm59rr0n8eudhre0md7m0zedpcsq", - "zs1yjmeu09mzrt8rgehv2gcfhxx6ddqz7ww87ssfapndvc94hxfrfsdkkgm8f8nr36xm8p7q462qy2", - "zs1ynqghdu0r0c20csp3ygrxdw9hk2l89j3g59q8zhht9jyxycpcc9ccvhyyn2f9j0ehp4pk5wkhqs", - "zs1y5ny4jpjm05vp5awjd6muaqqypdv0y9tr6pz0m5t82cwtrearxwf7km4aznydpcjeuzxqvk0z9m", - "zs1yh2vd5usfsyv4pscjrxg9wdy3gnnyuh8vky27ln3u9jspadmpqsjmyvxmvfyyq3nv4deudvygxa", - "zs1yclvhy57hngs7d233e4x8ywfreswslz2gvn0f8epcs0wrzuqqau3hkrvf7ru6jhh0zmsyn5jkj6", - "zs1yunkgwzf0m5suz380j7xqge6rd9e6acjc5wp22z0jhalqdpspdjey7jfjvgrckgsk9ydc9yrnq3", - "zs19p94fnry6p88ms3yh60nl4kxlxmu7uxv9aafmf5pc4nyd64vslaqgmj30nxe3l5j7cxu5kqeqpm", - "zs19x2df6qmd4c9whrgj6m4mssz22x9qj9x8lmcnexnhw32pey24xy9sws5ts2q7guunm7mx9wmllj", - "zs198a984na6qt2z3uyhdkmj7sfevt794dl3mum3782kddjy4uawr2teznpuxvnzc4dvs3c6zyqxey", - "zs192ld62azpypesveqsat6m63sqaw95ejlqfcjsal5t0fea9zjzqnurmpnl6074zdms0amw83rw0x", - "zs19vsx09xmzlj9vr3s3vu8z4237gpcgrl7qs0vapzzawgnu7gxngeaxlgwqf0ppu0f7us9cfe3cqz", - "zs19wfwd8zufu27zugan77wf2g790egdw7vkulf6f375ylq0arnv2nv94l84nl8lp3tpccv763wetn", - "zs19wcqtqqjj0mnrn90ntcmyq5x8qr2wsaslqwt0fysz4xh2mmjy0z9jjh4sj86sjrgen0axx04zt4", - "zs19jypvpjpvhv5et5wq2ny09skt72hxz9adfgk2ev7nza5jyxr6gss5qelygnxn0szmjqyke2h8a7", - "zs195kll03d43her83a65y7z0zsetynlnft4pjxdspegvun0m7cwtx0vsxfm89mv50vxr90qhvcqpz", - "zs195e2g52jpyly7t9vjpfcegt87g7lpa4rm74nxn0zvmtzjhvg7f5gjnskc5ax5skvwprcshenyqs", - "zs194e84mfxc4vn4ssce7hkvgrcm3c8j7vehcetkdf78rele2lwkx9tzcfnrwhykdqa2nmwx5qcr0j", - "zs19cxqspj63ksk6uwtynj0la72zuvh8rxfh0e0pr2y5vuuvw35sm78juzh5gxcuqa8jggv703rplf", - "zs19e04k24qrca0sx5z47dxmtx0swcx2ywxqjt5594gu95rjaeyxrpa2vyylvzxpau5spt2v529me6", - "zs19707gmdvc4hfwg4lgvxg55695gltx3jwye8l2gjekrx4zqz7yr6grq8s8hpfqwggrywx509ln5y", - "zs1xrw8nwla7yrz8l3d7y3rxlhamel2ly4kdmxlc6w4cztxhd6l8wufqv2pcsvtl3d7s6awvjatyx9", - "zs1xymrgyhle6dcvjk5f62k4xygr0vrr2wckqy7sp6wc6cttn29hra77dzhwxst7z9rxqxkz08jd7g", - "zs1x9c8tetxgauxh474hlhnlscuhgzww8vnvxfwm0p8589x73t5yl2fph8q8r8qpl8sh0wfwx0vg62", - "zs1xxcpzsfpyekhvvum3erxjpt34pw3h70ma8vxwecg85tze380f4srlg8zlgxty8yqhutt234nk9q", - "zs1xx6pd3vtj78tg0zpwtc0jjkdxlfy48vegzd6cng4m9w0gtcya8ck7pqgf4l5sxf9ml5zvzru5xg", - "zs1x8qre6x5d8e3tt2m4l9q2tujw8ajun70qelp8tfynyw390rm6vhjtmpf58dmx4hccef9xe50az0", - "zs1x88vjduckqarz2j8tp2me08ya4dgd6pw7j4j98j5jynrze3xy2jjptzye7eftjxd6dn4sj03v7m", - }; - - std::vector SietchShieldedPool2 = { - "zs1ehrs7hetemzsmfz9xwt8xetxag33j3xzj8mhdgywdnvkk4dmtvw6eqys6gm3vr679y865jz7rth", - "zs1ehyr6w0c4mwp0wlp6w5letgm3rjk32rxa9kkkur86e5x8lutr9mwzey0hsesnz0yaarmxra7w2z", - "zs1ec793pjf3anee0qq9ex5u2qygjzk9llmwfygev563l89quc3u8wxvtz9kctlmv2dtjgqwn7krcg", - "zs1eclpgnqy7qll0l5z0gy7m4ew86yjvp397yxyau9y2y43x5mqfdw2sll95l83ux6h8mppzsx3xnp", - "zs1eexedkctuzhjysl00m0j3ekknd32635yd8rejx9ykjp6zz77fyzf5388env642ja2qlg6mrwgsc", - "zs1e77uz8yaj998arp56d0fm4p827wchlf2w09hve6rgkmavhzeyhke8qsk3l7s5k6yh2jwjheqpup", - "zs1elj4qvy42jpts2cu22tcwt0kmwzafpmrjgztwf2xcqaycrlr4rpfxfpswx63e6agvhz96gps9yf", - "zs16q0fzcvf25fh70ysn38v7qkpfspakmelnljgnyrpu7rvllyew57n5cpqjqe0wmy5j57au47j6x8", - "zs16pnkw3mucdef34jjk6q28zd7ghhatdcqn598vs3g70qev234uc5uw6xxxjnzef3pt2t567qev8v", - "zs16rmnl4hd6c226u3v6eekk68y59u0x7v37n8pmytt9xw6drugjml7ryhd243nf3l2pvafw42rnxc", - "zs16ruwvwmetmnnns0rxwtx2kss23da2pccares0tehzw3v3nxd483qn49c9apdfua0hpm8xdecdt4", - "zs16ymafsjd7fp9zdl9vtyvfedecvn7q2vcs7emeglwy7hpuphve97d3j87v2evqs0xm3jrx44nwfe", - "zs1697ggm9zqp4rh0fv4r9hnh9uy6gg4hk7r2lm33tp2we4ry5azpxq6nwuzscha0g2nx03x4sstq8", - "zs168t8u6at9k6kt748dv749dxahnk8rv8yn32z8gcgvc9rkhkewscgu8r8vuzv0zecnq26w9p7x0c", - "zs16gnyx6f8vql24cepamfquhr3jjt7wgmzjcvwtct4lwy9p2studln6ut9kjzf6empwqjtxqmddqy", - "zs1622ra8snywvxufsunk97pccr7k0j32p960evl9yqjadhju22m4sk48md84q5u238gej8xnm4xm5", - "zs162stv8m0udzy4c6ff5kqva2g7pqth2rrdn7rjjgw29dcx7lj3vs4dnj8fz0gczsat3u3q5axgva", - "zs16t78376h9ledgt50k2dmwssuhyy4hn94wfgd8vzegvqy9k9kauuvpe8xz0f3va65l8ufqhgv4gv", - "zs16vxrghgv7mth6k9unzdude9cyt9vl76ms5hm9ce4py92rk69j4p9u570974nh8kqh8e2stqknj5", - "zs1654eafn589g2ujzcasa8caz8exag742tra2dd6mjkp22axh27hda6sy9exh3wkp4c6f5vztafr0", - "zs164u3ntsnn7s3zrp6c5gsqfrwr0ywhspynvunq3fhvr9crwz5eme706j5awwvuatqwh7m2qqkqm9", - "zs16cpqwm4yml5x8j5r3q5j0xljam68pf56xt40hylzn69w45venwdvd4h8drys5t380mspkvt7h8r", - "zs16c6m9aqs0q9kadm4nk6hugmqw6p0lf2h6v5d9ccwszssyecq35sm6284c3uqx2u40da4s2mr2ap", - "zs16u7rc066566j9ux73dcq0m7cq4qdmtd3gefrnhhrpjww3z00j4za7m5mcutmj6qcezkzys87mpp", - "zs1673rm5d5z9sh2k9uc2cvgwk2e44z0sekx6ezt9n4fvgnky5yxa2tc306dw7n2dg5vwfn7ppwr5s", - "zs167nvq5ahvu4s26447rem9j37qglgtle4fghsgpksumkz34g2q9x783pak5jgdhhzylmgs9wemg8", - "zs16lluayez28xevxg0rawxxcd7yx5t7qaraet256sxe8ac69lj7n7ppncsx3m2tddxlzptzyxv0qr", - "zs1mydlmczamey4ydc79n8gj5wtgs79zge4nwhcg8g640r6fvwu6wpt70970p7ptkcrzg6r6frqh0u", - "zs1my6tgqmy3kgdlqncyd5dv9s727x9hcrmj8h06e5whn4hkn5t2x46j84276yd8pw0p6ysx53u38u", - "zs1mte528eue8smvjwpe9cs8qz3wud9735rnk7vrtefu9lhyvh5pyeyenpaq5fa08jpwrl4x7sz069", - "zs1mvmu20syf3u5yzd6hpdd29xfej8237x2k0pcmf7pvra46qem5g0jralrmdcvncgf5j0y5varzr2", - "zs1mw86y6g2c8972a2ndw57648p9qcx2jppxr9g5k24df8hl3rgfzfsfe2xyesemdfmasutk88duht", - "zs1mwca7dqjq0r2mzmn4qarw8acmt4rjk26lyyar35sssqe2fky2nmv3kmf0lfxs2a9htugsadg027", - "zs1m0rpcrkfagzpex9mlw2htyrwpxe48v47pj8zg96l9wm5k8xkj3kev3xca6wumv5avkgsjtygush", - "zs1mjgyju3jnyxjhekv72y448edq3j2cvtk5s4wrej790zzpv3uc20dvewt7nhjdqryuecmykfm0je", - "zs1mjlfwyma3fv45yg50j73wcswnap2s4lsh5c9km6lcem73wky9lej7vy8wrlkr75sy6z2g0agtmw", - "zs1mkh9s9gdfxx4dkug47dqnc98g76dhm09zty779pm6gqc5aye4gvxvduqm5j56nq4lncx5ygqu90", - "zs1mm7tesf30r56l8xmnxjyxvgmnsny2zntsxahllrd930q8ycahz8npdxt7lqwu3k8ljs9sw7uzs8", - "zs1mu34v9wtyhtlr22phfxkp670wt0gj4z8czumx0m4u05elg7kjzu0dzveq5jn28xg5a2wqr6cywd", - "zs1ma3xy4fj0vm0w37a4kur3ghe72f8nstmqmmvh0u48kurtlwg50rqqlw39j6ng8lrxgam2dh0zyr", - "zs1m7yauj7694wjz92m5sxds8udp43z6kclarqwzc22wn2q6svkkk4lpzx53kwctwfn6jqcu4yww5u", - "zs1m77qqksfvuqmjmwdm22xr2u99z3uz4glenk02md4tq5z066gc7jkdayhf2txspqggv29quacpy4", - "zs1uq88d69zrnksytnquejpksdvdlp9e5y3xec3eyf0rrya8zap623zpwjs5mfzadrp7twawkpennl", - "zs1uq0zzag2cmekwn9a35vkf2q45sary5v8nt2adukhej9ydq3qpegskg5naysl3wvvxtzuyv5lu8w", - "zs1uqs3n3j8kfgurz8tj0ea5g2ny200c69rwwpq50kkup8sxntdne6h9uhx3wc2y5jjkcggvpvcl4g", - "zs1uqmnl793xh4cskxjherwlpt7xfnt6fy2sp2l3n58hpmd4msj2g3fjsks02069tqgzzvn77mpfg7", - "zs1uz73f8arfahrvgtxcjwya33ql5w8mwkmyrvxvjrjx5rla07hv3ax49hkeqg3aqynxx39z4y4vtt", - "zs1urzuwedq4qgnqjsjwjeauzyyjwxvs27mau6zmpretn37my92h3jqc0waad4r8s7zeeczq6jfas6", - "zs1urfls60sjxpnla4hhe736qu54w7047akw2p9cksx054y8e8gdyknkhwv6spwzgstf7z2wrsdapw", - "zs1u9jum0rl3959ay3qqxskkak5emv0fpceuhuhcj9rnkzfy6gpe2uv6ny29c399nrc68fx6fffg6c", - "zs1u8fdxg8lu08p6s5z9qe6jf6fkvd74a99yg3n5exlm6wm8paypygy82ue2smf0qqlhdhjzy2jxq4", - "zs1u8u44rlv4ay27248807fqwyf6lw2w76v8evn26nvwv887caqlenjgsw0nqlajzw9equn7phhs95", - "zs1u4jhx25fghqzn2az7he7lrv7xj23xd8spcl660g9kzqa3wyykm5gucuu5wwxvum6l6spq4u4e5s", - "zs1uh85d43vr4wwqnq6e7akxtlwkzx2y8cmdm3wrxzj6m42pzj3xs2heqey79hgxrhwhapwu8tt73g", - "zs1uhwgwkg2y3xex7e34dvnx97d0jdnhmchevcvg54tg4dg00ay9sjucr82py4jqx0kkf7cz5dytad", - "zs1uhkhsv3c3m5r8z7unmceg4zln6edwfr25wjauv5u8fxdqhdflj7vuc2xnkm9028y802w2pyf07g", - "zs1uhuwuzu89j05p9y48nseklu7gfhw4mrwv68f9s66csafrkpsmpsh23zzgxm24nspmsgrvtpttzg", - "zs1ucetuz8ysvz42uvuwndjfnphrtsfgekgef228meuhfrqtm97gql87rsvhxmxplw2xmj27p9jemj", - "zs1ucm95fgyy72rf6x5rwl5m5pldt38lulzqf9ueepel4gvd4cqjhk8xrf4kvl2lnn5ge9fwyfrfva", - "zs1um3pu2u0eu0zpx4czj9dufvxnud2zd0x5lygepp6maz96j572r6mh8gpmlm3w6jhmxxz2sepdfh", - "zs1ulkw8j488xuhhlewedj9dr7atm5jatmlwsxz83lquhz42ln78utqmtqsmhagcquq6uqszk23g9d", - "zs1az03j8f46n2600z47xnf5y28j34rpxljh3j6w5p3xgsmqt2fuklmhyd383aljxf4mx4pcfv0xm8", - "zs1ayal4wq4crwj70u6hae82h6r4jpk7ptycfhs9v5y83lxc7u4gadegu2r5ggsgt95n0rjk284fzj", - "zs1a984wux9sr2594lr24yal43zq6pstczyevj7yr8pn403643zuge88ekrc0cj8n2fk6z6xrxjpsz", - "zs1a95ptq9d6nauwtvgdj2lnct9y6g4cmm258jzyuqhsk4m3gqmaz62t4klqe42eu83n27jcpgz0ed", - "zs1a8xdhdzpjqx0alrjg43enszjnf6nn6nhf6c3xd77ecrvp4kfarvux4u4lcttv3rgyhmgzxukw2q", - "zs1afqnaljmvzunvjhr3m8yf2g4r0pe66kkxkm6ldjhylyjfsclk3nf88u29pskdqx76szdz48tt3m", - "zs1avx0j6mrcqrhp9903xrysptm6gefcyv6uqltta92hsgjpp2f8h8rz8suwxgjkp2f8366y6n6dj8", - "zs1a036amk3q8azryytah2zpdhyazeruq2q7zq2c06l0845kl0v2rmg0h8cdjvta4alxj0my4kcfad", - "zs1ahy2sja2ala03wrc79xx2ks3ujxxnsm44uh6yucmy5p5l0xcfa3g90cdgs4l9rhy975zvd4uzts", - "zs1aeyqta7xs8edzq2c0z6e9v3vjep55e4lg9fp9ls6d55x2mel6snxud6kqcaz8nl7zgrxxj96d6a", - "zs1aap3thj9xna07vlg3yz389c34v9mgd06g234d3htyq667286phjsf98nndm8frts7frmcyjfa90", - "zs17qdqrdgwcafkpgchc4rvk22e4u86alhnmzne5xzantpecwrxf3c6jxqk7xgzanzjj4kmxd2tuwg", - "zs17z3fmn6e84ypzpzn0p0j9nddptrj2nwhk9lhaw952j0lzxslrp24cj0ltuem9g5dustakcq4dsp", - "zs17zut2398dst3hnmnslnk0jv9w4q9yn8akelymvs8ewurdytxushp92nyqv30quqhy0yju7rn7lw", - "zs17r4fuv9ldl3kzwk5stv59exusc7jlsmtcz4t2uzjnrgrr6aj6tvnp04wc9jq2n3eh6fsyqe2ru5", - "zs17rajftxlkcywcenl0cn3fqw4lh2un5lpfegjdz06j3vl9gjmay2d5pk7uequ02vw6tmtzz6jrst", - "zs179rvu8endcr48sft7zg4w6uvxwu4ps94r06uwk7e606yffkgtx7epaamlfdqnc6xa4l9scqcv4v", - "zs178dr2z7zgqrsg5ul3sxx05qky2kemfequf08dxr332n9f5fq9cj98jttssz97lzmf2k22xpn54m", - "zs172zz77ds82urqmsa9pgyz65k04euw7uuk58k4ardcxectjc4t4yjekxm8xxmgd7gqs8k6jupypk", - "zs172eamykp6sl4vx4tsgmg2t0p482hnn3gg4my9y4frd4tl5zgsyrsvjvlxc9zjtqpve6e6djdc4x", - "zs17v4xqdu83fkvrjxrpnjksuanj0pung2kqn9ys533nnm8kq8ad8xv9kd48e4utrz947pejg55p46", - "zs17dgakqvwzgh4dgfe70cjulju698cs50zvchsze2e3zvdp68wytqdcvj4suh4vq2acdg7wuvs7ar", - "zs17snaqr6vukwp4apsdf44h6w3flgphzrnpmdjly662tgqtvkgs72lpz7m7tnkksdmt5uzjgmpg2e", - "zs173ad7l6u8dr90e2t5jkrnw0gc9u2mppv9vjeh8l6q2jdvgnq6tq4anxxltwuxm3wssfzgg6hfcy", - "zs17nez6jn8tnse243f5uf72d8y000ynmjnm6vsrpzpd2fj75wq4u4lu7xc8fmtn2e5v0r7uknphs3", - "zs174c6x8u2yagjnsq2kswnd6fh8u2f3g5dkrk7r7ja5n30zwjm4ke3x84syt9qklqyk0m7vekcx9f", - "zs174mlfm6snsmgj4usez3e6xtd5nkwwl24vgg96srpnv7ulz4de6n4lx6cmxaqszqnk7p9y6wcl8q", - "zs17h5lnrnpprdtkjwq09ax94qetryf65qm5jqv0gpyeesw4wujytks9qljvlry863flf242arvx8f", - "zs1lp07e40usxenrznuuf2nzn5v7tx9pzp9r6eaw6upnm4t9cer8l5fckzm7jr58j5l77tzjrprv8v", - "zs1ly5u5sqeeax9g3uafva7fl35r3wv0nm2aka9m940graqjh0zlw7rrcgay0a7f29j3ar4wrj4uzu", - "zs1lgqckcp2uqx5c6gdm5zklzrxz8ygva9kxtxc4u4dlzpg68m9prga5q3ur3uqutkcy4ztuhclrxw", - "zs1lgz7ychnnhe58hk2e379zhqdxynp30e6fdh6xjxx8u9ga9rmwzdrdvqcq5kps2uetyf6gzeqdn2", - "zs1l2ghymesqwrfw89pqnw08u346es6wn86r77a55n7d7xky2rc58jfhn7man9kjjesnegec3frxeh", - "zs1ls3lyaqhm39zgz3528ereaa48vzsw4cw99k536524a6ruxmdqyvqnv4pl477q7rwptrzx8dhhzu", - "zs1lsnr42d2ez0w55pxws4qn70f68vxllv92wppu24n75y7a0wrmkw6qgup0md5jhjmkwhzu742zx4", - "zs1ljzwlum9nme83hhvkjkxl323u0ezm4sgnk84nzkyu5acum0kxf0s6g06gy78w0hl66f5263g7ha", - "zs1l5kfev0dpl8swjlyvyms5t9yhhnvg0590jfgpxw7zxx6eh29vd7453q9d0ne75x7gsm42j65l3v", - "zs1lhpxmvxmfpdfa5myd35wf24pmacrgdhrcpxydrcwz3qvmfvpt9x78nf2ne3kkqh40m0nvhhd3uj", - "zs1lhkhftvpkvcuyhwgcz4gq9y9l3ly5esglk2g0sgdctrz2cd63lgss2gtn8eedsvtuh8f6shpwww", - }; - //TODO: Assumes pools of 100 - int randIndex = GetRandInt(100); // random int between 0 and 99 - if(randIndex % 2) { - return SietchShieldedPool1[randIndex]; - } else { - return SietchShieldedPool2[randIndex]; - } + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto zdust = sk.default_address(); + return EncodePaymentAddress(zdust); } #endif diff --git a/src/version.h b/src/version.h index 4056f105d..5cf912492 100644 --- a/src/version.h +++ b/src/version.h @@ -1,6 +1,7 @@ // Copyright (c) 2012-2014 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -24,7 +25,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 170008; +static const int PROTOCOL_VERSION = 170009; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 72af5d930..2cd835cbe 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -200,7 +200,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk) "2. \"label\" (string, optional, default=\"\") An optional label\n" "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "4. height (integer, optional, default=0) start at block height?\n" - "5. secret_key (integer, optional, default=188) used to import WIFs of other coins\n" + "5. secret_key (integer, optional, default=188) decimal value used to import WIFs of other coins\n" "\nNote: This call can take minutes to complete if rescan is true.\n" "\nExamples:\n" "\nDump a private key\n" diff --git a/src/wallet/rpchushwallet.cpp b/src/wallet/rpchushwallet.cpp index 64cd0e4a5..5fd77cc97 100644 --- a/src/wallet/rpchushwallet.cpp +++ b/src/wallet/rpchushwallet.cpp @@ -134,6 +134,9 @@ void zsTxSpendsToJSON(const CWalletTx& wtx, UniValue& spends, CAmount& totalSpen void zsTxReceivedToJSON(const CWalletTx& wtx, UniValue& received, CAmount& totalReceived, const std::string& strAddress, bool filterByAddress) { + if(fZdebug) + fprintf(stderr,"%s: txid=%s\n", __func__, wtx.GetHash().ToString().c_str() ); + LOCK2(cs_main, pwalletMain->cs_wallet); //Check address @@ -401,6 +404,10 @@ void zsWalletTxJSON(const CWalletTx& wtx, UniValue& ret, const std::string strAd //Begin Compiling the Decrypted Transaction tx.push_back(Pair("txid", wtx.GetHash().ToString())); + + if(fZdebug) + fprintf(stderr,"%s: txid=%s\n", __func__, wtx.GetHash().ToString().c_str() ); + if (wtx.IsCoinBase()) { tx.push_back(Pair("coinbase", true)); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a2fa34b3b..89d15f14f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -72,8 +72,7 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SAPLING = "sapling"; -const std::string ADDR_TYPE_DONOTREMEMBER = "donotremember"; -extern UniValue TxJoinSplitToJSON(const CTransaction& tx); +const std::string ADDR_TYPE_AMNESIA = "amnesia"; extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); @@ -170,7 +169,6 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); - entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx))); } string AccountFromValue(const UniValue& value) @@ -3352,8 +3350,8 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey& if (fHelp || params.size() > 5 || params.size() == 3) throw runtime_error( - "z_listreceivedbyaddress\n" - "\nReturns received outputs for a single address.\n" + "z_listreceivedaddress\n" + "\nReturns received outputs.\n" "\n" "This function only returns information on addresses with full spending keys." "\n" @@ -3411,8 +3409,8 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey& " }],\n" " },\n" "\nExamples:\n" - + HelpExampleCli("z_listreceivedbyaddress", "R...") - + HelpExampleRpc("z_listreceivedbyaddress", "R...") + + HelpExampleCli("z_listreceivedaddress", "\"*\"") + + HelpExampleRpc("z_listreceivedaddress", "RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn") ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3895,16 +3893,16 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk throw runtime_error( "z_getnewaddress ( type )\n" "\nReturns a new shielded address for receiving payments.\n" - "\nWith no arguments, returns a Sapling address.\n" - "\nBe very careful with 'donotremember' address type, the extended spending key (xsk) of that address is not stored in wallet.dat!\n" + "\nWith no arguments, returns a Sapling address (zaddr).\n" + "\nBe very careful with 'amnesia' address type, the address is not stored in wallet.dat and if you send funds to it THEY WILL BE LOST FOREVER\n" "\nArguments:\n" - "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. Either "+ ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER + " .\n" + "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. Either "+ ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_AMNESIA + " .\n" "\nResult:\n" "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new shielded address.\n" "\nExamples:\n" + HelpExampleCli("z_getnewaddress", "") + HelpExampleCli("z_getnewaddress", ADDR_TYPE_SAPLING) - + HelpExampleCli("z_getnewaddress", ADDR_TYPE_DONOTREMEMBER) + + HelpExampleCli("z_getnewaddress", ADDR_TYPE_AMNESIA) ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3917,15 +3915,14 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk } if (addrType == ADDR_TYPE_SAPLING) { return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey()); - } else if (addrType == ADDR_TYPE_DONOTREMEMBER) { - bool addToWallet = false; - auto zaddr = EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey(addToWallet)); + } else if (addrType == ADDR_TYPE_AMNESIA) { + auto zaddr = randomSietchZaddr(); if(fZdebug) { - fprintf(stderr,"%s: Sietch zaddr=%s created, xsk not stored in wallet.dat!\n", __FUNCTION__, zaddr.c_str() ); + fprintf(stderr,"%s: Sietch zaddr=%s created, not stored in wallet.dat!\n", __FUNCTION__, zaddr.c_str() ); } return zaddr; } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type! Try " + ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type! Try " + ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_AMNESIA); } } @@ -4086,7 +4083,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK " \"txid\": xxxxx, (string) the transaction id\n" " \"amount\": xxxxx, (numeric) the amount of value in the note\n" " \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n" - " \"confirmations\" : n, (numeric) the number of confirmations\n" + " \"confirmations\" : n, (numeric) the number of notarized confirmations (dpowconfs)\n" + " \"rawconfirmations\" : n, (numeric) the number of raw confirmations\n" " \"outindex\" (sapling) : n, (numeric) the output index\n" " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n" "}\n" @@ -4131,7 +4129,6 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK if (boost::get(&zaddr) != nullptr) { for (SaplingNoteEntry & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); - int nHeight = tx_height(entry.op.hash); int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); // Only return notarized results when minconf>1 @@ -4152,6 +4149,10 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK } obj.push_back(Pair("outindex", (int)entry.op.n)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); + auto wtx = pwalletMain->mapWallet.at(entry.op.hash); //.ToString()); + //fprintf(stderr,"%s: txid=%s not found in wallet!\n", __func__, entry.op.hash.ToString().c_str()); + obj.push_back(Pair("time", wtx.GetTxTime())); + obj.push_back(Pair("confirmations", dpowconfs)); if (hasSpendingKey) { obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op))); @@ -4740,24 +4741,22 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) // End goal is to have this be as large as possible without slowing xtns down too much // A value of 7 will provide much stronger linkability privacy versus pre-Sietch operations unsigned int DEFAULT_MIN_ZOUTS=7; - unsigned int MAX_ZOUTS=25; + unsigned int MAX_ZOUTS=50; unsigned int MIN_ZOUTS=GetArg("--sietch-min-zouts", DEFAULT_MIN_ZOUTS); if((MIN_ZOUTS<3) || (MIN_ZOUTS>MAX_ZOUTS)) { - fprintf(stderr,"%s: Sietch min zouts must be >=3 and <= 25, setting to default value of %d\n", __FUNCTION__, DEFAULT_MIN_ZOUTS ); + fprintf(stderr,"%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS ); MIN_ZOUTS=DEFAULT_MIN_ZOUTS; } int nAmount = 0; - // Dynamic Sietch zaddrs default to OFF - bool fSietchDynamic = GetArg("--sietch-dynamic",0); while (zaddrRecipients.size() < MIN_ZOUTS) { // OK, we identify this xtn as needing privacy zdust, we must decide how much, non-deterministically int decider = 1 + GetRandInt(100); // random int between 1 and 100 string zdust1, zdust2; - // Which zaddr we send to is non-deterministically chosen from two zpools... - zdust1 = fSietchDynamic ? newSietchZaddr() : randomSietchZaddr(); + // Which zaddr we send to is randomly generated + zdust1 = randomSietchZaddr(); // And their ordering when given to internals is also non-deterministic, which // helps breaks assumptions blockchain analysts may use from z_sendmany internals @@ -4771,7 +4770,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) //50% chance of adding another zout if (decider % 2) { - zdust2 = fSietchDynamic ? newSietchZaddr() : randomSietchZaddr(); + zdust2 = randomSietchZaddr(); // 50% chance of adding it to the front or back since all odd numbers are 1 or 3 mod 4 if(decider % 4 == 3) { zaddrRecipients.push_back( newSietchRecipient(zdust2) ); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f519b5a46..a0cd0533f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -59,6 +59,7 @@ using namespace libzcash; /** * Settings */ +const char * DEFAULT_WALLET_DAT = "wallet.dat"; CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; @@ -668,6 +669,25 @@ void CWallet::Flush(bool shutdown) bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString) { + LogPrintf("Using wallet %s\n", walletFile); + uiInterface.InitMessage(_("Verifying wallet...")); + + if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) { + boost::filesystem::path path(walletFile); + if (path.is_absolute()) { + if (!boost::filesystem::exists(path.parent_path())) { + LogPrintf("Absolute path %s does not exist!", walletFile); + return false; + } + } else { + boost::filesystem::path full_path = GetDataDir() / path; + if (!boost::filesystem::exists(full_path.parent_path())) { + LogPrintf("Relative path %s does not exist!", walletFile); + return false; + } + } + } + if (!bitdb.Open(GetDataDir())) { // try moving the database env out of the way @@ -3930,6 +3950,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // Track how many getdata requests our transaction gets mapRequestCount[wtxNew.GetHash()] = 0; + std::string strCmd = GetArg("-txsend", ""); + if (fBroadcastTransactions) { // Broadcast @@ -3942,6 +3964,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) } wtxNew.RelayWalletTransaction(); } + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + else if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", EncodeHexTx(wtxNew)); + boost::thread t(runCommand, strCmd); // thread runs free + } } return true; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dd6100f97..475214919 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -100,6 +100,8 @@ static const unsigned int DEFAULT_TX_RETENTION_LASTTX = 200; //Amount of transactions to delete per run while syncing static const int MAX_DELETE_TX_SIZE = 50000; +extern const char * DEFAULT_WALLET_DAT; + class CBlockIndex; class CCoinControl; class COutput;