@@ -1,33 +1,56 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2019 The Hush developers
|
||||
# Copyright 2019-2020 The Hush developers
|
||||
# Released under the GPLv3
|
||||
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 $amount = int(12.5*$satoshis);
|
||||
my $block = 0; # Block 0 in Hush Smart chains is the BTC genesis block
|
||||
my $puposhis = 100_000_000;
|
||||
my $reward0 = 1_250_000_000;
|
||||
my $halvings = 0;
|
||||
my $initial = 6178674 * $puposhis;
|
||||
my $interval = 1_640_000; # 4 years of 75s blocks
|
||||
my $stop = shift || -1;
|
||||
my $totalfr = 0; # total paid out to FR address
|
||||
my $reward = $reward0;
|
||||
|
||||
# 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) {
|
||||
printf "# block, supply, reward, fr, totalfr, halvings\n";
|
||||
|
||||
# We know BR will go to zero between 7 and 8th halvings
|
||||
while ($halvings <= 10) {
|
||||
$block++;
|
||||
if ($block < 5) {
|
||||
$amount = 40_000 * $satoshis;
|
||||
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 {
|
||||
# Halving every 840000 blocks
|
||||
if ($block % 840_000 == 0) {
|
||||
$amount /= 2;
|
||||
$halvings++;
|
||||
$fr = 125_000_000;
|
||||
if ($block < 340_000) {
|
||||
$reward = $reward0;
|
||||
} else {
|
||||
my $shifted = $block - 340_000;
|
||||
# Past the first halving
|
||||
$halvings = 1 + int ($shifted / $interval);
|
||||
if ($shifted % 840_000 == 0) {
|
||||
$reward >>= 2;
|
||||
$fr >>= 2;
|
||||
}
|
||||
}
|
||||
$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;
|
||||
$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;
|
||||
}
|
||||
|
||||
33
contrib/hush_supply_old
Executable file
33
contrib/hush_supply_old
Executable file
@@ -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;
|
||||
}
|
||||
51
qa/rpc-tests/feature_walletfile.py
Executable file
51
qa/rpc-tests/feature_walletfile.py
Executable file
@@ -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()
|
||||
3
src/crypto/bip39/README.md
Normal file
3
src/crypto/bip39/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# trezor-firmware bip39
|
||||
|
||||
Imported from https://github.com/trezor/trezor-firmware/commit/047fcffde1f8530d3aee279b731e5e5f5901590a
|
||||
281
src/crypto/bip39/bip39.c
Normal file
281
src/crypto/bip39/bip39.c
Normal file
@@ -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 <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
52
src/crypto/bip39/bip39.h
Normal file
52
src/crypto/bip39/bip39.h
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
367
src/crypto/bip39/bip39_english.h
Normal file
367
src/crypto/bip39/bip39_english.h
Normal file
@@ -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,
|
||||
};
|
||||
176
src/crypto/bip39/hmac.c
Normal file
176
src/crypto/bip39/hmac.c
Normal file
@@ -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 <string.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
60
src/crypto/bip39/hmac.h
Normal file
60
src/crypto/bip39/hmac.h
Normal file
@@ -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 <stdint.h>
|
||||
#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
|
||||
130
src/crypto/bip39/hmac_drbg.c
Normal file
130
src/crypto/bip39/hmac_drbg.c
Normal file
@@ -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 <string.h>
|
||||
#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);
|
||||
}
|
||||
43
src/crypto/bip39/hmac_drbg.h
Normal file
43
src/crypto/bip39/hmac_drbg.h
Normal file
@@ -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 <sha2.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// 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
|
||||
8
src/crypto/bip39/memzero.h
Normal file
8
src/crypto/bip39/memzero.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __MEMZERO_H__
|
||||
#define __MEMZERO_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void memzero(void* const pnt, const size_t len);
|
||||
|
||||
#endif
|
||||
99
src/crypto/bip39/options.h
Normal file
99
src/crypto/bip39/options.h
Normal file
@@ -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
|
||||
179
src/crypto/bip39/pbkdf2.c
Normal file
179
src/crypto/bip39/pbkdf2.c
Normal file
@@ -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 <string.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/crypto/bip39/pbkdf2.h
Normal file
66
src/crypto/bip39/pbkdf2.h
Normal file
@@ -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 <stdint.h>
|
||||
#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
|
||||
81
src/crypto/bip39/rand.c
Normal file
81
src/crypto/bip39/rand.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
37
src/crypto/bip39/rand.h
Normal file
37
src/crypto/bip39/rand.h
Normal file
@@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
||||
1283
src/crypto/bip39/sha2.c
Normal file
1283
src/crypto/bip39/sha2.c
Normal file
File diff suppressed because it is too large
Load Diff
116
src/crypto/bip39/sha2.h
Normal file
116
src/crypto/bip39/sha2.h
Normal file
@@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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
|
||||
397
src/crypto/bip39/sha3.c
Normal file
397
src/crypto/bip39/sha3.c
Normal file
@@ -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 <rhash.admin@gmail.com>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
89
src/crypto/bip39/sha3.h
Normal file
89
src/crypto/bip39/sha3.h
Normal file
@@ -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 <rhash.admin@gmail.com>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#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__ */
|
||||
21
src/crypto/ctaes/COPYING
Normal file
21
src/crypto/ctaes/COPYING
Normal file
@@ -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.
|
||||
41
src/crypto/ctaes/README.md
Normal file
41
src/crypto/ctaes/README.md
Normal file
@@ -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
|
||||
170
src/crypto/ctaes/bench.c
Normal file
170
src/crypto/ctaes/bench.c
Normal file
@@ -0,0 +1,170 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#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;
|
||||
}
|
||||
556
src/crypto/ctaes/ctaes.c
Normal file
556
src/crypto/ctaes/ctaes.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
41
src/crypto/ctaes/ctaes.h
Normal file
41
src/crypto/ctaes/ctaes.h
Normal file
@@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
||||
110
src/crypto/ctaes/test.c
Normal file
110
src/crypto/ctaes/test.c
Normal file
@@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
}
|
||||
33
src/hushd
33
src/hushd
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) 2019 Hush developers
|
||||
# Copyright (c) 2019-2020 Hush developers
|
||||
|
||||
# set working directory to the location of this script
|
||||
# readlink -f does not always exist
|
||||
@@ -8,31 +8,41 @@ cd $DIR
|
||||
DIR="$( cd "$( dirname "$( readlink "${BASH_SOURCE[0]}" )" )" && pwd )"
|
||||
cd $DIR
|
||||
|
||||
# Chain parameters
|
||||
NAME=HUSH3
|
||||
|
||||
# this corresponds to FR address RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn
|
||||
SCRIPT=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac
|
||||
|
||||
# Chain parameters
|
||||
# First Pure Sapling Zcash Protocol chain!
|
||||
SAPLING=1
|
||||
|
||||
# We use 3 "eras" of different supply curves
|
||||
ERAS=3
|
||||
BLOCKTIME=150
|
||||
# 6250000 - (sprout pool at block 500,000)
|
||||
|
||||
# These values are historical and over-ridden by internals!
|
||||
# Do not change these values, change internals.
|
||||
BLOCKTIME=150 # Hush goes to 75s blocktime at Block 340K
|
||||
REWARD=0,1125000000,562500000
|
||||
HALVING=129,340000,840000
|
||||
PERC=11111111
|
||||
END=128,340000,5422111
|
||||
|
||||
# 6250000 - (Sprout pool at block 500,000)
|
||||
SUPPLY=6178674
|
||||
FOUNDERS=1
|
||||
REWARD=0,1125000000,562500000
|
||||
PERC=11111111
|
||||
HALVING=129,340000,840000
|
||||
# NOTE: keep in sync with komodo_bitcoind.h
|
||||
END=128,340000,5422111
|
||||
CLIENTNAME=GoldenSandtrout
|
||||
NODE1=188.165.212.101 # EU
|
||||
NODE2=64.120.113.130 # AR
|
||||
NODE3=209.58.144.205 # NA
|
||||
NODE4=94.130.35.94 # EU
|
||||
CCLIB=hush3
|
||||
# First Pure Sapling Zcash Protocol chain!
|
||||
SAPLING=1
|
||||
|
||||
# CryptoConditions/Custom Consensus params
|
||||
# CCs will effectively be turned off at Block 340K
|
||||
# since transparent outputs will not be allowed, except
|
||||
# for mining and dpow. CCs can be used on Hush Smart
|
||||
# Chains that do not define ac_private=1
|
||||
FAUCET=228
|
||||
HEIR=234
|
||||
CHANNEL=235
|
||||
@@ -53,7 +63,6 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
$KMD -ac_name=$NAME \
|
||||
-ac_sapling=$SAPLING \
|
||||
-ac_reward=$REWARD \
|
||||
|
||||
@@ -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 )"
|
||||
|
||||
@@ -454,7 +454,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-maxtxfee=<amt>", 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=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
|
||||
strUsage += HelpMessageOpt("-wallet=<file>", _("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=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
|
||||
strUsage += HelpMessageOpt("-whitelistaddress=<Raddress>", _("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)."));
|
||||
|
||||
@@ -1234,52 +1234,83 @@ 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;
|
||||
// LABS fungible chains, cannot have any block reward!
|
||||
if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 )
|
||||
return(0);
|
||||
fprintf(stderr,"%s at height=%d\n",__func__,height);
|
||||
static bool didinit = false, ishush3 = false;
|
||||
|
||||
if (!didinit) {
|
||||
ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||
didinit = true;
|
||||
fprintf(stderr,"%s: didinit ishush3=%d\n", __func__, ishush3);
|
||||
}
|
||||
|
||||
int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0;
|
||||
if ( ASSETCHAINS_FOUNDERS != 0 )
|
||||
{
|
||||
nSubsidy = GetBlockSubsidy(height,Params().GetConsensus());
|
||||
//fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION));
|
||||
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) {
|
||||
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 = 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, 31250000, 15625000, 78125000, 39062500, 19531250, 9765625, // these are exact
|
||||
4882812, 2441406, 1220703, 610351 // these have deviation from ideal BR
|
||||
// Just like BTC, BRs in the far future will be slightly less than
|
||||
// they should be because exact values are not integers, causing
|
||||
// slightly less coins to be actually mined
|
||||
};
|
||||
// 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 = GetArg("-ac_halving2",1680000);
|
||||
}
|
||||
|
||||
// Transition period of 128 blocks has BR=FR=0
|
||||
if (height < TRANSITION) {
|
||||
commission = 0;
|
||||
} else if (height < HALVING1) {
|
||||
commission = starting_commission;
|
||||
} else if (height < HALVING1+1*INTERVAL) {
|
||||
commission = starting_commission / 2;
|
||||
} else if (height < HALVING1+2*INTERVAL) {
|
||||
commission = starting_commission / 4;
|
||||
} else if (height < HALVING1+3*INTERVAL) {
|
||||
commission = starting_commission / 8;
|
||||
} else if (height < HALVING1+4*INTERVAL) {
|
||||
commission = starting_commission / 16;
|
||||
} else if (height < HALVING1+5*INTERVAL) {
|
||||
commission = starting_commission / 32;
|
||||
} else if (height < HALVING1+6*INTERVAL) { // Block 5380000
|
||||
// Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting
|
||||
commission = starting_commission / 64;
|
||||
} else if (height < HALVING1+7*INTERVAL) {
|
||||
// Block reward will be zero before this is ever reached
|
||||
commission = starting_commission / 128; // Block 6220000
|
||||
} else if (height < HALVING1) { // before 1st Halving @ Block 340000 (Nov 2020)
|
||||
commission = commisions[0];
|
||||
} else if (height < HALVING1+1*INTERVAL) { // before 2nd Halving @ Block 2020000
|
||||
commission = commisions[1];
|
||||
} else if (height < HALVING1+2*INTERVAL) { // before 3rd Halving @ Block 3700000
|
||||
commission = commisions[2];
|
||||
} else if (height < HALVING1+3*INTERVAL) { // before 4th Halving @ Block 5380000
|
||||
commission = commisions[3];
|
||||
} else if (height < HALVING1+4*INTERVAL) { // before 5th Halving @ Block 7060000
|
||||
commission = commisions[4];
|
||||
} else if (height < HALVING1+5*INTERVAL) { // before 6th Halving @ Block 8740000
|
||||
commission = commisions[5];
|
||||
} else if (height < HALVING1+6*INTERVAL) { // before 7th Halving @ Block 10420000
|
||||
commission = commisions[6];
|
||||
} else if (height < HALVING1+7*INTERVAL) { // before 8th Halving @ Block 12100000
|
||||
// TODO: Still true??? Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting
|
||||
commission = commisions[7];
|
||||
} else if (height < HALVING1+8*INTERVAL) { // before 9th Halving @ Block 13780000
|
||||
// BR should be zero before this halving happens
|
||||
commission = commisions[8];
|
||||
}
|
||||
// Explicitly set the last block reward
|
||||
// BR_END is the block with the last non-zero block reward, which overrides
|
||||
// the -ac_end param on HUSH3
|
||||
if(height > BR_END) {
|
||||
commission = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1968,20 +1999,21 @@ 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 )
|
||||
{
|
||||
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<scriptlen; i++)
|
||||
|
||||
@@ -1534,24 +1534,44 @@ 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);
|
||||
}
|
||||
|
||||
uint64_t hush_block_subsidy(int nHeight)
|
||||
{
|
||||
uint64_t subsidy=0;
|
||||
//TODO: Cover all halvings until BR=0
|
||||
//if (nHeight >= 3700000) {
|
||||
// subsidy = ASSETCHAINS_REWARD[4];
|
||||
//} else
|
||||
if (nHeight >= 2020000) {
|
||||
subsidy = 140625000;
|
||||
} else if (nHeight >= GetArg("-z2zheight",340000)) {
|
||||
subsidy = 281250000;
|
||||
} else if (nHeight >= 128) {
|
||||
subsidy = 1125000000;
|
||||
}
|
||||
return subsidy;
|
||||
}
|
||||
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 )
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] == 0 ) {
|
||||
fprintf(stderr,"%s: defaulting to 0.0001 subsidy\n",__func__);
|
||||
subsidy = 10000;
|
||||
else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 )
|
||||
{
|
||||
} else if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 ) {
|
||||
// if we have an end block in the first era, find our current era
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 )
|
||||
{
|
||||
@@ -1561,26 +1581,30 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( curEra <= ASSETCHAINS_LASTERA )
|
||||
{
|
||||
int64_t nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0;
|
||||
subsidy = (int64_t)ASSETCHAINS_REWARD[curEra];
|
||||
fprintf(stderr,"%s: nStart.%ld subsidy.%ld curEra.%d\n",__func__,nStart,subsidy,curEra);
|
||||
|
||||
if ( subsidy || (curEra != ASSETCHAINS_LASTERA && ASSETCHAINS_REWARD[curEra + 1] != 0) )
|
||||
{
|
||||
if ( ASSETCHAINS_HALVING[curEra] != 0 )
|
||||
{
|
||||
if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 )
|
||||
{
|
||||
if ( ASSETCHAINS_DECAY[curEra] == 0 )
|
||||
if (ishush3) {
|
||||
subsidy = hush_block_subsidy(nHeight);
|
||||
fprintf(stderr,"%s: HUSH3 subsidy=%ld at height=%d\n",__func__,subsidy,nHeight);
|
||||
} else if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) {
|
||||
// The code below is not compatible with HUSH3 mainnet
|
||||
if ( ASSETCHAINS_DECAY[curEra] == 0 ) {
|
||||
subsidy >>= numhalvings;
|
||||
else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 )
|
||||
{
|
||||
fprintf(stderr,"%s: no decay, numhalvings.%d curEra.%d subsidy.%ld nStart.%ld\n",__func__, numhalvings, curEra, subsidy, nStart);
|
||||
} else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 ) {
|
||||
if ( curEra == ASSETCHAINS_LASTERA )
|
||||
{
|
||||
subsidyDifference = subsidy;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Ex: -ac_eras=3 -ac_reward=0,384,24 -ac_end=1440,260640,0 -ac_halving=1,1440,2103840 -ac_decay 100000000,97750000,0
|
||||
subsidyDifference = subsidy - ASSETCHAINS_REWARD[curEra + 1];
|
||||
if (subsidyDifference < 0)
|
||||
@@ -1592,13 +1616,10 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
|
||||
denominator = ASSETCHAINS_ENDSUBSIDY[curEra] - nStart;
|
||||
numerator = denominator - ((ASSETCHAINS_ENDSUBSIDY[curEra] - nHeight) + ((nHeight - nStart) % ASSETCHAINS_HALVING[curEra]));
|
||||
subsidy = subsidy - sign * ((subsidyDifference * numerator) / denominator);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings )
|
||||
} else {
|
||||
if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings ) {
|
||||
subsidy = cached_subsidy;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
for (int i=0; i < numhalvings && subsidy != 0; i++)
|
||||
subsidy = (subsidy * ASSETCHAINS_DECAY[curEra]) / 100000000;
|
||||
cached_subsidy = subsidy;
|
||||
@@ -1609,28 +1630,27 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"%s: curEra.%d > lastEra.%lu\n", __func__, curEra, ASSETCHAINS_LASTERA);
|
||||
}
|
||||
}
|
||||
uint32_t magicExtra = ASSETCHAINS_STAKED ? ASSETCHAINS_MAGIC : (ASSETCHAINS_MAGIC & 0xffffff);
|
||||
if ( ASSETCHAINS_SUPPLY > 10000000000 ) // over 10 billion?
|
||||
{
|
||||
fprintf(stderr,"%s: Detected supply over 10 billion, danger zone!\n",__func__);
|
||||
if ( nHeight <= ASSETCHAINS_SUPPLY/1000000000 )
|
||||
{
|
||||
subsidy += (uint64_t)1000000000 * COIN;
|
||||
if ( nHeight == 1 )
|
||||
subsidy += (ASSETCHAINS_SUPPLY % 1000000000)*COIN + magicExtra;
|
||||
}
|
||||
}
|
||||
else if ( nHeight == 1 )
|
||||
{
|
||||
} else if ( nHeight == 1 ) {
|
||||
if ( ASSETCHAINS_LASTERA == 0 )
|
||||
subsidy = ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra;
|
||||
else
|
||||
subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + magicExtra;
|
||||
}
|
||||
else if ( is_STAKED(ASSETCHAINS_SYMBOL) == 2 )
|
||||
return(0);
|
||||
// LABS fungible chains, cannot have any block reward!
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1798,6 +1818,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=%lu maxEras=%d\n", __func__, ASSETCHAINS_LASTERA, ASSETCHAINS_MAX_ERAS);
|
||||
|
||||
ASSETCHAINS_TIMELOCKGTE = (uint64_t)GetArg("-ac_timelockgte", _ASSETCHAINS_TIMELOCKOFF);
|
||||
ASSETCHAINS_TIMEUNLOCKFROM = GetArg("-ac_timeunlockfrom", 0);
|
||||
@@ -1805,13 +1826,33 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_TIMEUNLOCKFROM > ASSETCHAINS_TIMEUNLOCKTO )
|
||||
{
|
||||
printf("ASSETCHAINS_TIMELOCKGTE - must specify valid ac_timeunlockfrom and ac_timeunlockto\n");
|
||||
ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
|
||||
ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
|
||||
ASSETCHAINS_TIMEUNLOCKFROM = ASSETCHAINS_TIMEUNLOCKTO = 0;
|
||||
}
|
||||
|
||||
Split(GetArg("-ac_end",""), sizeof(ASSETCHAINS_ENDSUBSIDY)/sizeof(*ASSETCHAINS_ENDSUBSIDY), ASSETCHAINS_ENDSUBSIDY, 0);
|
||||
Split(GetArg("-ac_reward",""), sizeof(ASSETCHAINS_REWARD)/sizeof(*ASSETCHAINS_REWARD), ASSETCHAINS_REWARD, 0);
|
||||
Split(GetArg("-ac_halving",""), sizeof(ASSETCHAINS_HALVING)/sizeof(*ASSETCHAINS_HALVING), ASSETCHAINS_HALVING, 0);
|
||||
Split(GetArg("-ac_reward",""), sizeof(ASSETCHAINS_REWARD)/sizeof(*ASSETCHAINS_REWARD), ASSETCHAINS_REWARD, 0);
|
||||
|
||||
bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false;
|
||||
|
||||
if(ishush3) {
|
||||
fprintf(stderr,"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_ENDSUBSIDY[0] = 129;
|
||||
ASSETCHAINS_ENDSUBSIDY[1] = GetArg("-z2zheight",340000);
|
||||
ASSETCHAINS_ENDSUBSIDY[2] = 2*5422111; // TODO: Fix this, twice the previous end of rewards is an estimate
|
||||
// TODO: fill in all possible values for each halving/reward interval
|
||||
// based on simple halving schedule
|
||||
}
|
||||
Split(GetArg("-ac_decay",""), sizeof(ASSETCHAINS_DECAY)/sizeof(*ASSETCHAINS_DECAY), ASSETCHAINS_DECAY, 0);
|
||||
Split(GetArg("-ac_notarypay",""), sizeof(ASSETCHAINS_NOTARY_PAY)/sizeof(*ASSETCHAINS_NOTARY_PAY), ASSETCHAINS_NOTARY_PAY, 0);
|
||||
|
||||
|
||||
39
src/main.cpp
39
src/main.cpp
@@ -2406,45 +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));
|
||||
}
|
||||
/*
|
||||
// Mining slow start
|
||||
// The subsidy is ramped up linearly, skipping the middle payout of
|
||||
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
|
||||
if (nHeight < consensusParams.nSubsidySlowStartInterval / 2) {
|
||||
nSubsidy /= consensusParams.nSubsidySlowStartInterval;
|
||||
nSubsidy *= nHeight;
|
||||
return nSubsidy;
|
||||
} else if (nHeight < consensusParams.nSubsidySlowStartInterval) {
|
||||
nSubsidy /= consensusParams.nSubsidySlowStartInterval;
|
||||
nSubsidy *= (nHeight+1);
|
||||
return nSubsidy;
|
||||
}
|
||||
|
||||
assert(nHeight > consensusParams.SubsidySlowStartShift());
|
||||
int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;*/
|
||||
// Force block reward to zero when right shift is undefined.
|
||||
//int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
|
||||
//if (halvings >= 64)
|
||||
// return 0;
|
||||
|
||||
// Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years.
|
||||
//nSubsidy >>= halvings;
|
||||
//return nSubsidy;
|
||||
return komodo_ac_block_subsidy(nHeight);
|
||||
}
|
||||
|
||||
bool IsInitialBlockDownload()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -59,6 +59,7 @@ using namespace libzcash;
|
||||
/**
|
||||
* Settings
|
||||
*/
|
||||
const char * DEFAULT_WALLET_DAT = "wallet.dat";
|
||||
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
|
||||
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
||||
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
|
||||
@@ -668,6 +669,25 @@ void CWallet::Flush(bool shutdown)
|
||||
|
||||
bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString)
|
||||
{
|
||||
LogPrintf("Using wallet %s\n", walletFile);
|
||||
uiInterface.InitMessage(_("Verifying wallet..."));
|
||||
|
||||
if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) {
|
||||
boost::filesystem::path path(walletFile);
|
||||
if (path.is_absolute()) {
|
||||
if (!boost::filesystem::exists(path.parent_path())) {
|
||||
LogPrintf("Absolute path %s does not exist!", walletFile);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
boost::filesystem::path full_path = GetDataDir() / path;
|
||||
if (!boost::filesystem::exists(full_path.parent_path())) {
|
||||
LogPrintf("Relative path %s does not exist!", walletFile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitdb.Open(GetDataDir()))
|
||||
{
|
||||
// try moving the database env out of the way
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user