From 5412da7d715160259381481246163a2663c90ff9 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Wed, 9 Sep 2020 11:42:52 -0400 Subject: [PATCH 01/17] Connect z_listreceivedaddress to the outside world --- src/rpc/client.cpp | 10 +++++----- src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + src/wallet/rpchushwallet.cpp | 7 +++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 4f11a476f..a3e04623a 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -169,11 +169,11 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_listsentbyaddress", 3}, { "z_listsentbyaddress", 4}, { "z_listsentbyaddress", 5}, - { "z_listreceivedbyaddress", 1}, - { "z_listreceivedbyaddress", 2}, - { "z_listreceivedbyaddress", 3}, - { "z_listreceivedbyaddress", 4}, - { "z_listreceivedbyaddress", 5}, + { "z_listreceivedaddress", 1}, + { "z_listreceivedaddress", 2}, + { "z_listreceivedaddress", 3}, + { "z_listreceivedaddress", 4}, + { "z_listreceivedaddress", 5}, // crosschain { "assetchainproof", 1}, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 56c038596..16b25ae81 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -652,6 +652,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, { "wallet", "z_listreceivedbyaddress",&z_listreceivedbyaddress,false }, + { "wallet", "z_listreceivedaddress", &z_listreceivedaddress, false }, { "wallet", "z_getbalance", &z_getbalance, false }, { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, { "wallet", "z_mergetoaddress", &z_mergetoaddress, false }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 6568977d7..15c982d81 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -480,6 +480,7 @@ extern UniValue z_listnullifiers(const UniValue& params, bool fHelp, const CPubK extern UniValue z_exportwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp extern UniValue z_importwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdump.cpp extern UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp +extern UniValue z_listreceivedaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_getbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp diff --git a/src/wallet/rpchushwallet.cpp b/src/wallet/rpchushwallet.cpp index 64cd0e4a5..5fd77cc97 100644 --- a/src/wallet/rpchushwallet.cpp +++ b/src/wallet/rpchushwallet.cpp @@ -134,6 +134,9 @@ void zsTxSpendsToJSON(const CWalletTx& wtx, UniValue& spends, CAmount& totalSpen void zsTxReceivedToJSON(const CWalletTx& wtx, UniValue& received, CAmount& totalReceived, const std::string& strAddress, bool filterByAddress) { + if(fZdebug) + fprintf(stderr,"%s: txid=%s\n", __func__, wtx.GetHash().ToString().c_str() ); + LOCK2(cs_main, pwalletMain->cs_wallet); //Check address @@ -401,6 +404,10 @@ void zsWalletTxJSON(const CWalletTx& wtx, UniValue& ret, const std::string strAd //Begin Compiling the Decrypted Transaction tx.push_back(Pair("txid", wtx.GetHash().ToString())); + + if(fZdebug) + fprintf(stderr,"%s: txid=%s\n", __func__, wtx.GetHash().ToString().c_str() ); + if (wtx.IsCoinBase()) { tx.push_back(Pair("coinbase", true)); From fc9725ca4421bfc8c395d6959585653aa2ace3e5 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Wed, 9 Sep 2020 11:45:23 -0400 Subject: [PATCH 02/17] Fix docs --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a2fa34b3b..130394413 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3352,8 +3352,8 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey& if (fHelp || params.size() > 5 || params.size() == 3) throw runtime_error( - "z_listreceivedbyaddress\n" - "\nReturns received outputs for a single address.\n" + "z_listreceivedaddress\n" + "\nReturns received outputs.\n" "\n" "This function only returns information on addresses with full spending keys." "\n" From 0614f51f286a899a87b3ce1b53988ec45853e988 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Wed, 9 Sep 2020 11:51:59 -0400 Subject: [PATCH 03/17] Fix more docs bugs --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 130394413..19157432b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3411,8 +3411,8 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey& " }],\n" " },\n" "\nExamples:\n" - + HelpExampleCli("z_listreceivedbyaddress", "R...") - + HelpExampleRpc("z_listreceivedbyaddress", "R...") + + HelpExampleCli("z_listreceivedaddress", "\"*\"") + + HelpExampleRpc("z_listreceivedaddress", "RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn") ); LOCK2(cs_main, pwalletMain->cs_wallet); From 032c7cbb9f8d31f19ff002a5ce0f8cc49616782e Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Wed, 9 Sep 2020 12:58:53 -0400 Subject: [PATCH 04/17] Add transaction time to z_listreceivedbyaddress which drastically speeds up SD operations --- src/wallet/rpcwallet.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 19157432b..3b6361fe3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4086,7 +4086,8 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK " \"txid\": xxxxx, (string) the transaction id\n" " \"amount\": xxxxx, (numeric) the amount of value in the note\n" " \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n" - " \"confirmations\" : n, (numeric) the number of confirmations\n" + " \"confirmations\" : n, (numeric) the number of notarized confirmations (dpowconfs)\n" + " \"rawconfirmations\" : n, (numeric) the number of raw confirmations\n" " \"outindex\" (sapling) : n, (numeric) the output index\n" " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n" "}\n" @@ -4131,7 +4132,6 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK if (boost::get(&zaddr) != nullptr) { for (SaplingNoteEntry & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); - int nHeight = tx_height(entry.op.hash); int dpowconfs = komodo_dpowconfs(nHeight, entry.confirmations); // Only return notarized results when minconf>1 @@ -4152,6 +4152,10 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK } obj.push_back(Pair("outindex", (int)entry.op.n)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); + auto wtx = pwalletMain->mapWallet.at(entry.op.hash); //.ToString()); + //fprintf(stderr,"%s: txid=%s not found in wallet!\n", __func__, entry.op.hash.ToString().c_str()); + obj.push_back(Pair("time", wtx.GetTxTime())); + obj.push_back(Pair("confirmations", dpowconfs)); if (hasSpendingKey) { obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op))); From 5d08cd7b577f0322776fe90793c4b5f313f1ef7b Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Fri, 11 Sep 2020 07:23:37 -0400 Subject: [PATCH 05/17] Refactor Hush supply curve into a dedicated function and increase logspam --- src/komodo_bitcoind.h | 133 +++++++++++++++++++++++------------------- src/komodo_utils.h | 4 ++ 2 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 50973ef03..ff37a4847 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1238,6 +1238,70 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); // 10% of all block rewards go towards Hush core team // If you do not like this, you are encouraged to fork the chain // or start your own Hush Smart Chain: https://github.com/myhush/hush-smart-chains +// HUSH supply curve cannot be exactly represented via KMD AC CLI args, so we do it ourselves. +// You specify the BR, and the FR % gets added so 10% of 12.5 is 1.25 +// but to tell the AC params, I need to say "11% of 11.25" is 1.25 +// 11% ie. 1/9th cannot be exactly represented and so the FR has tiny amounts of error unless done manually +// Do not change this code unless you really know what you are doing. +// Here Be Dragons! -- Duke Leto +uint64_t hush_commission(int height) +{ + // 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 + }; + uint64_t commission = 0; + + 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); + fprintf(stderr,"%s: height=%d increasing interval to %d\n", __func__, height, INTERVAL); + } + + // Transition period of 128 blocks has BR=FR=0 + if (height < TRANSITION) { + commission = 0; + } else if (height < HALVING1) { // before 1st Halving @ Block 340000 (Nov 2020) + commission = commisions[0]; + } else if (height < HALVING1+1*INTERVAL) { // before 2nd Halving @ Block 2020000 + commission = commisions[1]; + } else if (height < HALVING1+2*INTERVAL) { // before 3rd Halving @ Block 3700000 + commission = commisions[2]; + } else if (height < HALVING1+3*INTERVAL) { // before 4th Halving @ Block 5380000 + commission = commisions[3]; + } else if (height < HALVING1+4*INTERVAL) { // before 5th Halving @ Block 7060000 + commission = commisions[4]; + } else if (height < HALVING1+5*INTERVAL) { // before 6th Halving @ Block 8740000 + commission = commisions[5]; + } else if (height < HALVING1+6*INTERVAL) { // before 7th Halving @ Block 10420000 + commission = commisions[6]; + } else if (height < HALVING1+7*INTERVAL) { // before 8th Halving @ Block 12100000 + // TODO: Still true??? Block reward will go to zero between 7th+8th halvings, ac_end may need adjusting + commission = commisions[7]; + } else if (height < HALVING1+8*INTERVAL) { // before 9th Halving @ Block 13780000 + // BR should be zero before this halving happens + commission = commisions[8]; + } + // Explicitly set the last block reward + // BR_END is the block with the last non-zero block reward, which overrides + // the -ac_end param on HUSH3 + if(height > BR_END) { + fprintf(stderr,"%s: HUSH block reward has gone to zero at height %d!!! It was a good run folks\n", __func__, height); + commission = 0; + } + fprintf(stderr,"%s: commission=%lu,interval=%d at height %d\n", __func__, commission, INTERVAL, height); + return commission; +} + uint64_t komodo_commission(const CBlock *pblock,int32_t height) { fprintf(stderr,"%s at height=%d\n",__func__,height); @@ -1256,78 +1320,25 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); commission = ((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); - // Do not change this code unless you really know what you are doing. - // Here Be Dragons! -- Duke Leto if (ishush3) { - // TODO: Calculate new BR_END based on 75s block time!!! 2X old BR_END is a rough estimate, not exact! - int32_t starting_commission = 125000000, HALVING1 = GetArg("-z2zheight",340000), - INTERVAL = 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) { // 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; - } + commission = hush_commission(height); } if ( ASSETCHAINS_FOUNDERS > 1 ) { if ( (height % ASSETCHAINS_FOUNDERS) == 0 ) { - if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) + if ( ASSETCHAINS_FOUNDERS_REWARD == 0 ) { commission = commission * ASSETCHAINS_FOUNDERS; - else + } else { commission = ASSETCHAINS_FOUNDERS_REWARD; + } + fprintf(stderr,"%s: set commission=%lu at height %d with\n",__func__,commission, height); + } else { + commission = 0; } - else commission = 0; } - } - else if ( pblock != 0 ) - { + } else if ( pblock != 0 ) { txn_count = pblock->vtx.size(); for (i=0; i Date: Fri, 11 Sep 2020 10:27:14 -0400 Subject: [PATCH 06/17] bip39 updates + tweaks --- src/crypto/bip39/bip39.c | 2 + src/crypto/bip39/bip39.h | 14 +- src/crypto/bip39/bip39_english.h | 2393 +++++++++++++++++++++++++----- src/crypto/bip39/hmac.h | 32 +- src/crypto/bip39/memzero.h | 2 +- src/crypto/bip39/options.h | 2 +- src/crypto/bip39/pbkdf2.h | 42 +- 7 files changed, 2085 insertions(+), 402 deletions(-) diff --git a/src/crypto/bip39/bip39.c b/src/crypto/bip39/bip39.c index 33455f6c5..76e0792ad 100644 --- a/src/crypto/bip39/bip39.c +++ b/src/crypto/bip39/bip39.c @@ -35,6 +35,8 @@ #if USE_BIP39_CACHE +int BIP39_WORDS = 2048; + static int bip39_cache_index = 0; static CONFIDENTIAL struct { diff --git a/src/crypto/bip39/bip39.h b/src/crypto/bip39/bip39.h index 07fb21bb2..ac76101d7 100644 --- a/src/crypto/bip39/bip39.h +++ b/src/crypto/bip39/bip39.h @@ -24,13 +24,11 @@ #ifndef __BIP39_H__ #define __BIP39_H__ -#include #include -#define BIP39_WORDS 2048 #define BIP39_PBKDF2_ROUNDS 2048 -const char *mnemonic_generate(int strength); // strength in bits +const char *mnemonic_generate(int strength); // strength in bits const char *mnemonic_from_data(const uint8_t *data, int len); void mnemonic_clear(void); @@ -39,14 +37,8 @@ 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)); +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); +const char * const *mnemonic_wordlist(void); #endif diff --git a/src/crypto/bip39/bip39_english.h b/src/crypto/bip39/bip39_english.h index c57fca365..77607ba7f 100644 --- a/src/crypto/bip39/bip39_english.h +++ b/src/crypto/bip39/bip39_english.h @@ -21,347 +21,2054 @@ * 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, +static const char * const wordlist[] = { +"abandon", +"ability", +"able", +"about", +"above", +"absent", +"absorb", +"abstract", +"absurd", +"abuse", +"access", +"accident", +"account", +"accuse", +"achieve", +"acid", +"acoustic", +"acquire", +"across", +"act", +"action", +"actor", +"actress", +"actual", +"adapt", +"add", +"addict", +"address", +"adjust", +"admit", +"adult", +"advance", +"advice", +"aerobic", +"affair", +"afford", +"afraid", +"again", +"age", +"agent", +"agree", +"ahead", +"aim", +"air", +"airport", +"aisle", +"alarm", +"album", +"alcohol", +"alert", +"alien", +"all", +"alley", +"allow", +"almost", +"alone", +"alpha", +"already", +"also", +"alter", +"always", +"amateur", +"amazing", +"among", +"amount", +"amused", +"analyst", +"anchor", +"ancient", +"anger", +"angle", +"angry", +"animal", +"ankle", +"announce", +"annual", +"another", +"answer", +"antenna", +"antique", +"anxiety", +"any", +"apart", +"apology", +"appear", +"apple", +"approve", +"april", +"arch", +"arctic", +"area", +"arena", +"argue", +"arm", +"armed", +"armor", +"army", +"around", +"arrange", +"arrest", +"arrive", +"arrow", +"art", +"artefact", +"artist", +"artwork", +"ask", +"aspect", +"assault", +"asset", +"assist", +"assume", +"asthma", +"athlete", +"atom", +"attack", +"attend", +"attitude", +"attract", +"auction", +"audit", +"august", +"aunt", +"author", +"auto", +"autumn", +"average", +"avocado", +"avoid", +"awake", +"aware", +"away", +"awesome", +"awful", +"awkward", +"axis", +"baby", +"bachelor", +"bacon", +"badge", +"bag", +"balance", +"balcony", +"ball", +"bamboo", +"banana", +"banner", +"bar", +"barely", +"bargain", +"barrel", +"base", +"basic", +"basket", +"battle", +"beach", +"bean", +"beauty", +"because", +"become", +"beef", +"before", +"begin", +"behave", +"behind", +"believe", +"below", +"belt", +"bench", +"benefit", +"best", +"betray", +"better", +"between", +"beyond", +"bicycle", +"bid", +"bike", +"bind", +"biology", +"bird", +"birth", +"bitter", +"black", +"blade", +"blame", +"blanket", +"blast", +"bleak", +"bless", +"blind", +"blood", +"blossom", +"blouse", +"blue", +"blur", +"blush", +"board", +"boat", +"body", +"boil", +"bomb", +"bone", +"bonus", +"book", +"boost", +"border", +"boring", +"borrow", +"boss", +"bottom", +"bounce", +"box", +"boy", +"bracket", +"brain", +"brand", +"brass", +"brave", +"bread", +"breeze", +"brick", +"bridge", +"brief", +"bright", +"bring", +"brisk", +"broccoli", +"broken", +"bronze", +"broom", +"brother", +"brown", +"brush", +"bubble", +"buddy", +"budget", +"buffalo", +"build", +"bulb", +"bulk", +"bullet", +"bundle", +"bunker", +"burden", +"burger", +"burst", +"bus", +"business", +"busy", +"butter", +"buyer", +"buzz", +"cabbage", +"cabin", +"cable", +"cactus", +"cage", +"cake", +"call", +"calm", +"camera", +"camp", +"can", +"canal", +"cancel", +"candy", +"cannon", +"canoe", +"canvas", +"canyon", +"capable", +"capital", +"captain", +"car", +"carbon", +"card", +"cargo", +"carpet", +"carry", +"cart", +"case", +"cash", +"casino", +"castle", +"casual", +"cat", +"catalog", +"catch", +"category", +"cattle", +"caught", +"cause", +"caution", +"cave", +"ceiling", +"celery", +"cement", +"census", +"century", +"cereal", +"certain", +"chair", +"chalk", +"champion", +"change", +"chaos", +"chapter", +"charge", +"chase", +"chat", +"cheap", +"check", +"cheese", +"chef", +"cherry", +"chest", +"chicken", +"chief", +"child", +"chimney", +"choice", +"choose", +"chronic", +"chuckle", +"chunk", +"churn", +"cigar", +"cinnamon", +"circle", +"citizen", +"city", +"civil", +"claim", +"clap", +"clarify", +"claw", +"clay", +"clean", +"clerk", +"clever", +"click", +"client", +"cliff", +"climb", +"clinic", +"clip", +"clock", +"clog", +"close", +"cloth", +"cloud", +"clown", +"club", +"clump", +"cluster", +"clutch", +"coach", +"coast", +"coconut", +"code", +"coffee", +"coil", +"coin", +"collect", +"color", +"column", +"combine", +"come", +"comfort", +"comic", +"common", +"company", +"concert", +"conduct", +"confirm", +"congress", +"connect", +"consider", +"control", +"convince", +"cook", +"cool", +"copper", +"copy", +"coral", +"core", +"corn", +"correct", +"cost", +"cotton", +"couch", +"country", +"couple", +"course", +"cousin", +"cover", +"coyote", +"crack", +"cradle", +"craft", +"cram", +"crane", +"crash", +"crater", +"crawl", +"crazy", +"cream", +"credit", +"creek", +"crew", +"cricket", +"crime", +"crisp", +"critic", +"crop", +"cross", +"crouch", +"crowd", +"crucial", +"cruel", +"cruise", +"crumble", +"crunch", +"crush", +"cry", +"crystal", +"cube", +"culture", +"cup", +"cupboard", +"curious", +"current", +"curtain", +"curve", +"cushion", +"custom", +"cute", +"cycle", +"dad", +"damage", +"damp", +"dance", +"danger", +"daring", +"dash", +"daughter", +"dawn", +"day", +"deal", +"debate", +"debris", +"decade", +"december", +"decide", +"decline", +"decorate", +"decrease", +"deer", +"defense", +"define", +"defy", +"degree", +"delay", +"deliver", +"demand", +"demise", +"denial", +"dentist", +"deny", +"depart", +"depend", +"deposit", +"depth", +"deputy", +"derive", +"describe", +"desert", +"design", +"desk", +"despair", +"destroy", +"detail", +"detect", +"develop", +"device", +"devote", +"diagram", +"dial", +"diamond", +"diary", +"dice", +"diesel", +"diet", +"differ", +"digital", +"dignity", +"dilemma", +"dinner", +"dinosaur", +"direct", +"dirt", +"disagree", +"discover", +"disease", +"dish", +"dismiss", +"disorder", +"display", +"distance", +"divert", +"divide", +"divorce", +"dizzy", +"doctor", +"document", +"dog", +"doll", +"dolphin", +"domain", +"donate", +"donkey", +"donor", +"door", +"dose", +"double", +"dove", +"draft", +"dragon", +"drama", +"drastic", +"draw", +"dream", +"dress", +"drift", +"drill", +"drink", +"drip", +"drive", +"drop", +"drum", +"dry", +"duck", +"dumb", +"dune", +"during", +"dust", +"dutch", +"duty", +"dwarf", +"dynamic", +"eager", +"eagle", +"early", +"earn", +"earth", +"easily", +"east", +"easy", +"echo", +"ecology", +"economy", +"edge", +"edit", +"educate", +"effort", +"egg", +"eight", +"either", +"elbow", +"elder", +"electric", +"elegant", +"element", +"elephant", +"elevator", +"elite", +"else", +"embark", +"embody", +"embrace", +"emerge", +"emotion", +"employ", +"empower", +"empty", +"enable", +"enact", +"end", +"endless", +"endorse", +"enemy", +"energy", +"enforce", +"engage", +"engine", +"enhance", +"enjoy", +"enlist", +"enough", +"enrich", +"enroll", +"ensure", +"enter", +"entire", +"entry", +"envelope", +"episode", +"equal", +"equip", +"era", +"erase", +"erode", +"erosion", +"error", +"erupt", +"escape", +"essay", +"essence", +"estate", +"eternal", +"ethics", +"evidence", +"evil", +"evoke", +"evolve", +"exact", +"example", +"excess", +"exchange", +"excite", +"exclude", +"excuse", +"execute", +"exercise", +"exhaust", +"exhibit", +"exile", +"exist", +"exit", +"exotic", +"expand", +"expect", +"expire", +"explain", +"expose", +"express", +"extend", +"extra", +"eye", +"eyebrow", +"fabric", +"face", +"faculty", +"fade", +"faint", +"faith", +"fall", +"false", +"fame", +"family", +"famous", +"fan", +"fancy", +"fantasy", +"farm", +"fashion", +"fat", +"fatal", +"father", +"fatigue", +"fault", +"favorite", +"feature", +"february", +"federal", +"fee", +"feed", +"feel", +"female", +"fence", +"festival", +"fetch", +"fever", +"few", +"fiber", +"fiction", +"field", +"figure", +"file", +"film", +"filter", +"final", +"find", +"fine", +"finger", +"finish", +"fire", +"firm", +"first", +"fiscal", +"fish", +"fit", +"fitness", +"fix", +"flag", +"flame", +"flash", +"flat", +"flavor", +"flee", +"flight", +"flip", +"float", +"flock", +"floor", +"flower", +"fluid", +"flush", +"fly", +"foam", +"focus", +"fog", +"foil", +"fold", +"follow", +"food", +"foot", +"force", +"forest", +"forget", +"fork", +"fortune", +"forum", +"forward", +"fossil", +"foster", +"found", +"fox", +"fragile", +"frame", +"frequent", +"fresh", +"friend", +"fringe", +"frog", +"front", +"frost", +"frown", +"frozen", +"fruit", +"fuel", +"fun", +"funny", +"furnace", +"fury", +"future", +"gadget", +"gain", +"galaxy", +"gallery", +"game", +"gap", +"garage", +"garbage", +"garden", +"garlic", +"garment", +"gas", +"gasp", +"gate", +"gather", +"gauge", +"gaze", +"general", +"genius", +"genre", +"gentle", +"genuine", +"gesture", +"ghost", +"giant", +"gift", +"giggle", +"ginger", +"giraffe", +"girl", +"give", +"glad", +"glance", +"glare", +"glass", +"glide", +"glimpse", +"globe", +"gloom", +"glory", +"glove", +"glow", +"glue", +"goat", +"goddess", +"gold", +"good", +"goose", +"gorilla", +"gospel", +"gossip", +"govern", +"gown", +"grab", +"grace", +"grain", +"grant", +"grape", +"grass", +"gravity", +"great", +"green", +"grid", +"grief", +"grit", +"grocery", +"group", +"grow", +"grunt", +"guard", +"guess", +"guide", +"guilt", +"guitar", +"gun", +"gym", +"habit", +"hair", +"half", +"hammer", +"hamster", +"hand", +"happy", +"harbor", +"hard", +"harsh", +"harvest", +"hat", +"have", +"hawk", +"hazard", +"head", +"health", +"heart", +"heavy", +"hedgehog", +"height", +"hello", +"helmet", +"help", +"hen", +"hero", +"hidden", +"high", +"hill", +"hint", +"hip", +"hire", +"history", +"hobby", +"hockey", +"hold", +"hole", +"holiday", +"hollow", +"home", +"honey", +"hood", +"hope", +"horn", +"horror", +"horse", +"hospital", +"host", +"hotel", +"hour", +"hover", +"hub", +"huge", +"human", +"humble", +"humor", +"hundred", +"hungry", +"hunt", +"hurdle", +"hurry", +"hurt", +"husband", +"hybrid", +"ice", +"icon", +"idea", +"identify", +"idle", +"ignore", +"ill", +"illegal", +"illness", +"image", +"imitate", +"immense", +"immune", +"impact", +"impose", +"improve", +"impulse", +"inch", +"include", +"income", +"increase", +"index", +"indicate", +"indoor", +"industry", +"infant", +"inflict", +"inform", +"inhale", +"inherit", +"initial", +"inject", +"injury", +"inmate", +"inner", +"innocent", +"input", +"inquiry", +"insane", +"insect", +"inside", +"inspire", +"install", +"intact", +"interest", +"into", +"invest", +"invite", +"involve", +"iron", +"island", +"isolate", +"issue", +"item", +"ivory", +"jacket", +"jaguar", +"jar", +"jazz", +"jealous", +"jeans", +"jelly", +"jewel", +"job", +"join", +"joke", +"journey", +"joy", +"judge", +"juice", +"jump", +"jungle", +"junior", +"junk", +"just", +"kangaroo", +"keen", +"keep", +"ketchup", +"key", +"kick", +"kid", +"kidney", +"kind", +"kingdom", +"kiss", +"kit", +"kitchen", +"kite", +"kitten", +"kiwi", +"knee", +"knife", +"knock", +"know", +"lab", +"label", +"labor", +"ladder", +"lady", +"lake", +"lamp", +"language", +"laptop", +"large", +"later", +"latin", +"laugh", +"laundry", +"lava", +"law", +"lawn", +"lawsuit", +"layer", +"lazy", +"leader", +"leaf", +"learn", +"leave", +"lecture", +"left", +"leg", +"legal", +"legend", +"leisure", +"lemon", +"lend", +"length", +"lens", +"leopard", +"lesson", +"letter", +"level", +"liar", +"liberty", +"library", +"license", +"life", +"lift", +"light", +"like", +"limb", +"limit", +"link", +"lion", +"liquid", +"list", +"little", +"live", +"lizard", +"load", +"loan", +"lobster", +"local", +"lock", +"logic", +"lonely", +"long", +"loop", +"lottery", +"loud", +"lounge", +"love", +"loyal", +"lucky", +"luggage", +"lumber", +"lunar", +"lunch", +"luxury", +"lyrics", +"machine", +"mad", +"magic", +"magnet", +"maid", +"mail", +"main", +"major", +"make", +"mammal", +"man", +"manage", +"mandate", +"mango", +"mansion", +"manual", +"maple", +"marble", +"march", +"margin", +"marine", +"market", +"marriage", +"mask", +"mass", +"master", +"match", +"material", +"math", +"matrix", +"matter", +"maximum", +"maze", +"meadow", +"mean", +"measure", +"meat", +"mechanic", +"medal", +"media", +"melody", +"melt", +"member", +"memory", +"mention", +"menu", +"mercy", +"merge", +"merit", +"merry", +"mesh", +"message", +"metal", +"method", +"middle", +"midnight", +"milk", +"million", +"mimic", +"mind", +"minimum", +"minor", +"minute", +"miracle", +"mirror", +"misery", +"miss", +"mistake", +"mix", +"mixed", +"mixture", +"mobile", +"model", +"modify", +"mom", +"moment", +"monitor", +"monkey", +"monster", +"month", +"moon", +"moral", +"more", +"morning", +"mosquito", +"mother", +"motion", +"motor", +"mountain", +"mouse", +"move", +"movie", +"much", +"muffin", +"mule", +"multiply", +"muscle", +"museum", +"mushroom", +"music", +"must", +"mutual", +"myself", +"mystery", +"myth", +"naive", +"name", +"napkin", +"narrow", +"nasty", +"nation", +"nature", +"near", +"neck", +"need", +"negative", +"neglect", +"neither", +"nephew", +"nerve", +"nest", +"net", +"network", +"neutral", +"never", +"news", +"next", +"nice", +"night", +"noble", +"noise", +"nominee", +"noodle", +"normal", +"north", +"nose", +"notable", +"note", +"nothing", +"notice", +"novel", +"now", +"nuclear", +"number", +"nurse", +"nut", +"oak", +"obey", +"object", +"oblige", +"obscure", +"observe", +"obtain", +"obvious", +"occur", +"ocean", +"october", +"odor", +"off", +"offer", +"office", +"often", +"oil", +"okay", +"old", +"olive", +"olympic", +"omit", +"once", +"one", +"onion", +"online", +"only", +"open", +"opera", +"opinion", +"oppose", +"option", +"orange", +"orbit", +"orchard", +"order", +"ordinary", +"organ", +"orient", +"original", +"orphan", +"ostrich", +"other", +"outdoor", +"outer", +"output", +"outside", +"oval", +"oven", +"over", +"own", +"owner", +"oxygen", +"oyster", +"ozone", +"pact", +"paddle", +"page", +"pair", +"palace", +"palm", +"panda", +"panel", +"panic", +"panther", +"paper", +"parade", +"parent", +"park", +"parrot", +"party", +"pass", +"patch", +"path", +"patient", +"patrol", +"pattern", +"pause", +"pave", +"payment", +"peace", +"peanut", +"pear", +"peasant", +"pelican", +"pen", +"penalty", +"pencil", +"people", +"pepper", +"perfect", +"permit", +"person", +"pet", +"phone", +"photo", +"phrase", +"physical", +"piano", +"picnic", +"picture", +"piece", +"pig", +"pigeon", +"pill", +"pilot", +"pink", +"pioneer", +"pipe", +"pistol", +"pitch", +"pizza", +"place", +"planet", +"plastic", +"plate", +"play", +"please", +"pledge", +"pluck", +"plug", +"plunge", +"poem", +"poet", +"point", +"polar", +"pole", +"police", +"pond", +"pony", +"pool", +"popular", +"portion", +"position", +"possible", +"post", +"potato", +"pottery", +"poverty", +"powder", +"power", +"practice", +"praise", +"predict", +"prefer", +"prepare", +"present", +"pretty", +"prevent", +"price", +"pride", +"primary", +"print", +"priority", +"prison", +"private", +"prize", +"problem", +"process", +"produce", +"profit", +"program", +"project", +"promote", +"proof", +"property", +"prosper", +"protect", +"proud", +"provide", +"public", +"pudding", +"pull", +"pulp", +"pulse", +"pumpkin", +"punch", +"pupil", +"puppy", +"purchase", +"purity", +"purpose", +"purse", +"push", +"put", +"puzzle", +"pyramid", +"quality", +"quantum", +"quarter", +"question", +"quick", +"quit", +"quiz", +"quote", +"rabbit", +"raccoon", +"race", +"rack", +"radar", +"radio", +"rail", +"rain", +"raise", +"rally", +"ramp", +"ranch", +"random", +"range", +"rapid", +"rare", +"rate", +"rather", +"raven", +"raw", +"razor", +"ready", +"real", +"reason", +"rebel", +"rebuild", +"recall", +"receive", +"recipe", +"record", +"recycle", +"reduce", +"reflect", +"reform", +"refuse", +"region", +"regret", +"regular", +"reject", +"relax", +"release", +"relief", +"rely", +"remain", +"remember", +"remind", +"remove", +"render", +"renew", +"rent", +"reopen", +"repair", +"repeat", +"replace", +"report", +"require", +"rescue", +"resemble", +"resist", +"resource", +"response", +"result", +"retire", +"retreat", +"return", +"reunion", +"reveal", +"review", +"reward", +"rhythm", +"rib", +"ribbon", +"rice", +"rich", +"ride", +"ridge", +"rifle", +"right", +"rigid", +"ring", +"riot", +"ripple", +"risk", +"ritual", +"rival", +"river", +"road", +"roast", +"robot", +"robust", +"rocket", +"romance", +"roof", +"rookie", +"room", +"rose", +"rotate", +"rough", +"round", +"route", +"royal", +"rubber", +"rude", +"rug", +"rule", +"run", +"runway", +"rural", +"sad", +"saddle", +"sadness", +"safe", +"sail", +"salad", +"salmon", +"salon", +"salt", +"salute", +"same", +"sample", +"sand", +"satisfy", +"satoshi", +"sauce", +"sausage", +"save", +"say", +"scale", +"scan", +"scare", +"scatter", +"scene", +"scheme", +"school", +"science", +"scissors", +"scorpion", +"scout", +"scrap", +"screen", +"script", +"scrub", +"sea", +"search", +"season", +"seat", +"second", +"secret", +"section", +"security", +"seed", +"seek", +"segment", +"select", +"sell", +"seminar", +"senior", +"sense", +"sentence", +"series", +"service", +"session", +"settle", +"setup", +"seven", +"shadow", +"shaft", +"shallow", +"share", +"shed", +"shell", +"sheriff", +"shield", +"shift", +"shine", +"ship", +"shiver", +"shock", +"shoe", +"shoot", +"shop", +"short", +"shoulder", +"shove", +"shrimp", +"shrug", +"shuffle", +"shy", +"sibling", +"sick", +"side", +"siege", +"sight", +"sign", +"silent", +"silk", +"silly", +"silver", +"similar", +"simple", +"since", +"sing", +"siren", +"sister", +"situate", +"six", +"size", +"skate", +"sketch", +"ski", +"skill", +"skin", +"skirt", +"skull", +"slab", +"slam", +"sleep", +"slender", +"slice", +"slide", +"slight", +"slim", +"slogan", +"slot", +"slow", +"slush", +"small", +"smart", +"smile", +"smoke", +"smooth", +"snack", +"snake", +"snap", +"sniff", +"snow", +"soap", +"soccer", +"social", +"sock", +"soda", +"soft", +"solar", +"soldier", +"solid", +"solution", +"solve", +"someone", +"song", +"soon", +"sorry", +"sort", +"soul", +"sound", +"soup", +"source", +"south", +"space", +"spare", +"spatial", +"spawn", +"speak", +"special", +"speed", +"spell", +"spend", +"sphere", +"spice", +"spider", +"spike", +"spin", +"spirit", +"split", +"spoil", +"sponsor", +"spoon", +"sport", +"spot", +"spray", +"spread", +"spring", +"spy", +"square", +"squeeze", +"squirrel", +"stable", +"stadium", +"staff", +"stage", +"stairs", +"stamp", +"stand", +"start", +"state", +"stay", +"steak", +"steel", +"stem", +"step", +"stereo", +"stick", +"still", +"sting", +"stock", +"stomach", +"stone", +"stool", +"story", +"stove", +"strategy", +"street", +"strike", +"strong", +"struggle", +"student", +"stuff", +"stumble", +"style", +"subject", +"submit", +"subway", +"success", +"such", +"sudden", +"suffer", +"sugar", +"suggest", +"suit", +"summer", +"sun", +"sunny", +"sunset", +"super", +"supply", +"supreme", +"sure", +"surface", +"surge", +"surprise", +"surround", +"survey", +"suspect", +"sustain", +"swallow", +"swamp", +"swap", +"swarm", +"swear", +"sweet", +"swift", +"swim", +"swing", +"switch", +"sword", +"symbol", +"symptom", +"syrup", +"system", +"table", +"tackle", +"tag", +"tail", +"talent", +"talk", +"tank", +"tape", +"target", +"task", +"taste", +"tattoo", +"taxi", +"teach", +"team", +"tell", +"ten", +"tenant", +"tennis", +"tent", +"term", +"test", +"text", +"thank", +"that", +"theme", +"then", +"theory", +"there", +"they", +"thing", +"this", +"thought", +"three", +"thrive", +"throw", +"thumb", +"thunder", +"ticket", +"tide", +"tiger", +"tilt", +"timber", +"time", +"tiny", +"tip", +"tired", +"tissue", +"title", +"toast", +"tobacco", +"today", +"toddler", +"toe", +"together", +"toilet", +"token", +"tomato", +"tomorrow", +"tone", +"tongue", +"tonight", +"tool", +"tooth", +"top", +"topic", +"topple", +"torch", +"tornado", +"tortoise", +"toss", +"total", +"tourist", +"toward", +"tower", +"town", +"toy", +"track", +"trade", +"traffic", +"tragic", +"train", +"transfer", +"trap", +"trash", +"travel", +"tray", +"treat", +"tree", +"trend", +"trial", +"tribe", +"trick", +"trigger", +"trim", +"trip", +"trophy", +"trouble", +"truck", +"true", +"truly", +"trumpet", +"trust", +"truth", +"try", +"tube", +"tuition", +"tumble", +"tuna", +"tunnel", +"turkey", +"turn", +"turtle", +"twelve", +"twenty", +"twice", +"twin", +"twist", +"two", +"type", +"typical", +"ugly", +"umbrella", +"unable", +"unaware", +"uncle", +"uncover", +"under", +"undo", +"unfair", +"unfold", +"unhappy", +"uniform", +"unique", +"unit", +"universe", +"unknown", +"unlock", +"until", +"unusual", +"unveil", +"update", +"upgrade", +"uphold", +"upon", +"upper", +"upset", +"urban", +"urge", +"usage", +"use", +"used", +"useful", +"useless", +"usual", +"utility", +"vacant", +"vacuum", +"vague", +"valid", +"valley", +"valve", +"van", +"vanish", +"vapor", +"various", +"vast", +"vault", +"vehicle", +"velvet", +"vendor", +"venture", +"venue", +"verb", +"verify", +"version", +"very", +"vessel", +"veteran", +"viable", +"vibrant", +"vicious", +"victory", +"video", +"view", +"village", +"vintage", +"violin", +"virtual", +"virus", +"visa", +"visit", +"visual", +"vital", +"vivid", +"vocal", +"voice", +"void", +"volcano", +"volume", +"vote", +"voyage", +"wage", +"wagon", +"wait", +"walk", +"wall", +"walnut", +"want", +"warfare", +"warm", +"warrior", +"wash", +"wasp", +"waste", +"water", +"wave", +"way", +"wealth", +"weapon", +"wear", +"weasel", +"weather", +"web", +"wedding", +"weekend", +"weird", +"welcome", +"west", +"wet", +"whale", +"what", +"wheat", +"wheel", +"when", +"where", +"whip", +"whisper", +"wide", +"width", +"wife", +"wild", +"will", +"win", +"window", +"wine", +"wing", +"wink", +"winner", +"winter", +"wire", +"wisdom", +"wise", +"wish", +"witness", +"wolf", +"woman", +"wonder", +"wood", +"wool", +"word", +"work", +"world", +"worry", +"worth", +"wrap", +"wreck", +"wrestle", +"wrist", +"write", +"wrong", +"yard", +"year", +"yellow", +"you", +"young", +"youth", +"zebra", +"zero", +"zone", +"zoo", +0, }; diff --git a/src/crypto/bip39/hmac.h b/src/crypto/bip39/hmac.h index 3921a171e..3cfc0cd0f 100644 --- a/src/crypto/bip39/hmac.h +++ b/src/crypto/bip39/hmac.h @@ -28,33 +28,25 @@ #include "sha2.h" typedef struct _HMAC_SHA256_CTX { - uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; - SHA256_CTX 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; + 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_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_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_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); +void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac); +void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest); #endif diff --git a/src/crypto/bip39/memzero.h b/src/crypto/bip39/memzero.h index 0a959fbc2..a7797d2b3 100644 --- a/src/crypto/bip39/memzero.h +++ b/src/crypto/bip39/memzero.h @@ -3,6 +3,6 @@ #include -void memzero(void* const pnt, const size_t len); +void memzero(void * const pnt, const size_t len); #endif diff --git a/src/crypto/bip39/options.h b/src/crypto/bip39/options.h index d3a9c2edf..e57654e6c 100644 --- a/src/crypto/bip39/options.h +++ b/src/crypto/bip39/options.h @@ -52,7 +52,7 @@ // support constructing BIP32 nodes from ed25519 and curve25519 curves. #ifndef USE_BIP32_25519_CURVES -#define USE_BIP32_25519_CURVES 1 +#define USE_BIP32_25519_CURVES 1 #endif // implement BIP39 caching diff --git a/src/crypto/bip39/pbkdf2.h b/src/crypto/bip39/pbkdf2.h index c2e3f04a6..e3f440c8f 100644 --- a/src/crypto/bip39/pbkdf2.h +++ b/src/crypto/bip39/pbkdf2.h @@ -28,39 +28,29 @@ #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; + 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; + 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_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_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_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); +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 From 514348c427cc35da48fb0cb59dcc087e2227a59a Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Fri, 11 Sep 2020 10:29:00 -0400 Subject: [PATCH 07/17] Add various bip39 and base32/base58 stuff --- src/crypto/bip39/base32.c | 233 +++++++++++++++++++++++ src/crypto/bip39/base32.h | 41 +++++ src/crypto/bip39/base58.c | 285 +++++++++++++++++++++++++++++ src/crypto/bip39/base58.h | 49 +++++ src/crypto/bip39/bip32.h | 112 ++++++++++++ src/crypto/bip39/bip39_mnemonic.c | 29 +++ src/crypto/bip39/bip39bruteforce.c | 87 +++++++++ 7 files changed, 836 insertions(+) create mode 100644 src/crypto/bip39/base32.c create mode 100644 src/crypto/bip39/base32.h create mode 100644 src/crypto/bip39/base58.c create mode 100644 src/crypto/bip39/base58.h create mode 100644 src/crypto/bip39/bip32.h create mode 100644 src/crypto/bip39/bip39_mnemonic.c create mode 100644 src/crypto/bip39/bip39bruteforce.c diff --git a/src/crypto/bip39/base32.c b/src/crypto/bip39/base32.c new file mode 100644 index 000000000..06760ccae --- /dev/null +++ b/src/crypto/bip39/base32.c @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E1PRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "base32.h" + +#include + +const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789"; + +static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out); +static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet); +static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out); + +static inline int base32_encode_character(uint8_t decoded, const char *alphabet); +static inline int base32_decode_character(char encoded, const char *alphabet); + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) { + size_t length = base32_encoded_length(inlen); + if (outlen <= length) { + return NULL; + } + + base32_encode_unsafe(in, inlen, (uint8_t *) out); + + for (size_t i = 0; i < length; i++) { + int ret = base32_encode_character(out[i], alphabet); + + if (ret == -1) { + return false; + } else { + out[i] = ret; + } + } + + out[length] = '\0'; + return &out[length]; +} + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) { + size_t length = base32_decoded_length(inlen); + if (outlen < length) { + return NULL; + } + + if (!base32_decode_unsafe((uint8_t *) in, inlen, (uint8_t *) out, alphabet)) { + return NULL; + } + + return &out[length]; +} + +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) { + uint8_t remainder = inlen % 5; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 5, j += 8) { + base32_5to8(&in[i], 5, &out[j]); + } + + if (remainder) base32_5to8(&in[i], remainder, &out[j]); +} + +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet) { + uint8_t remainder = inlen % 8; + size_t limit = inlen - remainder; + + size_t i, j; + for (i = 0, j = 0; i < limit; i += 8, j += 5) { + if (!base32_8to5(&in[i], 8, &out[j], alphabet)) { + return false; + } + } + + if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) { + return false; + } + + return true; +} + +size_t base32_encoded_length(size_t inlen) { + uint8_t remainder = inlen % 5; + + return (inlen / 5) * 8 + (remainder * 8 + 4) / 5; +} + +size_t base32_decoded_length(size_t inlen) { + uint8_t remainder = inlen % 8; + + return (inlen / 8) * 5 + (remainder * 5) / 8; +} + +void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 1) { + out[0] = (in[0] >> 3); + out[1] = (in[0] & 7) << 2; + } + + if (length >= 2) { + out[1] |= (in[1] >> 6); + out[2] = (in[1] >> 1) & 31; + out[3] = (in[1] & 1) << 4; + } + + if (length >= 3) { + out[3] |= (in[2] >> 4); + out[4] = (in[2] & 15) << 1; + } + + if (length >= 4) { + out[4] |= (in[3] >> 7); + out[5] = (in[3] >> 2) & 31; + out[6] = (in[3] & 3) << 3; + } + + if (length >= 5) { + out[6] |= (in[4] >> 5); + out[7] = (in[4] & 31); + } +} + +bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet) { + if (length == 1 || length == 3 || length == 6 || length > 8) { + return false; + } + + if (alphabet) { + uint8_t decoded[length]; + + for (size_t i = 0; i < length; i++) { + int ret = base32_decode_character(in[i], alphabet); + + if (ret == -1) { + return false; + } else { + decoded[i] = ret; + } + } + + base32_8to5_raw(decoded, length, out); + } else { + base32_8to5_raw(in, length, out); + } + + return true; +} + +void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) { + if (length >= 2) { + out[0] = (in[0] << 3); + out[0] |= (in[1] >> 2); + } + + if (length >= 4) { + out[1] = (in[1] & 3) << 6; + out[1] |= (in[2] << 1); + out[1] |= (in[3] >> 4); + } + + if (length >= 5) { + out[2] = (in[3] & 15) << 4; + out[2] |= (in[4] >> 1); + } + + if (length >= 7) { + out[3] = (in[4] & 1) << 7; + out[3] |= (in[5] << 2); + out[3] |= (in[6] >> 3); + } + + if (length >= 8) { + out[4] = (in[6] & 7) << 5; + out[4] |= (in[7] & 31); + } +} + +int base32_encode_character(uint8_t decoded, const char *alphabet) { + if (decoded >> 5) { + return -1; + } + + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (decoded < 26) { + return 'A' + decoded; + } else { + return '2' - 26 + decoded; + } + } + + return alphabet[decoded]; +} + +int base32_decode_character(char encoded, const char *alphabet) { + if (alphabet == BASE32_ALPHABET_RFC4648) { + if (encoded >= 'A' && encoded <= 'Z') { + return encoded - 'A'; + } else if (encoded >= 'a' && encoded <= 'z') { + return encoded - 'a'; + } else if (encoded >= '2' && encoded <= '7') { + return encoded - '2' + 26; + } else { + return -1; + } + } + + const char *occurrence = strchr(alphabet, encoded); + + if (occurrence) { + return occurrence - alphabet; + } else { + return -1; + } +} diff --git a/src/crypto/bip39/base32.h b/src/crypto/bip39/base32.h new file mode 100644 index 000000000..250997967 --- /dev/null +++ b/src/crypto/bip39/base32.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE32_H__ +#define __BASE32_H__ + +#include +#include +#include + +extern const char *BASE32_ALPHABET_RFC4648; + +char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet); +void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out); + +uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet); +bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet); + +size_t base32_encoded_length(size_t inlen); +size_t base32_decoded_length(size_t inlen); + +#endif diff --git a/src/crypto/bip39/base58.c b/src/crypto/bip39/base58.c new file mode 100644 index 000000000..cd74617b8 --- /dev/null +++ b/src/crypto/bip39/base58.c @@ -0,0 +1,285 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "base58.h" +#include "sha2.h" +#include "ripemd160.h" +#include "memzero.h" + +const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +const int8_t b58digits_map[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, + -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, + 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, + -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, + 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, +}; + +bool b58tobin(void *bin, size_t *binszp, const char *b58) +{ + size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + + const unsigned char *b58u = (const unsigned char*)b58; + unsigned char *binu = bin; + size_t outisz = (binsz + 3) / 4; + uint32_t outi[outisz]; + uint64_t t; + uint32_t c; + size_t i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + size_t b58sz; + + b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) + ++zerocount; + + for ( ; i < b58sz; ++i) + { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--; ) + { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + switch (bytesleft) { + case 3: + *(binu++) = (outi[0] & 0xff0000) >> 16; + //-fallthrough + case 2: + *(binu++) = (outi[0] & 0xff00) >> 8; + //-fallthrough + case 1: + *(binu++) = (outi[0] & 0xff); + ++j; + //-fallthrough + default: + break; + } + + for (; j < outisz; ++j) + { + *(binu++) = (outi[j] >> 0x18) & 0xff; + *(binu++) = (outi[j] >> 0x10) & 0xff; + *(binu++) = (outi[j] >> 8) & 0xff; + *(binu++) = (outi[j] >> 0) & 0xff; + } + + // Count canonical base58 byte count + binu = bin; + for (i = 0; i < binsz; ++i) + { + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } + break; + } + --*binszp; + } + *binszp += zerocount; + + return true; +} + +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + hasher_Raw(hasher_type, bin, binsz - 4, buf); + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) +{ + const uint8_t *bin = data; + int carry; + ssize_t i, j, high, zcount = 0; + size_t size; + + while (zcount < (ssize_t)binsz && !bin[zcount]) + ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) + { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) + { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + } + } + + for (j = 0; j < (ssize_t)size && !buf[j]; ++j); + + if (*b58sz <= zcount + size - j) + { + *b58sz = zcount + size - j + 1; + return false; + } + + if (zcount) + memset(b58, '1', zcount); + for (i = zcount; j < (ssize_t)size; ++i, ++j) + b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; +} + +int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + hasher_Raw(hasher_type, data, datalen, hash); + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen) +{ + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58check(nd, res, hasher_type, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} + +#if USE_GRAPHENE +int b58gphcheck(const void *bin, size_t binsz, const char *base58str) +{ + unsigned char buf[32]; + const uint8_t *binc = bin; + unsigned i; + if (binsz < 4) + return -4; + ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) + for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) + {} // Just finding the end of zeros, nothing to do in loop + if (binc[i] == '\0' || base58str[i] == '1') + return -3; + + return binc[0]; +} + +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize) +{ + if (datalen > 128) { + return 0; + } + uint8_t buf[datalen + 32]; + uint8_t *hash = buf + datalen; + memcpy(buf, data, datalen); + ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 + size_t res = strsize; + bool success = b58enc(str, &res, buf, datalen + 4); + memzero(buf, sizeof(buf)); + return success ? res : 0; +} + +int base58gph_decode_check(const char *str, uint8_t *data, int datalen) +{ + if (datalen > 128) { + return 0; + } + uint8_t d[datalen + 4]; + size_t res = datalen + 4; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen + 4 - res; + if (b58gphcheck(nd, res, str) < 0) { + return 0; + } + memcpy(data, nd, res - 4); + return res - 4; +} +#endif diff --git a/src/crypto/bip39/base58.h b/src/crypto/bip39/base58.h new file mode 100644 index 000000000..0fa9167bf --- /dev/null +++ b/src/crypto/bip39/base58.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BASE58_H__ +#define __BASE58_H__ + +#include +#include +#include "hasher.h" +#include "options.h" + +extern const char b58digits_ordered[]; +extern const int8_t b58digits_map[]; + +int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); +int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); + +// Private +bool b58tobin(void *bin, size_t *binszp, const char *b58); +int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str); +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); + +#if USE_GRAPHENE +int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize); +int base58gph_decode_check(const char *str, uint8_t *data, int datalen); +int b58gphcheck(const void *bin, size_t binsz, const char *base58str); +#endif + +#endif diff --git a/src/crypto/bip39/bip32.h b/src/crypto/bip39/bip32.h new file mode 100644 index 000000000..c0a04b5f8 --- /dev/null +++ b/src/crypto/bip39/bip32.h @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BIP32_H__ +#define __BIP32_H__ + +#include +#include +#include +#include "ecdsa.h" +#include "ed25519-donna/ed25519.h" +#include "options.h" + +typedef struct { + const char *bip32_name; // string for generating BIP32 xprv from seed + const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519 + + HasherType hasher_base58; + HasherType hasher_sign; + HasherType hasher_pubkey; + HasherType hasher_script; +} curve_info; + +typedef struct { + uint32_t depth; + uint32_t child_num; + uint8_t chain_code[32]; + + uint8_t private_key[32]; + uint8_t private_key_extension[32]; + + uint8_t public_key[33]; + const curve_info *curve; +} HDNode; + +int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out); + +int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out); + +int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out); + +#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) + +int hdnode_private_ckd(HDNode *inout, uint32_t i); + +#if USE_CARDANO +int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i); +int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out); +#endif + +int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code); + +int hdnode_public_ckd(HDNode *inout, uint32_t i); + +void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat); + +#if USE_BIP32_CACHE +int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint); +#endif + +uint32_t hdnode_fingerprint(HDNode *node); + +void hdnode_fill_public_key(HDNode *node); + +#if USE_ETHEREUM +int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash); +#endif + +#if USE_NEM +int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address); +int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key); +int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer); +#endif + +int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); +int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64])); + +int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size); + +int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); + +int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize); + +int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint); + +void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw); +void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize); + +const curve_info *get_curve_by_name(const char *curve_name); + +#endif diff --git a/src/crypto/bip39/bip39_mnemonic.c b/src/crypto/bip39/bip39_mnemonic.c new file mode 100644 index 000000000..a4dc27b86 --- /dev/null +++ b/src/crypto/bip39/bip39_mnemonic.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include "bip39.h" +#include + +// NOTE: We must override this to implement actual RNG! +void random_buffer(uint8_t *buf, size_t len) { + if( len > 0 ) { + randombytes_buf(buf, len); + } +} + +int main(int argc, char **argv) +{ + char *this = argv[0]; + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", this); + return 1; + } + if (sodium_init() == -1) { + fprintf(stderr, "libsodium init failed! :(\n"); + return 1; + } + int strength = 256; + const char *mnemonic = mnemonic_generate(strength); + printf("%s\n", mnemonic); + return 0; +} diff --git a/src/crypto/bip39/bip39bruteforce.c b/src/crypto/bip39/bip39bruteforce.c new file mode 100644 index 000000000..10fd69da7 --- /dev/null +++ b/src/crypto/bip39/bip39bruteforce.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include "bip39.h" +#include "bip32.h" +#include "ecdsa.h" +#include "curves.h" + +char iter[256]; +uint8_t seed[512 / 8]; +uint8_t addr[21], pubkeyhash[20]; +int count = 0, found = 0; +HDNode node; +clock_t start; + +// around 280 tries per second + +// testing data: +// +// mnemonic: "all all all all all all all all all all all all" +// address: "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL" +// passphrase: "" +// +// mnemonic: "all all all all all all all all all all all all" +// address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS" +// passphrase: "testing" + +int main(int argc, char **argv) +{ + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n"); + return 1; + } + const char *address = argv[1]; + const char *mnemonic, *item; + if (argc == 3) { + mnemonic = argv[2]; + item = "passphrase"; + } else { + mnemonic = NULL; + item = "mnemonic"; + } + if (mnemonic && !mnemonic_check(mnemonic)) { + fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic); + return 2; + } + if (!ecdsa_address_decode(address, 0, HASHER_SHA2, addr)) { + fprintf(stderr, "\"%s\" is not a valid address\n", address); + return 3; + } + printf("Reading %ss from stdin ...\n", item); + start = clock(); + for (;;) { + if (fgets(iter, 256, stdin) == NULL) break; + int len = strlen(iter); + if (len <= 0) { + continue; + } + count++; + iter[len - 1] = 0; + if (mnemonic) { + mnemonic_to_seed(mnemonic, iter, seed, NULL); + } else { + mnemonic_to_seed(iter, "", seed, NULL); + } + hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node); + hdnode_private_ckd_prime(&node, 44); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd_prime(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_private_ckd(&node, 0); + hdnode_fill_public_key(&node); + ecdsa_get_pubkeyhash(node.public_key, HASHER_SHA2, pubkeyhash); + if (memcmp(addr + 1, pubkeyhash, 20) == 0) { + found = 1; + break; + } + } + float dur = (float)(clock() - start) / CLOCKS_PER_SEC; + printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, (float)count/dur); + if (found) { + printf("Correct %s found! :-)\n\"%s\"\n", item, iter); + return 0; + } + printf("Correct %s not found. :-(\n", item); + return 4; +} From 7ae5a565d596edc5097ab53e0f46875c384ae75f Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Fri, 11 Sep 2020 10:30:01 -0400 Subject: [PATCH 08/17] Add a bunch of things required by bip39 dependencies --- src/crypto/bip39/blake256.h | 53 ++++++++++++ src/crypto/bip39/blake2_common.h | 39 +++++++++ src/crypto/bip39/blake2b.h | 41 +++++++++ src/crypto/bip39/blake2s.h | 41 +++++++++ src/crypto/bip39/hasher.c | 144 +++++++++++++++++++++++++++++++ src/crypto/bip39/hasher.h | 80 +++++++++++++++++ src/crypto/bip39/memzero.c | 66 ++++++++++++++ src/crypto/bip39/secp256k1.h | 38 ++++++++ 8 files changed, 502 insertions(+) create mode 100644 src/crypto/bip39/blake256.h create mode 100644 src/crypto/bip39/blake2_common.h create mode 100644 src/crypto/bip39/blake2b.h create mode 100644 src/crypto/bip39/blake2s.h create mode 100644 src/crypto/bip39/hasher.c create mode 100644 src/crypto/bip39/hasher.h create mode 100644 src/crypto/bip39/memzero.c create mode 100644 src/crypto/bip39/secp256k1.h diff --git a/src/crypto/bip39/blake256.h b/src/crypto/bip39/blake256.h new file mode 100644 index 000000000..313b6260e --- /dev/null +++ b/src/crypto/bip39/blake256.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef __BLAKE256_H__ +#define __BLAKE256_H__ + +#include +#include + +#define BLAKE256_DIGEST_LENGTH 32 +#define BLAKE256_BLOCK_LENGTH 64 + +typedef struct { + uint32_t h[8], s[4], t[2]; + size_t buflen; + uint8_t nullt; + uint8_t buf[64]; +} BLAKE256_CTX; + +void blake256_Init(BLAKE256_CTX *); +void blake256_Update(BLAKE256_CTX *, const uint8_t *, size_t); +void blake256_Final(BLAKE256_CTX *, uint8_t *); + +void blake256(const uint8_t *, size_t, uint8_t *); + +#endif /* __BLAKE256_H__ */ diff --git a/src/crypto/bip39/blake2_common.h b/src/crypto/bip39/blake2_common.h new file mode 100644 index 000000000..40c6da3b5 --- /dev/null +++ b/src/crypto/bip39/blake2_common.h @@ -0,0 +1,39 @@ +static inline uint32_t load32( const void *src ) +{ + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline uint64_t load64( const void *src ) +{ + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static inline void store16( void *dst, uint16_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store32( void *dst, uint32_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline void store64( void *dst, uint64_t w ) +{ + memcpy(dst, &w, sizeof w); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static inline uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + diff --git a/src/crypto/bip39/blake2b.h b/src/crypto/bip39/blake2b.h new file mode 100644 index 000000000..1a43e92d1 --- /dev/null +++ b/src/crypto/bip39/blake2b.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +enum blake2b_constant +{ + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state +{ + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; +} blake2b_state; + +#define BLAKE2B_CTX blake2b_state +#define BLAKE2B_BLOCK_LENGTH BLAKE2B_BLOCKBYTES +#define BLAKE2B_DIGEST_LENGTH BLAKE2B_OUTBYTES +#define BLAKE2B_KEY_LENGTH BLAKE2B_KEYBYTES + +int blake2b_Init(blake2b_state *S, size_t outlen); +int blake2b_InitKey(blake2b_state *S, size_t outlen, const void *key, size_t keylen); +int blake2b_InitPersonal(blake2b_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2b_Update(blake2b_state *S, const void *pin, size_t inlen); +int blake2b_Final(blake2b_state *S, void *out, size_t outlen); + +int blake2b(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2b_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/src/crypto/bip39/blake2s.h b/src/crypto/bip39/blake2s.h new file mode 100644 index 000000000..57991bc91 --- /dev/null +++ b/src/crypto/bip39/blake2s.h @@ -0,0 +1,41 @@ +#ifndef __BLAKE2S_H__ +#define __BLAKE2S_H__ + +#include +#include + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct __blake2s_state +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + uint32_t buflen; + uint8_t outlen; + uint8_t last_node; +} blake2s_state; + +#define BLAKE2S_CTX blake2s_state +#define BLAKE2S_BLOCK_LENGTH BLAKE2S_BLOCKBYTES +#define BLAKE2S_DIGEST_LENGTH BLAKE2S_OUTBYTES +#define BLAKE2S_KEY_LENGTH BLAKE2S_KEYBYTES + +int blake2s_Init(blake2s_state *S, size_t outlen); +int blake2s_InitKey(blake2s_state *S, size_t outlen, const void *key, size_t keylen); +int blake2s_InitPersonal(blake2s_state *S, size_t outlen, const void *personal, size_t personal_len); +int blake2s_Update(blake2s_state *S, const void *pin, size_t inlen); +int blake2s_Final(blake2s_state *S, void *out, size_t outlen); + +int blake2s(const uint8_t *msg, uint32_t msg_len, void *out, size_t outlen); +int blake2s_Key(const uint8_t *msg, uint32_t msg_len, const void *key, size_t keylen, void *out, size_t outlen); + +#endif diff --git a/src/crypto/bip39/hasher.c b/src/crypto/bip39/hasher.c new file mode 100644 index 000000000..dac3e9bf5 --- /dev/null +++ b/src/crypto/bip39/hasher.c @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "hasher.h" +#include "ripemd160.h" + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size) { + hasher->type = type; + hasher->param = param; + hasher->param_size = param_size; + + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Init(&hasher->ctx.sha2); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_256_Init(&hasher->ctx.sha3); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Init(&hasher->ctx.blake); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Init(&hasher->ctx.groestl); + break; + case HASHER_BLAKE2B: + blake2b_Init(&hasher->ctx.blake2b, 32); + break; + case HASHER_BLAKE2B_PERSONAL: + blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size); + break; + } +} + +void hasher_Init(Hasher *hasher, HasherType type) { + hasher_InitParam(hasher, type, NULL, 0); +} + +void hasher_Reset(Hasher *hasher) { + hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size); +} + +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { + switch (hasher->type) { + case HASHER_SHA2: + case HASHER_SHA2D: + case HASHER_SHA2_RIPEMD: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + case HASHER_SHA3: +#if USE_KECCAK + case HASHER_SHA3K: +#endif + sha3_Update(&hasher->ctx.sha3, data, length); + break; + case HASHER_BLAKE: + case HASHER_BLAKED: + case HASHER_BLAKE_RIPEMD: + blake256_Update(&hasher->ctx.blake, data, length); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_Update(&hasher->ctx.groestl, data, length); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Update(&hasher->ctx.blake2b, data, length); + break; + } +} + +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + case HASHER_SHA2D: + sha256_Final(&hasher->ctx.sha2, hash); + hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA2_RIPEMD: + sha256_Final(&hasher->ctx.sha2, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_SHA3: + sha3_Final(&hasher->ctx.sha3, hash); + break; +#if USE_KECCAK + case HASHER_SHA3K: + keccak_Final(&hasher->ctx.sha3, hash); + break; +#endif + case HASHER_BLAKE: + blake256_Final(&hasher->ctx.blake, hash); + break; + case HASHER_BLAKED: + blake256_Final(&hasher->ctx.blake, hash); + hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_BLAKE_RIPEMD: + blake256_Final(&hasher->ctx.blake, hash); + ripemd160(hash, HASHER_DIGEST_LENGTH, hash); + break; + case HASHER_GROESTLD_TRUNC: + groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); + break; + case HASHER_BLAKE2B: + case HASHER_BLAKE2B_PERSONAL: + blake2b_Final(&hasher->ctx.blake2b, hash, 32); + break; + } +} + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/src/crypto/bip39/hasher.h b/src/crypto/bip39/hasher.h new file mode 100644 index 000000000..0cde1df8b --- /dev/null +++ b/src/crypto/bip39/hasher.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2017 Saleem Rashid + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "sha2.h" +#include "sha3.h" +#include "blake256.h" +#include "groestl.h" +#include "blake2b.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, + HASHER_SHA2D, + HASHER_SHA2_RIPEMD, + + HASHER_SHA3, +#if USE_KECCAK + HASHER_SHA3K, +#endif + + HASHER_BLAKE, + HASHER_BLAKED, + HASHER_BLAKE_RIPEMD, + + HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ + + HASHER_BLAKE2B, + HASHER_BLAKE2B_PERSONAL, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; // for HASHER_SHA2{,D} + SHA3_CTX sha3; // for HASHER_SHA3{,K} + BLAKE256_CTX blake; // for HASHER_BLAKE{,D} + GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC + BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL} + } ctx; + + const void *param; + uint32_t param_size; +} Hasher; + +void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size); +void hasher_Init(Hasher *hasher, HasherType type); +void hasher_Reset(Hasher *hasher); +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif diff --git a/src/crypto/bip39/memzero.c b/src/crypto/bip39/memzero.c new file mode 100644 index 000000000..3c3a7383d --- /dev/null +++ b/src/crypto/bip39/memzero.c @@ -0,0 +1,66 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined( __NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t) len, 0, (rsize_t) len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} diff --git a/src/crypto/bip39/secp256k1.h b/src/crypto/bip39/secp256k1.h new file mode 100644 index 000000000..234ca97a9 --- /dev/null +++ b/src/crypto/bip39/secp256k1.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __SECP256K1_H__ +#define __SECP256K1_H__ + +#include + +#include "ecdsa.h" +#include "bip32.h" + +extern const ecdsa_curve secp256k1; +extern const curve_info secp256k1_info; +extern const curve_info secp256k1_decred_info; +extern const curve_info secp256k1_groestl_info; +extern const curve_info secp256k1_smart_info; + +#endif From a45ee31765e08d2a0c8801d5953d0cec780ac37b Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Fri, 11 Sep 2020 10:30:56 -0400 Subject: [PATCH 09/17] Add a static makefile for now --- src/crypto/bip39/Makefile | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/crypto/bip39/Makefile diff --git a/src/crypto/bip39/Makefile b/src/crypto/bip39/Makefile new file mode 100644 index 000000000..4a5dec3d8 --- /dev/null +++ b/src/crypto/bip39/Makefile @@ -0,0 +1,66 @@ +CC ?= gcc + +OPTFLAGS ?= -O3 -g + +CFLAGS += $(OPTFLAGS) \ + -std=gnu99 \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Werror + +VALGRIND ?= 1 + +CFLAGS += -I. +CFLAGS += -DVALGRIND=$(VALGRIND) +CFLAGS += $(shell pkg-config --cflags openssl) + +# disable certain optimizations and features when small footprint is required +ifdef SMALL +CFLAGS += -DUSE_PRECOMPUTED_CP=0 +endif + +SRCS = bignum.c ecdsa.c curves.c secp256k1.c nist256p1.c rand.c hmac.c bip32.c bip39.c pbkdf2.c base58.c base32.c +#SRCS += address.c +#SRCS += script.c +SRCS += ripemd160.c +SRCS += sha2.c +SRCS += sha3.c +SRCS += hasher.c +#SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c +#SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c +#SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c +#SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c +#SRCS += blake256.c +#SRCS += blake2b.c blake2s.c +#SRCS += chacha20poly1305/chacha20poly1305.c chacha20poly1305/chacha_merged.c chacha20poly1305/poly1305-donna.c chacha20poly1305/rfc7539.c +SRCS += memzero.c + +OBJS = $(SRCS:.c=.o) + +TESTLIBS = $(shell pkg-config --libs check) -lpthread -lm +TESTSSLLIBS = $(shell pkg-config --libs openssl) + +all: hasher.o bip39.o memzero.o pbkdf2.o base58.o base32.o + @echo "Created object files, donezo" + +%.o: %.c %.h options.h + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -rf *.o + From 5d86afef6a012962701f1385ea45533a660d640c Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 09:12:40 +0200 Subject: [PATCH 10/17] Port -txsend from str4d #37, https://github.com/zcash/zcash/pull/4522 --- src/init.cpp | 11 +++++++++++ src/rpc/rawtransaction.cpp | 16 ++++++++++++++++ src/wallet/wallet.cpp | 8 ++++++++ 3 files changed, 35 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index cd25e63fd..9f92999c4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -392,6 +392,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), 0)); + strUsage += HelpMessageOpt("-txsend=", _("Execute command to send a transaction instead of broadcasting (%s in cmd is replaced by transaction hex)")); strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX)); strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX)); strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX)); @@ -1118,6 +1119,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #endif } + if (mapArgs.count("-txsend")) { + if (GetBoolArg("-walletbroadcast", true)) { + if (SoftSetBoolArg("-walletbroadcast", false)) { + LogPrintf("%s: parameter interaction: -txsend= -> setting -walletbroadcast=0\n", __func__); + } else { + return InitError(_("Wallet transaction broadcasting is incompatible with -txsend (for privacy).")); + } + } + } + // ********************************************************* Step 3: parameter-to-internal-flags fZdebug=GetBoolArg("-zdebug", false); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 23327faf2..4b24081d7 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -45,7 +45,10 @@ #include +#include + #include +#include #include @@ -1373,6 +1376,19 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + std::string strCmd = GetArg("-txsend", ""); + if (!strCmd.empty()) { + if (fHaveChain) { + throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); + } + boost::replace_all(strCmd, "%s", EncodeHexTx(tx)); + boost::thread t(runCommand, strCmd); // thread runs free + // Return here so we don't add to our mempool or broadcast to peers + return hashTx.GetHex(); + } if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fe8cbb4f7..a0cd0533f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3950,6 +3950,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // Track how many getdata requests our transaction gets mapRequestCount[wtxNew.GetHash()] = 0; + std::string strCmd = GetArg("-txsend", ""); + if (fBroadcastTransactions) { // Broadcast @@ -3962,6 +3964,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) } wtxNew.RelayWalletTransaction(); } + // If we are configured to send transactions via an + // external service instead of broadcasting, do that + else if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", EncodeHexTx(wtxNew)); + boost::thread t(runCommand, strCmd); // thread runs free + } } return true; } From 2075d0da25c03435e9c827170df974c7fe9efcc7 Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 10:01:33 +0200 Subject: [PATCH 11/17] Port scheduler race condition fix from BTC upstream #133, https://github.com/bitcoin/bitcoin/commit/12519bf62b8c49b1c1744eca6ea5b3162a61f962 --- src/scheduler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 08aba3225..2e1223b8e 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -66,9 +66,10 @@ void CScheduler::serviceQueue() // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { - // Keep waiting until timeout + while (!shouldStop() && !taskQueue.empty()) { + boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) + break; // Exit loop after timeout, it means we reached the time of the event } // If there are multiple threads, the queue can empty while we're waiting (another From 702ea5fe91f11dc09a251dd8c6d7f6e5f392ba09 Mon Sep 17 00:00:00 2001 From: DenioD <41270280+DenioD@users.noreply.github.com> Date: Sat, 12 Sep 2020 15:11:52 +0200 Subject: [PATCH 12/17] delete joinsplit from rawtransactions #127 --- src/rpc/rawtransaction.cpp | 119 ------------------------------------- 1 file changed, 119 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4b24081d7..610e79149 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -85,65 +85,6 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.push_back(Pair("addresses", a)); } -UniValue TxJoinSplitToJSON(const CTransaction& tx) { - bool useGroth = tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION; - UniValue vjoinsplit(UniValue::VARR); - for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) { - const JSDescription& jsdescription = tx.vjoinsplit[i]; - UniValue joinsplit(UniValue::VOBJ); - - joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); - joinsplit.push_back(Pair("vpub_oldZat", jsdescription.vpub_old)); - joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new))); - joinsplit.push_back(Pair("vpub_newZat", jsdescription.vpub_new)); - - joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex())); - - { - UniValue nullifiers(UniValue::VARR); - BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) { - nullifiers.push_back(nf.GetHex()); - } - joinsplit.push_back(Pair("nullifiers", nullifiers)); - } - - { - UniValue commitments(UniValue::VARR); - BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) { - commitments.push_back(commitment.GetHex()); - } - joinsplit.push_back(Pair("commitments", commitments)); - } - - joinsplit.push_back(Pair("onetimePubKey", jsdescription.ephemeralKey.GetHex())); - joinsplit.push_back(Pair("randomSeed", jsdescription.randomSeed.GetHex())); - - { - UniValue macs(UniValue::VARR); - BOOST_FOREACH(const uint256 mac, jsdescription.macs) { - macs.push_back(mac.GetHex()); - } - joinsplit.push_back(Pair("macs", macs)); - } - - CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); - auto ps = SproutProofSerializer(ssProof, useGroth); - boost::apply_visitor(ps, jsdescription.proof); - joinsplit.push_back(Pair("proof", HexStr(ssProof.begin(), ssProof.end()))); - - { - UniValue ciphertexts(UniValue::VARR); - for (const ZCNoteEncryption::Ciphertext ct : jsdescription.ciphertexts) { - ciphertexts.push_back(HexStr(ct.begin(), ct.end())); - } - joinsplit.push_back(Pair("ciphertexts", ciphertexts)); - } - - vjoinsplit.push_back(joinsplit); - } - return vjoinsplit; -} - uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); UniValue TxShieldedSpendsToJSON(const CTransaction& tx) { @@ -309,9 +250,6 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -393,9 +331,6 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } entry.push_back(Pair("vout", vout)); - UniValue vjoinsplit = TxJoinSplitToJSON(tx); - entry.push_back(Pair("vjoinsplit", vjoinsplit)); - if (tx.fOverwintered && tx.nVersion >= SAPLING_TX_VERSION) { entry.push_back(Pair("valueBalance", ValueFromAmount(tx.valueBalance))); UniValue vspenddesc = TxShieldedSpendsToJSON(tx); @@ -481,33 +416,6 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp, const CPubKey& my " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value\n" - " \"vpub_new\" : x.xxx, (numeric) public output value\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" " \"blockhash\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of notarized DPoW confirmations\n" " \"rawconfirmations\" : n, (numeric) The number of raw confirmations\n" @@ -936,33 +844,6 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp, const CPubKey& " }\n" " ,...\n" " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value in HUSH\n" - " \"vpub_new\" : x.xxx, (numeric) public output value in HUSH\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" "}\n" "\nExamples:\n" From 85a40ae2ed9fa4c6d8c1f71cccdfbec9af20ae3f Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 13 Sep 2020 11:23:55 -0400 Subject: [PATCH 13/17] Tweak copyright --- src/sietch.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sietch.h b/src/sietch.h index 65908e2c9..995f4bbfa 100644 --- a/src/sietch.h +++ b/src/sietch.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2019-2020 The Hush developers * + * Copyright © 2019-2020 The Hush developers * * * * See the AUTHORS and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -10,6 +10,7 @@ * or distributed except according to the terms contained in the GPLv3 * * * * Removal or modification of this copyright notice is prohibited. * + * https://myhush.org * * * ******************************************************************************/ @@ -24,6 +25,7 @@ string newSietchZaddr() { SendManyRecipient newSietchRecipient(string zaddr) { int nAmount = 0; + // TODO: Should we randomize length of data, perhaps into buckets? // Sietch zouts have random data in their memos so they are indistinguishable from // encrypted data being stored in the memo field char hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; From 4f702525246b092e57a5c633e805fadc83f3cf74 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 13 Sep 2020 11:24:47 -0400 Subject: [PATCH 14/17] Increase max --sietch-min-zouts to 50 --- src/wallet/rpcwallet.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3b6361fe3..29b79e02b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4744,17 +4744,15 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) // End goal is to have this be as large as possible without slowing xtns down too much // A value of 7 will provide much stronger linkability privacy versus pre-Sietch operations unsigned int DEFAULT_MIN_ZOUTS=7; - unsigned int MAX_ZOUTS=25; + unsigned int MAX_ZOUTS=50; unsigned int MIN_ZOUTS=GetArg("--sietch-min-zouts", DEFAULT_MIN_ZOUTS); if((MIN_ZOUTS<3) || (MIN_ZOUTS>MAX_ZOUTS)) { - fprintf(stderr,"%s: Sietch min zouts must be >=3 and <= 25, setting to default value of %d\n", __FUNCTION__, DEFAULT_MIN_ZOUTS ); + fprintf(stderr,"%s: Sietch min zouts must be >= 3 and <= %d, setting to default value of %d\n", __FUNCTION__, MAX_ZOUTS, DEFAULT_MIN_ZOUTS ); MIN_ZOUTS=DEFAULT_MIN_ZOUTS; } int nAmount = 0; - // Dynamic Sietch zaddrs default to OFF - bool fSietchDynamic = GetArg("--sietch-dynamic",0); while (zaddrRecipients.size() < MIN_ZOUTS) { // OK, we identify this xtn as needing privacy zdust, we must decide how much, non-deterministically int decider = 1 + GetRandInt(100); // random int between 1 and 100 From b22a73fc2927a5a2e9f3868d52675e6ad0ba3733 Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 13 Sep 2020 12:35:41 -0400 Subject: [PATCH 15/17] Run-time randomly generated Sietch zdust addresses This commit drastically improves the privacy of the HUSH anonymity set under attacks which ingest wallet.dat's which have been obtained by seizure, i.e. stealing someones HUSH wallet.dat and putting it into chain analysis software. Ciphertrace is known to do this to ZEC and XMR and we can assume all chain analysis companies are implementing new ways to de-anonymize privacy coins with any data they can obtain. Instead of randomly sending to a randomly chosen static address, hushd Sietch zdust addresses are now randomly generated at run-time. These addresses are not stored in wallet.dat in any way and their private keys are not known except by the internal memory of hushd for a few milliseconds. This data is not stored in long-lived data structures of hushd, only as long as the RPC z_getnewaddress is running or the equivalent function for internals code paths. The seeds or private keys of these addresses are never stored on disk. This now brings hushd on par with SDL, which already does this via a different but equivalent seed phrase technique. With this technique, if a HUSH wallet.dat is seized, it's impossible to tell if any of the shielded outputs are random Sietch zdust with random data payload or a one-time-use zaddr with encrypted payload. --- src/sietch.h | 220 +-------------------------------------- src/wallet/rpcwallet.cpp | 25 +++-- 2 files changed, 16 insertions(+), 229 deletions(-) diff --git a/src/sietch.h b/src/sietch.h index 995f4bbfa..d68716bb1 100644 --- a/src/sietch.h +++ b/src/sietch.h @@ -38,223 +38,11 @@ SendManyRecipient newSietchRecipient(string zaddr) { return SendManyRecipient( zaddr, nAmount, string(str) ); } - -// The network essentially DoS's these addresses and reduces their privacy slightly -// by making them public, but in return, the rest of the shielded pool benefits -// and so it's a large benefit for a small cost. string randomSietchZaddr() { - std::vector SietchShieldedPool1 = { - "zs1qqj4aw35ku9yn72g3tha588mxk66mhl5smnn99as40887xvdg49d4yqf43hhqnj9rpsq7qaqqhx", - "zs1qywzq2cutvg6rkynjljtssz246easagumg3hlwjluz4g7qttg9kqrld7s43ewutpph56jmn2zu6", - "zs1qx7swmw28dj992f6zs0aqucds9kag88mnca5u73dddeqek4m97pg7h9qsaxxwwkgqxht6zujaxc", - "zs1q82pkqu58uemrm2749x6g2ta5shnsra9p5jgk0qqzxd3e08ke6vyeezz7lhldj32jxtsuemskk7", - "zs1qvah5w05qq4yhrsqrt73ckgntkmwdv9mntxep8clnxqfph8xggqad96a5nvwg4evfr9pc5ruvc8", - "zs1qwrkjcmnrwrqqkz3dyfjvdvdppe0ndnm8fhhpsz8stje4qcfc54jtuygz2jfwc3aag69wsjcm8h", - "zs1q5pd7h4x7dtnpa4ace7tytye5sd0j4043t4f3jdntyxvg9ex258nu6pw9tthn6t5gmjq5gv0lhc", - "zs1q6vjrpsuf468an545q7fh9cx0xlkwh75a7qjpemjh3ymuqqzxz5ts2n2dcth3yfnlv6vqpjyglr", - "zs1qmsvwtxkwlh3tkh0lqtwqv2mxy94jt778f7j74a8067nejkt4j3m2rkmypccju7cfuw7xyg0gg8", - "zs1qu3jxrw5qwuvl7zfvnsdvywr4a9cn4h00me65te29platx5agek072f5rvxgt8kdt630qs4tgtr", - "zs1qamxwddwrl5xn56alffruk69p304cqf7uf5nhqpwfc374l9ph00m78xv2kzwymyz0fhxcku7v5k", - "zs1q7gv479e6q7d8fxc35v5s27em66mmm5gz50excudf95rzjgnwdy5pnwdfytvm7gt8kt6wpkfphq", - "zs1pqvxd9a2zcsh2v8gaswh3jp2qkzz5umrucl5k4gx0rkvmq68krpx3jesavxftd8t0z56v8whllj", - "zs1ppn2mdznaa2pd9mavfnxrcjtv0c9un8pg6jaa9ww4wy6wdfs8xxwquqk5umtcjwm6vr4zrqy5x7", - "zs1pz9c9ydyrm7e876cvae9ha45ww77ru5fhys2yz33kjy8ej9230wjy8yupfxkynwqr6nfupgmf94", - "zs1p83g95avpsgr847eu3rm3xcmgurt9hc77wtndnmpypa046n529aqdc9ptz04ugsuhvum2ztzwe3", - "zs1p83jle2p8awu4peevq389y5kyrs5tqxxyrk32zy0t98d4cfepmme0myxp68nrq60xwzc5teulvg", - "zs1pg5ggzwx4yaa7g83yuhay8kzh78nahxfe7cgavn88f7rxlnuckhl2vznv0f33yuqhhs3sh62vl6", - "zs1p2nrefmqfhnwrxqfsz4ruvu8wl7742j5rv2fmwlpmpudwqpdn2yrha9rwsu5gc0fdv2j73tfk6a", - "zs1pw29hkrvszxpe2e4tjpj5h9pszjhql2p4tzcj2c5lf67m7d8jtgc22vehftxdnqze33mgtjc25k", - "zs1p0ggg024alu2l5x8df8ucu4lz8r453su56w2mmshru49uh9a0p6ufy3qfj8a9n7xeu8dxxjrk4p", - "zs1psaydszvszu4mar7ef9gk8atmwpnfjjsh8plajn6ttlgdk44jfud5zv8l3uyq73qk3eskec96ut", - "zs1pjf3kczvrwduuy4x99t03wfrgwstueyw0ypvwa44fz2tukux8kqqqs48uag4y39ed4rux8etvv0", - "zs1pnwzzh4mhehkvf4ys9x70q6meq9mgqj6mgl9ddzwvf8excswrj54lfgu4m9slmc90s37q8e63du", - "zs1pnndevupuakjcqyqzu4sfcgdmdzrhutp8ygxwsl5wvq5hgu20u55auu8p08wphvz9mu3k8ynyr5", - "zs1pmy6tvt9p3xxp5edt70mkwfqk0ljgaranzdnluh5ln36g9g3v2udquleuz5974q2mamywmrxl7j", - "zs1pau6lddk3uapms7v7rsmxvxeekqh52z795kzy9z3dv9qvzq3jwh4pr2adg5cf8fw2e3mzqmgstq", - "zs1zpy6wuvy3jlrfmj0363tx6cuume6j0mqfakk7ydw4f6zvn4s7plewk0gtm7r34pjtppvkp8rzl0", - "zs1zpvkccety206ww6c344ehughuyklc3v02q07j4p72pqewxl0n50zugtje6lclj3m292t6vs56fl", - "zs1zzucdg9kalcjnnknt98gpg42qm9aqpkc6qf5ewgr29udu55r0zt862z3zt23sd4mj9t47k7k6w4", - "zs1z9agq4vq7eswwynhmzdsy58nxq3azhn66y853yw9kvercmve8vv6d5pawpwwpwpuyedmzpcqk8q", - "zs1zvddl2e0pve5kl0hu7fcum30lyhx4pdq64jztq2vp09lqtu5gclfg4fe9fqvnm8k2d5svydg7s4", - "zs1zvsmkn6a4celtcg8ece6exnkvnr2u06ej8kjt6mrpm0983e86dr9al6gd5g73k24j0a0zkpjs3w", - "zs1zv33kglx4n5572dg2pez2k3m7tgtz08a70ndpfj6x204pphlm0pzcppetsnjlat3qflswqfmu83", - "zs1zsz5c9xua7arkvd60vsl559d4dvnjz8ejq4rlmmm9cnz942fdmjmvsgrdl7d5ddxh4y9258jk2l", - "zs1z5n6qvch0wfymumxjflezekxa2j5t978eqzh9ldxsl39h2jjrlzdv9rf00wdrvg0t6afq7mq0us", - "zs1z4ymm3gt22f3pcj9p9l2yg00e2m39kfexgaz99s9y4nsuxhlk6u0sl9lsx9awzywumxyuxv9vuw", - "zs1zkjnhz96xepc97rfyven23epymd5s558yqhp488gcxcj794z6p37h5ej5m5waqxfupmc538mej3", - "zs1zcqdekyq656yj2y86lh08u8zpetfanj5u4rhfpcphne9xw7esce8asux2rdr4yjxzds56fuda5r", - "zs1zceru3jt9m3jqzacnffetvrg8zch6le0zactl7ssfky2vwy7pcffkg3pmauqqpkv5v7nv3uzc5a", - "zs1zellp4tdmxdsd6hmg2c4qlx96m39c0cjlqupw085z87lvzcnx2r0gs7plc0wp4m4upk3zcs35e8", - "zs1zm2pcg2d3hnyxufn8cyshjn742gmffwaqdc0nt5uf9gsytdjywsqaasfdxf4sysfu0sgxjwjp0g", - "zs1za9nk7fpgnfetjulq6t8jgfyks06xg4q8rfwpgsfrkn49k34nc7xhm27dnjuzztgnwkww28ztyw", - "zs1zaaz6j6z7z748mck4v55s3fd4htl4f478kulnwr84m8vn4m0r227juddyq0ncu3cyvc765z9gm4", - "zs1zlz59lgwc8pqq33508v5ygk9e58f7fs4rpj3achhwnkcyn2dku44yfjghdf5l2v50nu2gjzgl2l", - "zs1zlgenma0yuqxmqgns2avpnauclxgfvgd6rf0jt09fmfyaflwlhsscem9ypmrvewl9l356dn3jtr", - "zs1rzu2yg2328l2wlfstu27dl024ucqsjx6g635yxmyhs0wr3lduutkc3peuhqe83uueh5n5q624rd", - "zs1rr9jpeemn9ek30x4h65rx0ddul7xet6cc8atwrjftmq9sdrvj9f5zdc9xg7amtc6dv5fxjyhu54", - "zs1rrgccr0yvfn5fdek39x09y2ylyf42xkydcwzq67wdrzyjj2mv874easa4h4tymz5gj852aqpffk", - "zs1rynh7vl05weafzwkp0p5eafuzzqph04prgg74emqq0sx6xudtrs2380v3ycxgp5lzudw6tmc2zd", - "zs1rxqz0a59zx3yduncc3azyzexwu8xl6cc0zu83hfd28mksrgahhvx8604uhf0u5mna9m4znnj4gr", - "zs1rxr2xff2vcv0y9s6ux6c6t9y7r3zvcvrqmwkvsnxj39t0qv7qwyhncnykhzcqg0ggpu423ykzxe", - "zs1r8chvye5uzlskv8jvt6j8nxnyz4lshy3u46yjhc8w9ekhjhneg402knft3t943t5nrhs6d0d5um", - "zs1rgu6mz58xrqxpyl5xw7ss2szz29cg98s8xl25hu7fy4lcxw58zr93a8rgyha52vwxx7hxj2emkw", - "zs1rveutz8ftruljrlctum42kakjqk4cm8dm2807nqm974dz0rptlxcs999ttsvwp65vc9e59vv9fe", - "zs1rwfqhlezm5ln7kq8wp8hkl08ddn74ryr8cs4cu8qc23spdx79xgfqj4lju4u2yqdrkxkwfvk3ed", - "zs1rwklllsk9jwhhf0fedvlzsqfqdkwer05zh8c8hwypl4tls2hdal54lexhca7kghhum5hycurvfe", - "zs1r0ulehrcg9xz0lfdcukjm3qlvqy74t0u8raqf4zn88vdsta8mzp8t8p9ul8jragssvs9qaqpw2e", - "zs1r3t0cve050wufwl8r2tly05vn7w79v53fe6dagjtt2ese0qm6vgjp3rrsfu4n0am840sq5thn72", - "zs1rnd8zwan2xlrnfwylm9khkeutnzg2v9vjdnyellyuzkwmed94uvd2dq8ceumxwspz037zp2ctqa", - "zs1r4tphfnf3zy34dqyjuld2kgtyg88hrxpv756pkkkmrfdeun0cqzpepac4ma9qrjrvdqxg2z5fuv", - "zs1rcpywy0v4sfej85wdaslfwsp4pe9sa87xgzv24ywhps2l4c9jlrqttv0wl9zkc5e7rsekf42wvp", - "zs1r66et0z9xw3qqhzyc2aht294y7yqyz8wx2l2t63unca4k4zh4v9t44kpmg52z9va5968y45fdkx", - "zs1rat3szdulwxwmx7y4rdphvlpjj5phadvz0fsvj7mtg9ggzwd22sn30hzsh27h7t6cvca6a8wu2n", - "zs1rau4jcth66jsg098ucclp9tfa5qe6jmtmfkcluaqnyj3uatkt9dsrgx44xtmxr3e9xuxv6sy208", - "zs1ypf2v2yu4p4mnlmw0wd3mpztpjlhl39jnn6hkvf77ell0h5u6yg2pgeusvku5y5sykyy6kk6yyh", - "zs1yzkt8catgk6slwj7azu79tvwv6tkd6agcykvvht4rxlevtsh99u036jf5503pju3h05w7x02cm8", - "zs1yrty5fmnyaartpcyjnpal0w44g4mt2ey5tyzcmgq4g6qtsfjmxae7fvy2zsw7t0zvseuwcfwt2e", - "zs1y9p5gazcx04kke96xudep0edzkqr06gdjnr5vm99a6qxzatqz5katput4q9nx95e8965sg7d3pl", - "zs1y9vpfgkxwh3xm3j9d38zkeqql2lh8w3ucgerkww2asdv89p87emdavkzurnqpkrmu7e3xv5myue", - "zs1yfa9gwmn0xe4myrg0rf8kmu36243u8773ukeev0set2yv0z9vpxm6ratee52e9zmpvvx7w2xy28", - "zs1ytpjrujfsgs69smqerxeaf8m38jwxc4ejgxxe4pzc5qu4auqrgy8tf7zxc402pxf9uku646kc0q", - "zs1ytvtdwmcn8tnka6w6wa8n3ghnkf7gp2qaudd4233y6m509ntm59rr0n8eudhre0md7m0zedpcsq", - "zs1yjmeu09mzrt8rgehv2gcfhxx6ddqz7ww87ssfapndvc94hxfrfsdkkgm8f8nr36xm8p7q462qy2", - "zs1ynqghdu0r0c20csp3ygrxdw9hk2l89j3g59q8zhht9jyxycpcc9ccvhyyn2f9j0ehp4pk5wkhqs", - "zs1y5ny4jpjm05vp5awjd6muaqqypdv0y9tr6pz0m5t82cwtrearxwf7km4aznydpcjeuzxqvk0z9m", - "zs1yh2vd5usfsyv4pscjrxg9wdy3gnnyuh8vky27ln3u9jspadmpqsjmyvxmvfyyq3nv4deudvygxa", - "zs1yclvhy57hngs7d233e4x8ywfreswslz2gvn0f8epcs0wrzuqqau3hkrvf7ru6jhh0zmsyn5jkj6", - "zs1yunkgwzf0m5suz380j7xqge6rd9e6acjc5wp22z0jhalqdpspdjey7jfjvgrckgsk9ydc9yrnq3", - "zs19p94fnry6p88ms3yh60nl4kxlxmu7uxv9aafmf5pc4nyd64vslaqgmj30nxe3l5j7cxu5kqeqpm", - "zs19x2df6qmd4c9whrgj6m4mssz22x9qj9x8lmcnexnhw32pey24xy9sws5ts2q7guunm7mx9wmllj", - "zs198a984na6qt2z3uyhdkmj7sfevt794dl3mum3782kddjy4uawr2teznpuxvnzc4dvs3c6zyqxey", - "zs192ld62azpypesveqsat6m63sqaw95ejlqfcjsal5t0fea9zjzqnurmpnl6074zdms0amw83rw0x", - "zs19vsx09xmzlj9vr3s3vu8z4237gpcgrl7qs0vapzzawgnu7gxngeaxlgwqf0ppu0f7us9cfe3cqz", - "zs19wfwd8zufu27zugan77wf2g790egdw7vkulf6f375ylq0arnv2nv94l84nl8lp3tpccv763wetn", - "zs19wcqtqqjj0mnrn90ntcmyq5x8qr2wsaslqwt0fysz4xh2mmjy0z9jjh4sj86sjrgen0axx04zt4", - "zs19jypvpjpvhv5et5wq2ny09skt72hxz9adfgk2ev7nza5jyxr6gss5qelygnxn0szmjqyke2h8a7", - "zs195kll03d43her83a65y7z0zsetynlnft4pjxdspegvun0m7cwtx0vsxfm89mv50vxr90qhvcqpz", - "zs195e2g52jpyly7t9vjpfcegt87g7lpa4rm74nxn0zvmtzjhvg7f5gjnskc5ax5skvwprcshenyqs", - "zs194e84mfxc4vn4ssce7hkvgrcm3c8j7vehcetkdf78rele2lwkx9tzcfnrwhykdqa2nmwx5qcr0j", - "zs19cxqspj63ksk6uwtynj0la72zuvh8rxfh0e0pr2y5vuuvw35sm78juzh5gxcuqa8jggv703rplf", - "zs19e04k24qrca0sx5z47dxmtx0swcx2ywxqjt5594gu95rjaeyxrpa2vyylvzxpau5spt2v529me6", - "zs19707gmdvc4hfwg4lgvxg55695gltx3jwye8l2gjekrx4zqz7yr6grq8s8hpfqwggrywx509ln5y", - "zs1xrw8nwla7yrz8l3d7y3rxlhamel2ly4kdmxlc6w4cztxhd6l8wufqv2pcsvtl3d7s6awvjatyx9", - "zs1xymrgyhle6dcvjk5f62k4xygr0vrr2wckqy7sp6wc6cttn29hra77dzhwxst7z9rxqxkz08jd7g", - "zs1x9c8tetxgauxh474hlhnlscuhgzww8vnvxfwm0p8589x73t5yl2fph8q8r8qpl8sh0wfwx0vg62", - "zs1xxcpzsfpyekhvvum3erxjpt34pw3h70ma8vxwecg85tze380f4srlg8zlgxty8yqhutt234nk9q", - "zs1xx6pd3vtj78tg0zpwtc0jjkdxlfy48vegzd6cng4m9w0gtcya8ck7pqgf4l5sxf9ml5zvzru5xg", - "zs1x8qre6x5d8e3tt2m4l9q2tujw8ajun70qelp8tfynyw390rm6vhjtmpf58dmx4hccef9xe50az0", - "zs1x88vjduckqarz2j8tp2me08ya4dgd6pw7j4j98j5jynrze3xy2jjptzye7eftjxd6dn4sj03v7m", - }; - - std::vector SietchShieldedPool2 = { - "zs1ehrs7hetemzsmfz9xwt8xetxag33j3xzj8mhdgywdnvkk4dmtvw6eqys6gm3vr679y865jz7rth", - "zs1ehyr6w0c4mwp0wlp6w5letgm3rjk32rxa9kkkur86e5x8lutr9mwzey0hsesnz0yaarmxra7w2z", - "zs1ec793pjf3anee0qq9ex5u2qygjzk9llmwfygev563l89quc3u8wxvtz9kctlmv2dtjgqwn7krcg", - "zs1eclpgnqy7qll0l5z0gy7m4ew86yjvp397yxyau9y2y43x5mqfdw2sll95l83ux6h8mppzsx3xnp", - "zs1eexedkctuzhjysl00m0j3ekknd32635yd8rejx9ykjp6zz77fyzf5388env642ja2qlg6mrwgsc", - "zs1e77uz8yaj998arp56d0fm4p827wchlf2w09hve6rgkmavhzeyhke8qsk3l7s5k6yh2jwjheqpup", - "zs1elj4qvy42jpts2cu22tcwt0kmwzafpmrjgztwf2xcqaycrlr4rpfxfpswx63e6agvhz96gps9yf", - "zs16q0fzcvf25fh70ysn38v7qkpfspakmelnljgnyrpu7rvllyew57n5cpqjqe0wmy5j57au47j6x8", - "zs16pnkw3mucdef34jjk6q28zd7ghhatdcqn598vs3g70qev234uc5uw6xxxjnzef3pt2t567qev8v", - "zs16rmnl4hd6c226u3v6eekk68y59u0x7v37n8pmytt9xw6drugjml7ryhd243nf3l2pvafw42rnxc", - "zs16ruwvwmetmnnns0rxwtx2kss23da2pccares0tehzw3v3nxd483qn49c9apdfua0hpm8xdecdt4", - "zs16ymafsjd7fp9zdl9vtyvfedecvn7q2vcs7emeglwy7hpuphve97d3j87v2evqs0xm3jrx44nwfe", - "zs1697ggm9zqp4rh0fv4r9hnh9uy6gg4hk7r2lm33tp2we4ry5azpxq6nwuzscha0g2nx03x4sstq8", - "zs168t8u6at9k6kt748dv749dxahnk8rv8yn32z8gcgvc9rkhkewscgu8r8vuzv0zecnq26w9p7x0c", - "zs16gnyx6f8vql24cepamfquhr3jjt7wgmzjcvwtct4lwy9p2studln6ut9kjzf6empwqjtxqmddqy", - "zs1622ra8snywvxufsunk97pccr7k0j32p960evl9yqjadhju22m4sk48md84q5u238gej8xnm4xm5", - "zs162stv8m0udzy4c6ff5kqva2g7pqth2rrdn7rjjgw29dcx7lj3vs4dnj8fz0gczsat3u3q5axgva", - "zs16t78376h9ledgt50k2dmwssuhyy4hn94wfgd8vzegvqy9k9kauuvpe8xz0f3va65l8ufqhgv4gv", - "zs16vxrghgv7mth6k9unzdude9cyt9vl76ms5hm9ce4py92rk69j4p9u570974nh8kqh8e2stqknj5", - "zs1654eafn589g2ujzcasa8caz8exag742tra2dd6mjkp22axh27hda6sy9exh3wkp4c6f5vztafr0", - "zs164u3ntsnn7s3zrp6c5gsqfrwr0ywhspynvunq3fhvr9crwz5eme706j5awwvuatqwh7m2qqkqm9", - "zs16cpqwm4yml5x8j5r3q5j0xljam68pf56xt40hylzn69w45venwdvd4h8drys5t380mspkvt7h8r", - "zs16c6m9aqs0q9kadm4nk6hugmqw6p0lf2h6v5d9ccwszssyecq35sm6284c3uqx2u40da4s2mr2ap", - "zs16u7rc066566j9ux73dcq0m7cq4qdmtd3gefrnhhrpjww3z00j4za7m5mcutmj6qcezkzys87mpp", - "zs1673rm5d5z9sh2k9uc2cvgwk2e44z0sekx6ezt9n4fvgnky5yxa2tc306dw7n2dg5vwfn7ppwr5s", - "zs167nvq5ahvu4s26447rem9j37qglgtle4fghsgpksumkz34g2q9x783pak5jgdhhzylmgs9wemg8", - "zs16lluayez28xevxg0rawxxcd7yx5t7qaraet256sxe8ac69lj7n7ppncsx3m2tddxlzptzyxv0qr", - "zs1mydlmczamey4ydc79n8gj5wtgs79zge4nwhcg8g640r6fvwu6wpt70970p7ptkcrzg6r6frqh0u", - "zs1my6tgqmy3kgdlqncyd5dv9s727x9hcrmj8h06e5whn4hkn5t2x46j84276yd8pw0p6ysx53u38u", - "zs1mte528eue8smvjwpe9cs8qz3wud9735rnk7vrtefu9lhyvh5pyeyenpaq5fa08jpwrl4x7sz069", - "zs1mvmu20syf3u5yzd6hpdd29xfej8237x2k0pcmf7pvra46qem5g0jralrmdcvncgf5j0y5varzr2", - "zs1mw86y6g2c8972a2ndw57648p9qcx2jppxr9g5k24df8hl3rgfzfsfe2xyesemdfmasutk88duht", - "zs1mwca7dqjq0r2mzmn4qarw8acmt4rjk26lyyar35sssqe2fky2nmv3kmf0lfxs2a9htugsadg027", - "zs1m0rpcrkfagzpex9mlw2htyrwpxe48v47pj8zg96l9wm5k8xkj3kev3xca6wumv5avkgsjtygush", - "zs1mjgyju3jnyxjhekv72y448edq3j2cvtk5s4wrej790zzpv3uc20dvewt7nhjdqryuecmykfm0je", - "zs1mjlfwyma3fv45yg50j73wcswnap2s4lsh5c9km6lcem73wky9lej7vy8wrlkr75sy6z2g0agtmw", - "zs1mkh9s9gdfxx4dkug47dqnc98g76dhm09zty779pm6gqc5aye4gvxvduqm5j56nq4lncx5ygqu90", - "zs1mm7tesf30r56l8xmnxjyxvgmnsny2zntsxahllrd930q8ycahz8npdxt7lqwu3k8ljs9sw7uzs8", - "zs1mu34v9wtyhtlr22phfxkp670wt0gj4z8czumx0m4u05elg7kjzu0dzveq5jn28xg5a2wqr6cywd", - "zs1ma3xy4fj0vm0w37a4kur3ghe72f8nstmqmmvh0u48kurtlwg50rqqlw39j6ng8lrxgam2dh0zyr", - "zs1m7yauj7694wjz92m5sxds8udp43z6kclarqwzc22wn2q6svkkk4lpzx53kwctwfn6jqcu4yww5u", - "zs1m77qqksfvuqmjmwdm22xr2u99z3uz4glenk02md4tq5z066gc7jkdayhf2txspqggv29quacpy4", - "zs1uq88d69zrnksytnquejpksdvdlp9e5y3xec3eyf0rrya8zap623zpwjs5mfzadrp7twawkpennl", - "zs1uq0zzag2cmekwn9a35vkf2q45sary5v8nt2adukhej9ydq3qpegskg5naysl3wvvxtzuyv5lu8w", - "zs1uqs3n3j8kfgurz8tj0ea5g2ny200c69rwwpq50kkup8sxntdne6h9uhx3wc2y5jjkcggvpvcl4g", - "zs1uqmnl793xh4cskxjherwlpt7xfnt6fy2sp2l3n58hpmd4msj2g3fjsks02069tqgzzvn77mpfg7", - "zs1uz73f8arfahrvgtxcjwya33ql5w8mwkmyrvxvjrjx5rla07hv3ax49hkeqg3aqynxx39z4y4vtt", - "zs1urzuwedq4qgnqjsjwjeauzyyjwxvs27mau6zmpretn37my92h3jqc0waad4r8s7zeeczq6jfas6", - "zs1urfls60sjxpnla4hhe736qu54w7047akw2p9cksx054y8e8gdyknkhwv6spwzgstf7z2wrsdapw", - "zs1u9jum0rl3959ay3qqxskkak5emv0fpceuhuhcj9rnkzfy6gpe2uv6ny29c399nrc68fx6fffg6c", - "zs1u8fdxg8lu08p6s5z9qe6jf6fkvd74a99yg3n5exlm6wm8paypygy82ue2smf0qqlhdhjzy2jxq4", - "zs1u8u44rlv4ay27248807fqwyf6lw2w76v8evn26nvwv887caqlenjgsw0nqlajzw9equn7phhs95", - "zs1u4jhx25fghqzn2az7he7lrv7xj23xd8spcl660g9kzqa3wyykm5gucuu5wwxvum6l6spq4u4e5s", - "zs1uh85d43vr4wwqnq6e7akxtlwkzx2y8cmdm3wrxzj6m42pzj3xs2heqey79hgxrhwhapwu8tt73g", - "zs1uhwgwkg2y3xex7e34dvnx97d0jdnhmchevcvg54tg4dg00ay9sjucr82py4jqx0kkf7cz5dytad", - "zs1uhkhsv3c3m5r8z7unmceg4zln6edwfr25wjauv5u8fxdqhdflj7vuc2xnkm9028y802w2pyf07g", - "zs1uhuwuzu89j05p9y48nseklu7gfhw4mrwv68f9s66csafrkpsmpsh23zzgxm24nspmsgrvtpttzg", - "zs1ucetuz8ysvz42uvuwndjfnphrtsfgekgef228meuhfrqtm97gql87rsvhxmxplw2xmj27p9jemj", - "zs1ucm95fgyy72rf6x5rwl5m5pldt38lulzqf9ueepel4gvd4cqjhk8xrf4kvl2lnn5ge9fwyfrfva", - "zs1um3pu2u0eu0zpx4czj9dufvxnud2zd0x5lygepp6maz96j572r6mh8gpmlm3w6jhmxxz2sepdfh", - "zs1ulkw8j488xuhhlewedj9dr7atm5jatmlwsxz83lquhz42ln78utqmtqsmhagcquq6uqszk23g9d", - "zs1az03j8f46n2600z47xnf5y28j34rpxljh3j6w5p3xgsmqt2fuklmhyd383aljxf4mx4pcfv0xm8", - "zs1ayal4wq4crwj70u6hae82h6r4jpk7ptycfhs9v5y83lxc7u4gadegu2r5ggsgt95n0rjk284fzj", - "zs1a984wux9sr2594lr24yal43zq6pstczyevj7yr8pn403643zuge88ekrc0cj8n2fk6z6xrxjpsz", - "zs1a95ptq9d6nauwtvgdj2lnct9y6g4cmm258jzyuqhsk4m3gqmaz62t4klqe42eu83n27jcpgz0ed", - "zs1a8xdhdzpjqx0alrjg43enszjnf6nn6nhf6c3xd77ecrvp4kfarvux4u4lcttv3rgyhmgzxukw2q", - "zs1afqnaljmvzunvjhr3m8yf2g4r0pe66kkxkm6ldjhylyjfsclk3nf88u29pskdqx76szdz48tt3m", - "zs1avx0j6mrcqrhp9903xrysptm6gefcyv6uqltta92hsgjpp2f8h8rz8suwxgjkp2f8366y6n6dj8", - "zs1a036amk3q8azryytah2zpdhyazeruq2q7zq2c06l0845kl0v2rmg0h8cdjvta4alxj0my4kcfad", - "zs1ahy2sja2ala03wrc79xx2ks3ujxxnsm44uh6yucmy5p5l0xcfa3g90cdgs4l9rhy975zvd4uzts", - "zs1aeyqta7xs8edzq2c0z6e9v3vjep55e4lg9fp9ls6d55x2mel6snxud6kqcaz8nl7zgrxxj96d6a", - "zs1aap3thj9xna07vlg3yz389c34v9mgd06g234d3htyq667286phjsf98nndm8frts7frmcyjfa90", - "zs17qdqrdgwcafkpgchc4rvk22e4u86alhnmzne5xzantpecwrxf3c6jxqk7xgzanzjj4kmxd2tuwg", - "zs17z3fmn6e84ypzpzn0p0j9nddptrj2nwhk9lhaw952j0lzxslrp24cj0ltuem9g5dustakcq4dsp", - "zs17zut2398dst3hnmnslnk0jv9w4q9yn8akelymvs8ewurdytxushp92nyqv30quqhy0yju7rn7lw", - "zs17r4fuv9ldl3kzwk5stv59exusc7jlsmtcz4t2uzjnrgrr6aj6tvnp04wc9jq2n3eh6fsyqe2ru5", - "zs17rajftxlkcywcenl0cn3fqw4lh2un5lpfegjdz06j3vl9gjmay2d5pk7uequ02vw6tmtzz6jrst", - "zs179rvu8endcr48sft7zg4w6uvxwu4ps94r06uwk7e606yffkgtx7epaamlfdqnc6xa4l9scqcv4v", - "zs178dr2z7zgqrsg5ul3sxx05qky2kemfequf08dxr332n9f5fq9cj98jttssz97lzmf2k22xpn54m", - "zs172zz77ds82urqmsa9pgyz65k04euw7uuk58k4ardcxectjc4t4yjekxm8xxmgd7gqs8k6jupypk", - "zs172eamykp6sl4vx4tsgmg2t0p482hnn3gg4my9y4frd4tl5zgsyrsvjvlxc9zjtqpve6e6djdc4x", - "zs17v4xqdu83fkvrjxrpnjksuanj0pung2kqn9ys533nnm8kq8ad8xv9kd48e4utrz947pejg55p46", - "zs17dgakqvwzgh4dgfe70cjulju698cs50zvchsze2e3zvdp68wytqdcvj4suh4vq2acdg7wuvs7ar", - "zs17snaqr6vukwp4apsdf44h6w3flgphzrnpmdjly662tgqtvkgs72lpz7m7tnkksdmt5uzjgmpg2e", - "zs173ad7l6u8dr90e2t5jkrnw0gc9u2mppv9vjeh8l6q2jdvgnq6tq4anxxltwuxm3wssfzgg6hfcy", - "zs17nez6jn8tnse243f5uf72d8y000ynmjnm6vsrpzpd2fj75wq4u4lu7xc8fmtn2e5v0r7uknphs3", - "zs174c6x8u2yagjnsq2kswnd6fh8u2f3g5dkrk7r7ja5n30zwjm4ke3x84syt9qklqyk0m7vekcx9f", - "zs174mlfm6snsmgj4usez3e6xtd5nkwwl24vgg96srpnv7ulz4de6n4lx6cmxaqszqnk7p9y6wcl8q", - "zs17h5lnrnpprdtkjwq09ax94qetryf65qm5jqv0gpyeesw4wujytks9qljvlry863flf242arvx8f", - "zs1lp07e40usxenrznuuf2nzn5v7tx9pzp9r6eaw6upnm4t9cer8l5fckzm7jr58j5l77tzjrprv8v", - "zs1ly5u5sqeeax9g3uafva7fl35r3wv0nm2aka9m940graqjh0zlw7rrcgay0a7f29j3ar4wrj4uzu", - "zs1lgqckcp2uqx5c6gdm5zklzrxz8ygva9kxtxc4u4dlzpg68m9prga5q3ur3uqutkcy4ztuhclrxw", - "zs1lgz7ychnnhe58hk2e379zhqdxynp30e6fdh6xjxx8u9ga9rmwzdrdvqcq5kps2uetyf6gzeqdn2", - "zs1l2ghymesqwrfw89pqnw08u346es6wn86r77a55n7d7xky2rc58jfhn7man9kjjesnegec3frxeh", - "zs1ls3lyaqhm39zgz3528ereaa48vzsw4cw99k536524a6ruxmdqyvqnv4pl477q7rwptrzx8dhhzu", - "zs1lsnr42d2ez0w55pxws4qn70f68vxllv92wppu24n75y7a0wrmkw6qgup0md5jhjmkwhzu742zx4", - "zs1ljzwlum9nme83hhvkjkxl323u0ezm4sgnk84nzkyu5acum0kxf0s6g06gy78w0hl66f5263g7ha", - "zs1l5kfev0dpl8swjlyvyms5t9yhhnvg0590jfgpxw7zxx6eh29vd7453q9d0ne75x7gsm42j65l3v", - "zs1lhpxmvxmfpdfa5myd35wf24pmacrgdhrcpxydrcwz3qvmfvpt9x78nf2ne3kkqh40m0nvhhd3uj", - "zs1lhkhftvpkvcuyhwgcz4gq9y9l3ly5esglk2g0sgdctrz2cd63lgss2gtn8eedsvtuh8f6shpwww", - }; - //TODO: Assumes pools of 100 - int randIndex = GetRandInt(100); // random int between 0 and 99 - if(randIndex % 2) { - return SietchShieldedPool1[randIndex]; - } else { - return SietchShieldedPool2[randIndex]; - } + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto zdust = sk.default_address(); + return EncodePaymentAddress(zdust); } #endif diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 29b79e02b..c8793b4a8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -72,7 +72,7 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SAPLING = "sapling"; -const std::string ADDR_TYPE_DONOTREMEMBER = "donotremember"; +const std::string ADDR_TYPE_AMNESIA = "amnesia"; extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); @@ -3895,16 +3895,16 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk throw runtime_error( "z_getnewaddress ( type )\n" "\nReturns a new shielded address for receiving payments.\n" - "\nWith no arguments, returns a Sapling address.\n" - "\nBe very careful with 'donotremember' address type, the extended spending key (xsk) of that address is not stored in wallet.dat!\n" + "\nWith no arguments, returns a Sapling address (zaddr).\n" + "\nBe very careful with 'amnesia' address type, the address is not stored in wallet.dat and if you send funds to it THEY WILL BE LOST FOREVER\n" "\nArguments:\n" - "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. Either "+ ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER + " .\n" + "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. Either "+ ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_AMNESIA + " .\n" "\nResult:\n" "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new shielded address.\n" "\nExamples:\n" + HelpExampleCli("z_getnewaddress", "") + HelpExampleCli("z_getnewaddress", ADDR_TYPE_SAPLING) - + HelpExampleCli("z_getnewaddress", ADDR_TYPE_DONOTREMEMBER) + + HelpExampleCli("z_getnewaddress", ADDR_TYPE_AMNESIA) ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3917,15 +3917,14 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk } if (addrType == ADDR_TYPE_SAPLING) { return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey()); - } else if (addrType == ADDR_TYPE_DONOTREMEMBER) { - bool addToWallet = false; - auto zaddr = EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey(addToWallet)); + } else if (addrType == ADDR_TYPE_AMNESIA) { + auto zaddr = randomSietchZaddr(); if(fZdebug) { - fprintf(stderr,"%s: Sietch zaddr=%s created, xsk not stored in wallet.dat!\n", __FUNCTION__, zaddr.c_str() ); + fprintf(stderr,"%s: Sietch zaddr=%s created, not stored in wallet.dat!\n", __FUNCTION__, zaddr.c_str() ); } return zaddr; } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type! Try " + ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type! Try " + ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_AMNESIA); } } @@ -4758,8 +4757,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) int decider = 1 + GetRandInt(100); // random int between 1 and 100 string zdust1, zdust2; - // Which zaddr we send to is non-deterministically chosen from two zpools... - zdust1 = fSietchDynamic ? newSietchZaddr() : randomSietchZaddr(); + // Which zaddr we send to is randomly generated + zdust1 = randomSietchZaddr(); // And their ordering when given to internals is also non-deterministic, which // helps breaks assumptions blockchain analysts may use from z_sendmany internals @@ -4773,7 +4772,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) //50% chance of adding another zout if (decider % 2) { - zdust2 = fSietchDynamic ? newSietchZaddr() : randomSietchZaddr(); + zdust2 = randomSietchZaddr(); // 50% chance of adding it to the front or back since all odd numbers are 1 or 3 mod 4 if(decider % 4 == 3) { zaddrRecipients.push_back( newSietchRecipient(zdust2) ); From 5c5e545e75038279fcd8a8f2eeb617f8278aa89d Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 13 Sep 2020 19:12:21 -0400 Subject: [PATCH 16/17] HUSH has no JoinSplits --- src/wallet/rpcwallet.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c8793b4a8..89d15f14f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -73,7 +73,6 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SAPLING = "sapling"; const std::string ADDR_TYPE_AMNESIA = "amnesia"; -extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); @@ -170,7 +169,6 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); - entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx))); } string AccountFromValue(const UniValue& value) From 3f2e814067e1cb90793082a93cc77be8286e8b5b Mon Sep 17 00:00:00 2001 From: Duke Leto Date: Sun, 13 Sep 2020 19:15:15 -0400 Subject: [PATCH 17/17] alert system updates --- src/Makefile.am | 2 +- src/sendalert.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 88e33df95..dc66cb4a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -462,7 +462,7 @@ libbitcoin_server_a_SOURCES += rpc/testtransactions.cpp endif -# cli: zcash-cli +# cli libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ diff --git a/src/sendalert.cpp b/src/sendalert.cpp index 7b8ca4589..b626f5b05 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers // Copyright (c) 2016 The Zcash developers // Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44 @@ -74,9 +75,9 @@ void ThreadSendAlert() if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) return; + //TODO: wait until KOMODO_IN_SYNC MilliSleep(60*1000); // Wait a minute so we get connected - // // Alerts are relayed around the network until nRelayUntil, flood // filling to every node. // After the relay time is past, new nodes are told about alerts @@ -87,7 +88,7 @@ void ThreadSendAlert() CAlert alert; alert.nRelayUntil = GetTime() + 15 * 60; alert.nExpiration = GetTime() + 10 * 365 * 24 * 60 * 60; - alert.nID = 1005; // use https://github.com/zcash/zcash/wiki/specification#assigned-numbers to keep track of alert IDs + alert.nID = 1005; // HUSH3 has never had any alert id's alert.nCancel = 1004; // cancels previous messages up to this ID number // These versions are protocol versions @@ -103,12 +104,12 @@ void ThreadSendAlert() // 4000 or higher will put the RPC into safe mode alert.nPriority = 4000; alert.strComment = ""; - alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Hush (3.2.0 or later)."; + alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Hush (3.5.0 or later)."; alert.strRPCError = alert.strStatusBar; // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // alert.setSubVer.insert(std::string("/MagicBean:0.7.2/")); - const std::vector useragents = {}; //{"MagicBean", "BeanStalk", "AppleSeed", "EleosZcash"}; + const std::vector useragents = {}; //{"MagicBean", "BeanStalk", "AppleSeed" }; BOOST_FOREACH(const std::string& useragent, useragents) { }