From 40d6716993e7695f52d1f6b61c8fe00fde7422ca Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sat, 1 Aug 2020 09:12:14 -0400 Subject: [PATCH 01/33] Update Hush emission schedule code based on going to 75s blocks @ Block 340K --- src/komodo_bitcoind.h | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 930d7ddf8..e58056a40 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1254,32 +1254,51 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); if (ishush3) { - int32_t starting_commission = 125000000, HALVING1 = 340000, INTERVAL = 840000, TRANSITION = 129, BR_END = 5422111; + // TODO: Calculate new BR_END based on 75s block time!!! 2X old BR_END is a rough estimate, not exact! + int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), INTERVAL = 840000, TRANSITION = 129, BR_END = 2*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 + + + 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 + // With 150s blocks, we have 210,000 blocks per year + // With 75s blocks, we have 420,000 blocks per year + INTERVAL = 1680000; + } + // Transition period of 128 blocks has BR=FR=0 if (height < TRANSITION) { commission = 0; - } else if (height < HALVING1) { + } else if (height < HALVING1) { // before 1st Halving @ Block 340000 (Nov 2020) commission = starting_commission; - } else if (height < HALVING1+1*INTERVAL) { + } else if (height < HALVING1+1*INTERVAL) { // before 2nd Halving @ Block 2020000 commission = starting_commission / 2; - } else if (height < HALVING1+2*INTERVAL) { + } else if (height < HALVING1+2*INTERVAL) { // before 3rd Halving @ Block 3700000 commission = starting_commission / 4; - } else if (height < HALVING1+3*INTERVAL) { + } else if (height < HALVING1+3*INTERVAL) { // before 4th Halving @ Block 5380000 commission = starting_commission / 8; - } else if (height < HALVING1+4*INTERVAL) { + } else if (height < HALVING1+4*INTERVAL) { // before 5th Halving @ Block 7060000 commission = starting_commission / 16; - } else if (height < HALVING1+5*INTERVAL) { + } else if (height < HALVING1+5*INTERVAL) { // before 6th Halving @ Block 8740000 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 + } else if (height < HALVING1+6*INTERVAL) { // before 7th Halving @ Block 10420000 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 + } else if (height < HALVING1+7*INTERVAL) { // before 8th Halving @ Block 12100000 + // Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting + commission = starting_commission / 128; + } else if (height < HALVING1+8*INTERVAL) { // before 9th Halving @ Block 13780000 + // BR should be zero before this halving happens + commission = starting_commission / 256; + } + // Explicitly set the last block reward + // BR_END is the block with the last non-zero block reward, which overrides + // the -ac_end param on HUSH3 + if(height > BR_END) { + commission = 0; } } From 9deb58fa4ea4dca1e959612aca313aa038d08e20 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 16 Aug 2020 23:18:15 -0400 Subject: [PATCH 02/33] Start to tweak hush_supply and save old script to compare results --- contrib/hush_supply | 2 +- contrib/hush_supply_old | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100755 contrib/hush_supply_old diff --git a/contrib/hush_supply b/contrib/hush_supply index 92e917055..674424073 100755 --- a/contrib/hush_supply +++ b/contrib/hush_supply @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# Copyright 2019 The Hush developers +# Copyright 2019-2020 The Hush developers # Released under the GPLv3 use warnings; use strict; 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; +} From 6745ea5a48e6e443375f2b98b8b4f468b04d235a Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 17 Aug 2020 00:17:09 -0400 Subject: [PATCH 03/33] WIP script to simulate Hush total supply for every block in the future until it goes to zero --- contrib/hush_supply | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/contrib/hush_supply b/contrib/hush_supply index 674424073..99659f219 100755 --- a/contrib/hush_supply +++ b/contrib/hush_supply @@ -4,30 +4,43 @@ use warnings; use strict; +# Simulate the total supply on Hush v3 mainnet + my $supply = 0.0; my $block = 0; my $satoshis = 100_000_000; -my $amount = int(12.5*$satoshis); +my $reward0 = int(12.5*$satoshis); my $halvings = 0; +my $initial = 6178674 * $satoshis; +my $interval = 1_640_000; # 4 years of 75s blocks +my $height = shift || -1; -# Usage: ./hush_supply &> supply.csv +# Usage: ./hush_supply &> supply.csv +# ./hush_supply HEIGHT &> supply.csv # stop at HEIGHT -# 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) { +my $reward = $reward0; +# We know BR will go to zero between 7 and 8th halvings +while ($halvings <= 10) { $block++; - if ($block < 5) { - $amount = 40_000 * $satoshis; + # blocks 2-127 of Hush v3 had BR=0 + if ($block == 1) { + $reward = $initial; # airdropped funds from Hush v2 mainnet + } elsif ($block > 1 && $block < 128) { + $reward = 0; # blocks 2-127 have BR=0 } else { - # Halving every 840000 blocks - if ($block % 840_000 == 0) { - $amount /= 2; - $halvings++; + if ($block < 340_000) { + $reward = $reward0; + } else { + # Past the first halving + $block -= 340_000; + $halvings = 1 + ($block % $interval); + $reward <<= $halvings; } - $amount = int(12.5*$satoshis) / (2**$halvings); } - $supply += $amount; + $supply += $reward; # block, current supply, block reward amount, number of halvings - printf "%s,%s,%s,%s\n", $block,$supply / $satoshis, $amount / $satoshis, $halvings; + # all amounts are in satoshis + printf "%s,%s,%s,%s\n",$block, $supply, $reward, $halvings; + #exit(0) if ($block > 200); + exit(0) if $block == $height; } From 5315ded7861d218072991a5bfc33d7492fd0a052 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 4 Sep 2020 19:31:05 -0700 Subject: [PATCH 04/33] Support wallet.dat outside of datadir Ported from https://github.com/zcash/zcash/commit/6a7cfdea54a9469ac1234e32db9d2fed0bb146af which did not apply cleanly. --- qa/rpc-tests/feature_walletfile.py | 51 ++++++++++++++++++++++++++++++ src/wallet/wallet.cpp | 17 ++++++++++ 2 files changed, 68 insertions(+) create mode 100755 qa/rpc-tests/feature_walletfile.py 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/wallet/wallet.cpp b/src/wallet/wallet.cpp index f519b5a46..1347ef974 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -668,6 +668,23 @@ 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())) { + return UIError(strprintf(_("Absolute path %s does not exist!"), walletFile)); + } + } else { + boost::filesystem::path full_path = GetDataDir() / path; + if (!boost::filesystem::exists(full_path.parent_path())) { + return UIError(strprintf(_("Relative path %s does not exist!"), walletFile)); + } + } + } + if (!bitdb.Open(GetDataDir())) { // try moving the database env out of the way From ad3e5db501c7d99748f8cee0a537ec8e1ea2be9f Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 4 Sep 2020 19:40:29 -0700 Subject: [PATCH 05/33] Update help regarding new -wallet option for relative paths --- src/init.cpp | 2 +- src/wallet/wallet.cpp | 1 + src/wallet/wallet.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index d52888503..cd25e63fd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -454,7 +454,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).")); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1347ef974..9d2528073 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; 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; From b3ff90ed6fbb92ae46bbbad81eb964e352802b96 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 4 Sep 2020 22:29:28 -0700 Subject: [PATCH 06/33] Add constant time AES routines --- src/crypto/ctaes/COPYING | 21 ++ src/crypto/ctaes/README.md | 41 +++ src/crypto/ctaes/bench.c | 170 ++++++++++++ src/crypto/ctaes/ctaes.c | 556 +++++++++++++++++++++++++++++++++++++ src/crypto/ctaes/ctaes.h | 41 +++ src/crypto/ctaes/test.c | 110 ++++++++ 6 files changed, 939 insertions(+) create mode 100644 src/crypto/ctaes/COPYING create mode 100644 src/crypto/ctaes/README.md create mode 100644 src/crypto/ctaes/bench.c create mode 100644 src/crypto/ctaes/ctaes.c create mode 100644 src/crypto/ctaes/ctaes.h create mode 100644 src/crypto/ctaes/test.c 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); +} From 820a48bb73610f9ae0ad195491fb24deab7048c8 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 4 Sep 2020 22:50:23 -0700 Subject: [PATCH 07/33] Add trezor bip39 code --- src/crypto/bip39/README.md | 3 + src/crypto/bip39/bip39.c | 281 +++++++ src/crypto/bip39/bip39.h | 52 ++ src/crypto/bip39/bip39_english.h | 367 +++++++++ src/crypto/bip39/hmac.c | 176 ++++ src/crypto/bip39/hmac.h | 60 ++ src/crypto/bip39/hmac_drbg.c | 130 +++ src/crypto/bip39/hmac_drbg.h | 43 + src/crypto/bip39/memzero.h | 8 + src/crypto/bip39/options.h | 99 +++ src/crypto/bip39/pbkdf2.c | 179 +++++ src/crypto/bip39/pbkdf2.h | 66 ++ src/crypto/bip39/rand.c | 81 ++ src/crypto/bip39/rand.h | 37 + src/crypto/bip39/sha2.c | 1283 ++++++++++++++++++++++++++++++ src/crypto/bip39/sha2.h | 116 +++ src/crypto/bip39/sha3.c | 397 +++++++++ src/crypto/bip39/sha3.h | 89 +++ 18 files changed, 3467 insertions(+) create mode 100644 src/crypto/bip39/README.md create mode 100644 src/crypto/bip39/bip39.c create mode 100644 src/crypto/bip39/bip39.h create mode 100644 src/crypto/bip39/bip39_english.h create mode 100644 src/crypto/bip39/hmac.c create mode 100644 src/crypto/bip39/hmac.h create mode 100644 src/crypto/bip39/hmac_drbg.c create mode 100644 src/crypto/bip39/hmac_drbg.h create mode 100644 src/crypto/bip39/memzero.h create mode 100644 src/crypto/bip39/options.h create mode 100644 src/crypto/bip39/pbkdf2.c create mode 100644 src/crypto/bip39/pbkdf2.h create mode 100644 src/crypto/bip39/rand.c create mode 100644 src/crypto/bip39/rand.h create mode 100644 src/crypto/bip39/sha2.c create mode 100644 src/crypto/bip39/sha2.h create mode 100644 src/crypto/bip39/sha3.c create mode 100644 src/crypto/bip39/sha3.h 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/bip39.c b/src/crypto/bip39/bip39.c new file mode 100644 index 000000000..33455f6c5 --- /dev/null +++ b/src/crypto/bip39/bip39.c @@ -0,0 +1,281 @@ +/** + * 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 + +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..07fb21bb2 --- /dev/null +++ b/src/crypto/bip39/bip39.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 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 +#include + +#define BIP39_WORDS 2048 +#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)); + +int mnemonic_find_word(const char *word); +const char *mnemonic_complete_word(const char *prefix, int len); +const char *mnemonic_get_word(int index); +uint32_t mnemonic_word_completion_mask(const char *prefix, int len); + +#endif diff --git a/src/crypto/bip39/bip39_english.h b/src/crypto/bip39/bip39_english.h new file mode 100644 index 000000000..c57fca365 --- /dev/null +++ b/src/crypto/bip39/bip39_english.h @@ -0,0 +1,367 @@ +/** + * 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/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..3921a171e --- /dev/null +++ b/src/crypto/bip39/hmac.h @@ -0,0 +1,60 @@ +/** + * 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.h b/src/crypto/bip39/memzero.h new file mode 100644 index 000000000..0a959fbc2 --- /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..d3a9c2edf --- /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..c2e3f04a6 --- /dev/null +++ b/src/crypto/bip39/pbkdf2.h @@ -0,0 +1,66 @@ +/** + * 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/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__ */ From 86ad289a42b3f6b26cbff6a6bb8aa6257bad89c4 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sat, 5 Sep 2020 04:45:54 -0700 Subject: [PATCH 08/33] Clean up dead code --- src/main.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d58edff19..60e350c44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2421,30 +2421,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { 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; } bool IsInitialBlockDownload() From 0c0b2ec1cc58d1d3f01c1b6a5e3ad847bb9840e5 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sat, 5 Sep 2020 05:36:28 -0700 Subject: [PATCH 09/33] cleanup --- src/komodo_bitcoind.h | 5 +---- src/main.cpp | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e58056a40..93dd18f8b 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1236,10 +1236,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); 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); + static bool didinit = false, ishush3 = false; if (!didinit) { ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; diff --git a/src/main.cpp b/src/main.cpp index 60e350c44..5038a0c00 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2416,9 +2416,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) else if ( nHeight < 2*KOMODO_ENDOFERA ) return(2 * COIN); else return(COIN); - } - else - { + } else { return(komodo_ac_block_subsidy(nHeight)); } } From 2bb5454020621d0b9359ff237c65a66c98dc75fc Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sat, 5 Sep 2020 05:38:09 -0700 Subject: [PATCH 10/33] Explicitly set BR in each halving interval This extremely important consensus-changing code takes into account that with our new 75s block time, which gives us twice as many blocks per day, we must divide our block reward by two in the next halving interval, becoming 3.125 HUSH per block insted of 6.25 HUSH under the old rules of 150s blocks. Subsequent halving intervals do not change block times, and so they follow the normal pattern of halving. This commit has a number of rough edges: * Final BR height is still incorrect * Due to above, exact number of halvings is unknown under new 75s blocktime --- src/komodo_bitcoind.h | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 93dd18f8b..1f95052c7 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1250,15 +1250,24 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) //fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); + // Do not change this code unless you really know what you are doing. + // Here Be Dragons! -- Duke Leto if (ishush3) { // TODO: Calculate new BR_END based on 75s block time!!! 2X old BR_END is a rough estimate, not exact! int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), INTERVAL = 840000, TRANSITION = 129, BR_END = 2*5422111; + // TODO: how many halvings will we have given new 75s blocktime? + int32_t commisions[] = {starting_commision, 3125000000, 1562500000, 781250000, 390625000, + 195312500, 97656250, 48828125, // these are exact + 24414062, 12207031, 6103515 // 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 + }; // 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 - 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 @@ -1271,25 +1280,25 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) if (height < TRANSITION) { commission = 0; } else if (height < HALVING1) { // before 1st Halving @ Block 340000 (Nov 2020) - commission = starting_commission; + commission = commisions[0]; } else if (height < HALVING1+1*INTERVAL) { // before 2nd Halving @ Block 2020000 - commission = starting_commission / 2; + commission = commisions[1]; } else if (height < HALVING1+2*INTERVAL) { // before 3rd Halving @ Block 3700000 - commission = starting_commission / 4; + commission = commisions[2]; } else if (height < HALVING1+3*INTERVAL) { // before 4th Halving @ Block 5380000 - commission = starting_commission / 8; + commission = commisions[3]; } else if (height < HALVING1+4*INTERVAL) { // before 5th Halving @ Block 7060000 - commission = starting_commission / 16; + commission = commisions[4]; } else if (height < HALVING1+5*INTERVAL) { // before 6th Halving @ Block 8740000 - commission = starting_commission / 32; + commission = commisions[5]; } else if (height < HALVING1+6*INTERVAL) { // before 7th Halving @ Block 10420000 - commission = starting_commission / 64; + commission = commisions[6]; } else if (height < HALVING1+7*INTERVAL) { // before 8th Halving @ Block 12100000 - // Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting - commission = starting_commission / 128; + // 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 = starting_commission / 256; + commission = commisions[8]; } // Explicitly set the last block reward // BR_END is the block with the last non-zero block reward, which overrides From 1c4a2ee13c6e5681ba80b1db7791402e62ac026b Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 08:33:38 -0400 Subject: [PATCH 11/33] WIP hush_supply --- contrib/hush_supply | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/contrib/hush_supply b/contrib/hush_supply index 99659f219..f7813c64d 100755 --- a/contrib/hush_supply +++ b/contrib/hush_supply @@ -5,42 +5,52 @@ use warnings; use strict; # Simulate the total supply on Hush v3 mainnet +# Todo: track FR +# Todo: verify FR off-by-one my $supply = 0.0; -my $block = 0; -my $satoshis = 100_000_000; -my $reward0 = int(12.5*$satoshis); +my $block = 0; # Block 0 in Hush Smart chains is the BTC genesis block +my $puposhis = 100_000_000; +my $reward0 = 1_250_000_000; my $halvings = 0; -my $initial = 6178674 * $satoshis; +my $initial = 6178674 * $puposhis; my $interval = 1_640_000; # 4 years of 75s blocks -my $height = shift || -1; +my $stop = shift || -1; +my $totalfr = 0; # total paid out to FR address +my $reward = $reward0; # Usage: ./hush_supply &> supply.csv # ./hush_supply HEIGHT &> supply.csv # stop at HEIGHT -my $reward = $reward0; +printf "# block, supply, reward, fr, totalfr, halvings\n"; + # We know BR will go to zero between 7 and 8th halvings while ($halvings <= 10) { $block++; + my $fr = 0; # blocks 2-127 of Hush v3 had BR=0 if ($block == 1) { $reward = $initial; # airdropped funds from Hush v2 mainnet } elsif ($block > 1 && $block < 128) { $reward = 0; # blocks 2-127 have BR=0 } else { + $fr = 125_000_000; if ($block < 340_000) { $reward = $reward0; } else { + my $shifted = $block - 340_000; # Past the first halving - $block -= 340_000; - $halvings = 1 + ($block % $interval); - $reward <<= $halvings; + $halvings = 1 + int ($shifted / $interval); + if ($shifted % 840_000 == 0) { + $reward >>= 2; + $fr >>= 2; + } } } - $supply += $reward; - # block, current supply, block reward amount, number of halvings - # all amounts are in satoshis - printf "%s,%s,%s,%s\n",$block, $supply, $reward, $halvings; - #exit(0) if ($block > 200); - exit(0) if $block == $height; + $supply += $reward; + $totalfr += $fr; + + # block, current supply, block reward amount, number of halvings, all amounts are in puposhis + printf "%d,%d,%d,%d,%d,%d\n", $block, $supply, $reward, $fr, $totalfr, $halvings; + exit(0) if $block == $stop; } From b9fd0ce900f51634aa10b79995b66877606aa227 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 08:34:19 -0400 Subject: [PATCH 12/33] Fix bugs in porting zec upstream code --- src/wallet/wallet.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9d2528073..fe8cbb4f7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -676,12 +676,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er boost::filesystem::path path(walletFile); if (path.is_absolute()) { if (!boost::filesystem::exists(path.parent_path())) { - return UIError(strprintf(_("Absolute path %s does not exist!"), walletFile)); + 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())) { - return UIError(strprintf(_("Relative path %s does not exist!"), walletFile)); + LogPrintf("Relative path %s does not exist!", walletFile); + return false; } } } From 043d58709de8d70ecff9e2cb31bd4627e4d97ecd Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 08:36:48 -0400 Subject: [PATCH 13/33] Fix off-by-one-decimal-place error discovered by @DenioD --- src/komodo_bitcoind.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 1f95052c7..23c35a7b9 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1234,6 +1234,10 @@ 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 uint64_t komodo_commission(const CBlock *pblock,int32_t height) { static bool didinit = false, ishush3 = false; @@ -1256,9 +1260,8 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) // TODO: Calculate new BR_END based on 75s block time!!! 2X old BR_END is a rough estimate, not exact! int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), INTERVAL = 840000, TRANSITION = 129, BR_END = 2*5422111; // TODO: how many halvings will we have given new 75s blocktime? - int32_t commisions[] = {starting_commision, 3125000000, 1562500000, 781250000, 390625000, - 195312500, 97656250, 48828125, // these are exact - 24414062, 12207031, 6103515 // these have deviation from ideal BR + int32_t commisions[] = {starting_commission, 312500000, 156250000, 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 From 58f7ae13369d5180e2b28d5002026199a1698171 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 08:51:50 -0400 Subject: [PATCH 14/33] Document hushd a bit --- src/hushd | 27 +++++++++++++++++---------- src/hushd-testnet | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/hushd b/src/hushd index b5b504ea4..896cc7055 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,29 +8,36 @@ 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 + +# 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 +# NOTE: komodo_bitcoind.h decides these values 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 FAUCET=228 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 )" From 880cbc6b0d99e5446920e4a1dac698da7484c418 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 08:54:12 -0400 Subject: [PATCH 15/33] Mo docs for hushd --- src/hushd | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hushd b/src/hushd index 896cc7055..ca3f28319 100755 --- a/src/hushd +++ b/src/hushd @@ -28,10 +28,9 @@ HALVING=129,340000,840000 PERC=11111111 END=128,340000,5422111 -# 6250000 - (sprout pool at block 500,000) +# 6250000 - (Sprout pool at block 500,000) SUPPLY=6178674 FOUNDERS=1 -# NOTE: komodo_bitcoind.h decides these values CLIENTNAME=GoldenSandtrout NODE1=188.165.212.101 # EU NODE2=64.120.113.130 # AR @@ -40,6 +39,10 @@ NODE4=94.130.35.94 # EU CCLIB=hush3 # 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 @@ -60,7 +63,6 @@ else fi fi - $KMD -ac_name=$NAME \ -ac_sapling=$SAPLING \ -ac_reward=$REWARD \ From d420e144720b039b5d42015773616db9f991f8b2 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 12:35:15 -0400 Subject: [PATCH 16/33] Explicitly set the Hush block reward and halving intervals for the next two halvings (8 years) --- src/komodo_utils.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 0a1634348..f5acc56b0 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1634,6 +1634,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) return(subsidy); } +extern bool ishush3; extern int64_t MAX_MONEY; void komodo_cbopretupdate(int32_t forceflag); void SplitStr(const std::string& strVal, std::vector &outVals); @@ -1810,8 +1811,21 @@ void komodo_args(char *argv0) } 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); + if(ishush3) { + // 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 (old halving interval plus new halving interval) + ASSETCHAINS_HALVING[3] = 3700000; // ASSETCHAINS_HALVING[2] + 1680000; + // 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); From 727abe0ef2e3c7b9ad2323f7330d9c030ae072e6 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 12:36:26 -0400 Subject: [PATCH 17/33] Be more precise --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index f5acc56b0..252da087f 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1821,7 +1821,7 @@ void komodo_args(char *argv0) 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 (old halving interval plus new halving interval) + ASSETCHAINS_HALVING[2] = 2020000; // 2020000 = 340000 + 1680000 (1st halving block plus new halving interval) ASSETCHAINS_HALVING[3] = 3700000; // ASSETCHAINS_HALVING[2] + 1680000; // TODO: fill in all possible values for each halving/reward interval // based on simple halving schedule From 9ae40031d63bab98b28bce49e545394e6f8bd810 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 12:58:50 -0400 Subject: [PATCH 18/33] Add -ac_halving1 + -ac_halving2 CLI args for devs These new CLI args control the interval of the 1st halving (between 1st and 2nd halving blocks) and the 2nd halving (between 2nd and 3rd halving blocks). -ac_halving2 is used for all subsequent halvings. This allows devs to simulate things via the CLI without changing code, to verify things work as expected at halvings in the far future. --- src/komodo_bitcoind.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 23c35a7b9..b596a60f6 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1258,7 +1258,8 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) // Here Be Dragons! -- Duke Leto if (ishush3) { // TODO: Calculate new BR_END based on 75s block time!!! 2X old BR_END is a rough estimate, not exact! - int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), INTERVAL = 840000, TRANSITION = 129, BR_END = 2*5422111; + int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), + INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129, BR_END = 2*5422111; // TODO: how many halvings will we have given new 75s blocktime? int32_t commisions[] = {starting_commission, 312500000, 156250000, 78125000, 39062500, 19531250, 9765625, // these are exact 4882812, 2441406, 1220703, 610351 // these have deviation from ideal BR @@ -1276,7 +1277,7 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) // must be twice as often, i.e. 840000*2=1680000 // With 150s blocks, we have 210,000 blocks per year // With 75s blocks, we have 420,000 blocks per year - INTERVAL = 1680000; + INTERVAL = GetArg("-ac_halving2",1680000); } // Transition period of 128 blocks has BR=FR=0 From b572ef02283cbf27078aae76a5b08eedec6b920a Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Mon, 7 Sep 2020 18:40:51 -0400 Subject: [PATCH 19/33] Calculate this value at run-time because it's not set yet when this header file is parsed --- src/komodo_utils.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 252da087f..2c56dad33 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1634,7 +1634,6 @@ uint64_t komodo_ac_block_subsidy(int nHeight) return(subsidy); } -extern bool ishush3; extern int64_t MAX_MONEY; void komodo_cbopretupdate(int32_t forceflag); void SplitStr(const std::string& strVal, std::vector &outVals); @@ -1813,6 +1812,9 @@ void komodo_args(char *argv0) Split(GetArg("-ac_end",""), sizeof(ASSETCHAINS_ENDSUBSIDY)/sizeof(*ASSETCHAINS_ENDSUBSIDY), ASSETCHAINS_ENDSUBSIDY, 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) { // Over-ride HUSH3 values from CLI params. Changing our blocktime to 75s changes things ASSETCHAINS_REWARD[0] = 0; From d53e39aa4d4b4ce4d28335f5387a3bc94c9efcf2 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 8 Sep 2020 05:47:53 -0700 Subject: [PATCH 20/33] Good ol' off-by-one strikes again --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index b596a60f6..19d00f319 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1261,7 +1261,7 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), INTERVAL = GetArg("-ac_halving1",840000), TRANSITION = 129, BR_END = 2*5422111; // TODO: how many halvings will we have given new 75s blocktime? - int32_t commisions[] = {starting_commission, 312500000, 156250000, 78125000, 39062500, 19531250, 9765625, // these are exact + 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 From 31940f2b3a994dfc457fd003f505a701991f1c04 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 09:54:13 -0400 Subject: [PATCH 21/33] Thanks to @DenioD for reminding me we must modify -ac_end internals variable as well --- src/komodo_utils.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 2c56dad33..985b9f663 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1816,15 +1816,19 @@ void komodo_args(char *argv0) bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; if(ishush3) { + fprintf(stderr,"Setting custom HUSH3 chain values...\n"); // 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_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 } From 95ff64404cf2fe6f8113d70748baadc6a238732e Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 11:10:43 -0400 Subject: [PATCH 22/33] Specify that secret_key is a decimal not hex value --- src/wallet/rpcdump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" From 67ed136e25a4e510e7a6c91344117da319331ab2 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 11:45:19 -0400 Subject: [PATCH 23/33] Only give 3 values for now to match how many values come in via CLI --- src/komodo_utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 985b9f663..60c10827a 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1821,11 +1821,11 @@ void komodo_args(char *argv0) 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_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_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 From fe4f0f7e9ece22aba55a714e6f71b829ed551473 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 12:01:07 -0400 Subject: [PATCH 24/33] Logspam --- src/komodo_bitcoind.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 19d00f319..dac8de882 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -2003,14 +2003,14 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height) 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,"komodo_checkcommission vsize.%d height.%d commission %.8f\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 ( 1 ) { int32_t i; for (i=0; i Date: Tue, 8 Sep 2020 12:47:17 -0400 Subject: [PATCH 25/33] Behold vast logspam, refactoring and dead code removal --- src/komodo_bitcoind.h | 5 ++++- src/komodo_utils.h | 29 +++++++++++------------------ src/main.cpp | 15 +++------------ 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index dac8de882..50973ef03 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1240,18 +1240,20 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); // or start your own Hush Smart Chain: https://github.com/myhush/hush-smart-chains uint64_t komodo_commission(const CBlock *pblock,int32_t height) { + 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)); + fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); // Do not change this code unless you really know what you are doing. @@ -1997,6 +1999,7 @@ void GetKomodoEarlytxidScriptPub() int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { + 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 ) { diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 60c10827a..6df9366ec 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1548,10 +1548,9 @@ uint64_t komodo_ac_block_subsidy(int nHeight) static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era; // 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 ) { 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 ) { @@ -1571,16 +1570,14 @@ uint64_t komodo_ac_block_subsidy(int nHeight) { if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) { - if ( ASSETCHAINS_DECAY[curEra] == 0 ) + 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\n",__func__, numhalvings, curEra, subsidy); + } 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 +1589,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; @@ -1614,6 +1608,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) 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; @@ -1628,9 +1623,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) else subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; } - else if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 ) - return(0); - // LABS fungible chains, cannot have any block reward! + fprintf(stderr,"%s: ht.%d curEra.%d subsidy.%ld numhalvings.%d\n",__func__,nHeight,curEra,subsidy,numhalvings); return(subsidy); } diff --git a/src/main.cpp b/src/main.cpp index 5038a0c00..c4fb5a26f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2406,19 +2406,10 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW) CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { + fprintf(stderr,"%s: ht.%d\n", __func__, nHeight); 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)); - } + + return komodo_ac_block_subsidy(nHeight); } bool IsInitialBlockDownload() From 5871b3019ab7d2fb22e9326e2b85d006b8dd998e Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 14:57:38 -0400 Subject: [PATCH 26/33] Mo debug regarding current era and block subsidy --- src/komodo_utils.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 6df9366ec..51efd81c1 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1549,6 +1549,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) // check for backwards compat, older chains with no explicit rewards had 0.0001 block reward 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 ) { // if we have an end block in the first era, find our current era @@ -1564,6 +1565,8 @@ uint64_t komodo_ac_block_subsidy(int nHeight) { int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; subsidy = (int64_t)ASSETCHAINS_REWARD[curEra]; + 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 ) @@ -1572,7 +1575,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) { if ( ASSETCHAINS_DECAY[curEra] == 0 ) { subsidy >>= numhalvings; - fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld\n",__func__, numhalvings, curEra, subsidy); + 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 ) { From 1751f986f1757fda3d42d3dcd92a5ca33576d2f5 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 15:16:00 -0400 Subject: [PATCH 27/33] Logspam for last and max eras --- src/komodo_utils.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 51efd81c1..13ee98890 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1618,15 +1618,13 @@ uint64_t komodo_ac_block_subsidy(int nHeight) 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; } - fprintf(stderr,"%s: ht.%d curEra.%d subsidy.%ld numhalvings.%d\n",__func__,nHeight,curEra,subsidy,numhalvings); + fprintf(stderr,"%s: ht.%d curEra.%d lastEra.%d subsidy.%ld numhalvings.%d\n",__func__,nHeight,curEra,ASSETCHAINS_LASTERA,subsidy,numhalvings); return(subsidy); } @@ -1794,6 +1792,7 @@ 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; + fprintf(stderr,"%s: lastEra=%d maxEras=%d\n", ASSETCHAINS_LASTERA, ASSETCHAINS_MAX_ERAS); ASSETCHAINS_TIMELOCKGTE = (uint64_t)GetArg("-ac_timelockgte", _ASSETCHAINS_TIMELOCKOFF); ASSETCHAINS_TIMEUNLOCKFROM = GetArg("-ac_timeunlockfrom", 0); @@ -1801,7 +1800,7 @@ 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; } From fbc34ef0714bfd02eca306115e6ffcdc6a8ee19b Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 15:49:10 -0400 Subject: [PATCH 28/33] Implement custom Hush block subsidy code since changing our blocktime and using many eras breaks assumptions of existing code --- src/komodo_utils.h | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 13ee98890..24e5933ef 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1534,6 +1534,8 @@ 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); @@ -1541,11 +1543,13 @@ uint64_t komodo_max_money() 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; 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 ) { @@ -1561,6 +1565,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) break; } } + if ( curEra <= ASSETCHAINS_LASTERA ) { int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; @@ -1571,8 +1576,26 @@ uint64_t komodo_ac_block_subsidy(int nHeight) { if ( ASSETCHAINS_HALVING[curEra] != 0 ) { - if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) - { + if (ishush3) { + //TODO: Cover all halvings until BR=0 + if (nHeight >= 129) { + // This is the beginning of an Era but not a Halving + } else if (nHeight >= GetArg("-z2zheight",340000)) { + numhalvings = 1; + } else if (nHeight >= 2020000) { + numhalvings = 2; + } else if (nHeight >= 3700000) { + numhalvings = 3; + } + + // Since we had 128 blocks of BR=0 when we launched Hush v3 mainnet, it adds an index + // to the beginning of ASSETCHAINS_REWARD, so we must add one to numhalvings to get + // the correct block reward + subsidy = ASSETCHAINS_REWARD[numhalvings+1]; + + fprintf(stderr,"%s: HUSH3 subsidy=%ld numhalvings=%d at height=%d\n",__func__,subsidy,numhalvings,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; fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart); @@ -1606,6 +1629,8 @@ 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); @@ -1624,7 +1649,7 @@ uint64_t komodo_ac_block_subsidy(int nHeight) else subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra; } - fprintf(stderr,"%s: ht.%d curEra.%d lastEra.%d subsidy.%ld numhalvings.%d\n",__func__,nHeight,curEra,ASSETCHAINS_LASTERA,subsidy,numhalvings); + fprintf(stderr,"%s: ht.%d curEra.%d lastEra.%lu subsidy.%ld numhalvings.%d magicExtra.%u\n",__func__,nHeight,curEra,ASSETCHAINS_LASTERA,subsidy,numhalvings,magicExtra); return(subsidy); } @@ -1792,7 +1817,7 @@ 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; - fprintf(stderr,"%s: lastEra=%d maxEras=%d\n", ASSETCHAINS_LASTERA, ASSETCHAINS_MAX_ERAS); + 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); From 3744f429f29dfe7c1504688b8a0a8a4ce6662b7f Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 15:52:09 -0400 Subject: [PATCH 29/33] Re-enable 3rd block subsidy era --- src/komodo_utils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 24e5933ef..b6f8494cf 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1841,11 +1841,11 @@ void komodo_args(char *argv0) 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_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_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 From b432e27f1b1efff046411a44beb94aae5cc18f95 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Tue, 8 Sep 2020 16:10:32 -0400 Subject: [PATCH 30/33] Refactor hush block subsidy --- src/komodo_utils.h | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index b6f8494cf..89c1228e6 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1578,21 +1578,17 @@ uint64_t komodo_ac_block_subsidy(int nHeight) { if (ishush3) { //TODO: Cover all halvings until BR=0 - if (nHeight >= 129) { - // This is the beginning of an Era but not a Halving + //if (nHeight >= 3700000) { + // subsidy = ASSETCHAINS_REWARD[4]; + //} else + if (nHeight >= 2020000) { + subsidy = ASSETCHAINS_REWARD[3]; } else if (nHeight >= GetArg("-z2zheight",340000)) { - numhalvings = 1; - } else if (nHeight >= 2020000) { - numhalvings = 2; - } else if (nHeight >= 3700000) { - numhalvings = 3; + subsidy = ASSETCHAINS_REWARD[2]; + } else if (nHeight >= 129) { + subsidy = ASSETCHAINS_REWARD[1]; } - // Since we had 128 blocks of BR=0 when we launched Hush v3 mainnet, it adds an index - // to the beginning of ASSETCHAINS_REWARD, so we must add one to numhalvings to get - // the correct block reward - subsidy = ASSETCHAINS_REWARD[numhalvings+1]; - fprintf(stderr,"%s: HUSH3 subsidy=%ld numhalvings=%d at height=%d\n",__func__,subsidy,numhalvings,nHeight); } else if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) { // The code below is not compatible with HUSH3 mainnet From f4294a25cffccf1dfcc109e2bd541442561cd500 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 8 Sep 2020 14:33:52 -0700 Subject: [PATCH 31/33] Be more explicit --- src/komodo_utils.h | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 89c1228e6..40a0368bf 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1541,6 +1541,22 @@ uint64_t komodo_max_money() return komodo_current_supply(10000000); } +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 = 14062500; + } else if (nHeight >= GetArg("-z2zheight",340000)) { + subsidy = 281250000; + } else if (nHeight >= 129) { + subsidy = 1125000000; + } + return subsidy; +} uint64_t komodo_ac_block_subsidy(int nHeight) { fprintf(stderr,"%s: ht.%d\n", __func__, nHeight); @@ -1577,19 +1593,8 @@ uint64_t komodo_ac_block_subsidy(int nHeight) if ( ASSETCHAINS_HALVING[curEra] != 0 ) { if (ishush3) { - //TODO: Cover all halvings until BR=0 - //if (nHeight >= 3700000) { - // subsidy = ASSETCHAINS_REWARD[4]; - //} else - if (nHeight >= 2020000) { - subsidy = ASSETCHAINS_REWARD[3]; - } else if (nHeight >= GetArg("-z2zheight",340000)) { - subsidy = ASSETCHAINS_REWARD[2]; - } else if (nHeight >= 129) { - subsidy = ASSETCHAINS_REWARD[1]; - } - - fprintf(stderr,"%s: HUSH3 subsidy=%ld numhalvings=%d at height=%d\n",__func__,subsidy,numhalvings,nHeight); + subsidy = hush_block_subsidy(nHeight); + 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 ) { From dd13bfb3949f06911a0dfdb4c1902cddea565a88 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 8 Sep 2020 14:38:58 -0700 Subject: [PATCH 32/33] Yep --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 40a0368bf..5d2980df9 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1549,7 +1549,7 @@ uint64_t hush_block_subsidy(int nHeight) // subsidy = ASSETCHAINS_REWARD[4]; //} else if (nHeight >= 2020000) { - subsidy = 14062500; + subsidy = 140625000; } else if (nHeight >= GetArg("-z2zheight",340000)) { subsidy = 281250000; } else if (nHeight >= 129) { From 844626f4572d04c072ad666f4eb69ea77e4e11c7 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 8 Sep 2020 15:06:06 -0700 Subject: [PATCH 33/33] Block 128 has a block reward of 11.25 HUSH --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 5d2980df9..52d6899f0 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1552,7 +1552,7 @@ uint64_t hush_block_subsidy(int nHeight) subsidy = 140625000; } else if (nHeight >= GetArg("-z2zheight",340000)) { subsidy = 281250000; - } else if (nHeight >= 129) { + } else if (nHeight >= 128) { subsidy = 1125000000; } return subsidy;