diff --git a/src/sietch.h b/src/sietch.h index 64a4fe0ce..65908e2c9 100644 --- a/src/sietch.h +++ b/src/sietch.h @@ -16,6 +16,27 @@ #ifndef SIETCH_H #define SIETCH_H +string newSietchZaddr() { + bool addToWallet = false; + auto zaddr = EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey(addToWallet)); + return zaddr; +} + +SendManyRecipient newSietchRecipient(string zaddr) { + int nAmount = 0; + // 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'}; + // memo field is 512 bytes or 1024 hex chars + char str[1024]; + for(int i=0;i<1024;i++) { + str[i] = hex[GetRandInt(16)]; + } + str[1024] = 0; + 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. diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ed4d64f31..350215b69 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -72,6 +72,7 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; const std::string ADDR_TYPE_SAPLING = "sapling"; +const std::string ADDR_TYPE_DONOTREMEMBER = "donotremember"; extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); @@ -81,6 +82,9 @@ CBlockIndex *komodo_getblockindex(uint256 hash); extern string randomSietchZaddr(); extern CAmount fConsolidationTxFee; extern bool fZindex; +extern string randomSietchZaddr(); +extern SendManyRecipient newSietchRecipient(string zaddr); +extern string newSietchZaddr(); int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -2812,6 +2816,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) LOCK2(cs_main, pwalletMain->cs_wallet); + const CHDChain& hdChain = pwalletMain->GetHDChain(); UniValue obj(UniValue::VOBJ); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); @@ -2820,6 +2825,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); + obj.push_back(Pair("saplingAccountCounter", (int)hdChain.saplingAccountCounter)); if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); @@ -3890,14 +3896,15 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk "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" "\nArguments:\n" - "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. One of [\"" - + ADDR_TYPE_SAPLING + "\"].\n" + "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. Either "+ ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER + " .\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) ); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -3908,11 +3915,17 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk if (params.size() > 0) { addrType = params[0].get_str(); } - if (addrType == ADDR_TYPE_SAPLING) { return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey()); + } else if (addrType == ADDR_TYPE_DONOTREMEMBER) { + bool addToWallet = false; + auto zaddr = EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey(addToWallet)); + if(fZdebug) { + fprintf(stderr,"%s: Sietch zaddr=%s created, xsk not stored in wallet.dat!\n", __FUNCTION__, zaddr.c_str() ); + } + return zaddr; } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type!"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type! Try " + ADDR_TYPE_SAPLING + " or " + ADDR_TYPE_DONOTREMEMBER); } } @@ -4264,6 +4277,7 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& my "\nResult:\n" "{\n" " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n" + " \"private\": xxxxx, (numeric) the total balance of shielded funds\n" " \"private\": xxxxx, (numeric) the total balance of private funds\n" " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n" "}\n" @@ -4725,44 +4739,44 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) // SIETCH: Sprinkle our cave with some magic privacy zdust // 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 MIN_ZOUTS=GetArg("--sietch-min-zouts", DEFAULT_MIN_ZOUTS); - if((MIN_ZOUTS<2) || (MIN_ZOUTS>MAX_ZOUTS)) { - fprintf(stderr,"%s: Sietch min zouts must be >=2 and <= 25, setting to default value of %d\n", __FUNCTION__, 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 ); 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 nAmount = 0; int decider = 1 + GetRandInt(100); // random int between 1 and 100 - string memo = "f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - string zdust1, zdust2; // Which zaddr we send to is non-deterministically chosen from two zpools... - zdust1 = randomSietchZaddr(); + zdust1 = fSietchDynamic ? newSietchZaddr() : randomSietchZaddr(); // And their ordering when given to internals is also non-deterministic, which // helps breaks assumptions blockchain analysts may use from z_sendmany internals if (decider % 2) { - zaddrRecipients.insert(std::begin(zaddrRecipients), SendManyRecipient(zdust1, nAmount, memo) ); + zaddrRecipients.insert(std::begin(zaddrRecipients), newSietchRecipient(zdust1) ); } else { - zaddrRecipients.push_back( SendManyRecipient(zdust1, nAmount, memo) ); + zaddrRecipients.push_back( newSietchRecipient(zdust1) ); } if(fZdebug) fprintf(stderr,"%s: adding %s as zdust receiver\n", __FUNCTION__, zdust1.c_str()); //50% chance of adding another zout if (decider % 2) { - zdust2 = randomSietchZaddr(); + zdust2 = fSietchDynamic ? newSietchZaddr() : 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( SendManyRecipient(zdust2, nAmount, memo) ); + zaddrRecipients.push_back( newSietchRecipient(zdust2) ); } else { - zaddrRecipients.insert(std::begin(zaddrRecipients), SendManyRecipient(zdust2, nAmount, memo) ); + zaddrRecipients.insert(std::begin(zaddrRecipients), newSietchRecipient(zdust2) ); } if(fZdebug) fprintf(stderr,"%s: adding %s as zdust receiver\n", __FUNCTION__, zdust2.c_str()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 80d927284..e10065de4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -118,7 +118,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const // Generate a new Sapling spending key and return its public payment address -SaplingPaymentAddress CWallet::GenerateNewSaplingZKey() +SaplingPaymentAddress CWallet::GenerateNewSaplingZKey(bool addToWallet) { AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata @@ -159,7 +159,7 @@ SaplingPaymentAddress CWallet::GenerateNewSaplingZKey() mapSaplingZKeyMetadata[ivk] = metadata; auto addr = xsk.DefaultAddress(); - if (!AddSaplingZKey(xsk, addr)) { + if (addToWallet && !AddSaplingZKey(xsk, addr)) { throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed"); } // return default sapling payment address. diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f6e6274d1..dd6100f97 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1071,7 +1071,8 @@ public: * Sapling ZKeys */ //! Generates new Sapling key - libzcash::SaplingPaymentAddress GenerateNewSaplingZKey(); + // Sietch uses addToWallet=false + libzcash::SaplingPaymentAddress GenerateNewSaplingZKey(bool addToWallet=true); //! Adds Sapling spending key to the store, and saves it to disk bool AddSaplingZKey( const libzcash::SaplingExtendedSpendingKey &key,