From af20f12844ac7a1f7fdbe9a42fef5a272a76c5c8 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Mon, 2 Dec 2019 23:41:20 +0400 Subject: [PATCH] Sigma fixes (#777) * Sigma fixes * Tests fix --- configure.ac | 2 +- qa/rpc-tests/exodus_sendspend.py | 2 +- qa/rpc-tests/exodus_sigma_reindex.py | 2 +- qa/rpc-tests/exodus_sigma_reorg.py | 4 +- qa/rpc-tests/sigma_meetspend.py | 2 +- qa/rpc-tests/sigma_mintspend.py | 5 +- src/chainparams.cpp | 6 +++ src/clientversion.h | 2 +- src/consensus/params.h | 4 ++ src/exodus/rpctx.cpp | 5 +- src/exodus/sigma.cpp | 5 +- src/exodus/sigma.h | 3 +- src/exodus/sigmaprimitives.h | 12 ++--- src/exodus/test/create_payload_tests.cpp | 2 +- src/exodus/test/sigma_tests.cpp | 16 +++--- src/exodus/test/sigmaprimitives_tests.cpp | 14 ++--- src/exodus/test/wallet_tests.cpp | 14 ++--- src/exodus/test/walletmodels_tests.cpp | 2 +- src/exodus/txprocessor.cpp | 4 +- src/exodus/wallet.cpp | 6 +-- src/exodus/wallet.h | 2 +- src/hdmint/wallet.cpp | 8 ++- src/libzerocoin/Zerocoin.h | 1 + src/main.cpp | 14 +++++ src/miner.cpp | 3 ++ src/qt/sigmadialog.cpp | 4 ++ src/qt/walletmodel.cpp | 2 + src/qt/walletmodel.h | 1 + src/secp256k1/include/GroupElement.h | 2 + src/secp256k1/include/Scalar.h | 2 + src/secp256k1/src/cpp/GroupElement.cpp | 5 ++ src/secp256k1/src/cpp/Scalar.cpp | 6 ++- src/sigma.cpp | 19 ++++++- src/sigma/coin.cpp | 2 +- src/sigma/coinspend.cpp | 12 +++-- src/sigma/coinspend.h | 5 +- src/sigma/r1_proof_generator.hpp | 17 ++++-- src/sigma/r1_proof_verifier.hpp | 20 +++++-- src/sigma/sigma_primitives.hpp | 12 ++--- src/sigma/sigmaplus_prover.h | 1 + src/sigma/sigmaplus_prover.hpp | 65 +++++++++++++++++++++-- src/sigma/sigmaplus_verifier.h | 3 +- src/sigma/sigmaplus_verifier.hpp | 57 +++++++++++++++++--- src/sigma/test/coin_spend_tests.cpp | 26 ++++----- src/sigma/test/protocol_tests.cpp | 62 ++++++++++++++++++--- src/sigma/test/serialize_test.cpp | 2 +- src/test/sigma_manymintspend_test.cpp | 4 +- src/test/sigma_state_tests.cpp | 30 +++++------ src/test/zerocoin_tests2_v3.cpp | 5 +- src/wallet/sigmaspendbuilder.cpp | 17 ++++-- src/wallet/wallet.cpp | 23 ++++++-- src/zerocoin_params.h | 8 +++ 52 files changed, 413 insertions(+), 139 deletions(-) diff --git a/configure.ac b/configure.ac index 163ff62a59..ff1878160f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 13) define(_CLIENT_VERSION_REVISION, 8) -define(_CLIENT_VERSION_BUILD, 5) +define(_CLIENT_VERSION_BUILD, 8) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) define(_COPYRIGHT_HOLDERS,[The %s developers]) diff --git a/qa/rpc-tests/exodus_sendspend.py b/qa/rpc-tests/exodus_sendspend.py index f464c3ec20..5a5ad384ea 100755 --- a/qa/rpc-tests/exodus_sendspend.py +++ b/qa/rpc-tests/exodus_sendspend.py @@ -7,7 +7,7 @@ class ExodusSendSpendTest(ExodusTestFramework): def run_test(self): super().run_test() - sigma_starting_block = 500 + sigma_starting_block = 550 self.nodes[0].generatetoaddress(sigma_starting_block - self.nodes[0].getblockcount(), self.addrs[0]) self.sync_all() diff --git a/qa/rpc-tests/exodus_sigma_reindex.py b/qa/rpc-tests/exodus_sigma_reindex.py index 01528b9bcb..22f4061370 100755 --- a/qa/rpc-tests/exodus_sigma_reindex.py +++ b/qa/rpc-tests/exodus_sigma_reindex.py @@ -6,7 +6,7 @@ class ExodusSigmaReindexTest(ExodusTestFramework): def run_test(self): super().run_test() - sigma_start_block = 500 + sigma_start_block = 550 self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) # generate mints to spend diff --git a/qa/rpc-tests/exodus_sigma_reorg.py b/qa/rpc-tests/exodus_sigma_reorg.py index 664d1b5d27..6c09fa23ec 100755 --- a/qa/rpc-tests/exodus_sigma_reorg.py +++ b/qa/rpc-tests/exodus_sigma_reorg.py @@ -6,7 +6,7 @@ class ExodusSigmaReorgTest(ExodusTestFramework): def run_test(self): super().run_test() - sigma_start_block = 500 + sigma_start_block = 550 self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount()) # generate mints to spend @@ -75,4 +75,4 @@ def run_test(self): assert_equal(balance, self.nodes[0].exodus_getbalance(self.addrs[0], sigma_property)['balance']) if __name__ == '__main__': - ExodusSigmaReorgTest().main() \ No newline at end of file + ExodusSigmaReorgTest().main() diff --git a/qa/rpc-tests/sigma_meetspend.py b/qa/rpc-tests/sigma_meetspend.py index 66d80b1f20..ecde4cea7c 100755 --- a/qa/rpc-tests/sigma_meetspend.py +++ b/qa/rpc-tests/sigma_meetspend.py @@ -20,7 +20,7 @@ def run_test(self): # Decimal formating: 6 digits for balance will be enought 000.000 getcontext().prec = 6 - self.nodes[0].generate(400) + self.nodes[0].generate(500) self.sync_all() start_bal = self.nodes[0].getbalance() diff --git a/qa/rpc-tests/sigma_mintspend.py b/qa/rpc-tests/sigma_mintspend.py index 59ef7d4847..bbfe4df358 100755 --- a/qa/rpc-tests/sigma_mintspend.py +++ b/qa/rpc-tests/sigma_mintspend.py @@ -19,7 +19,7 @@ def setup_nodes(self): def run_test(self): # Decimal formating: 6 digits for balance will be enought 000.000 getcontext().prec = 6 - self.nodes[0].generate(400) + self.nodes[0].generate(551) self.sync_all() # old denomination @@ -27,7 +27,6 @@ def run_test(self): denoms = [0.1, 0.5, 1, 10, 100] start_bal = self.nodes[0].getbalance() - assert start_bal == 14918.000, 'Unexpected start balance: {}'.format(start_bal) mint_trans = list() for denom in denoms: @@ -146,4 +145,4 @@ def run_test(self): if __name__ == '__main__': - SigmaMintSpendTest().main() \ No newline at end of file + SigmaMintSpendTest().main() diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6cb1523152..4627e2d58e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -253,6 +253,8 @@ class CMainParams : public CChainParams { // Sigma related values. consensus.nSigmaStartBlock = ZC_SIGMA_STARTING_BLOCK; + consensus.nSigmaPaddingBlock = ZC_SIGMA_PADDING_BLOCK; + consensus.nDisableUnpaddedSigmaBlock = ZC_SIGMA_DISABLE_UNPADDED_BLOCK; consensus.nOldSigmaBanBlock = ZC_OLD_SIGMA_BAN_BLOCK; consensus.nZerocoinV2MintMempoolGracefulPeriod = ZC_V2_MINT_GRACEFUL_MEMPOOL_PERIOD; consensus.nZerocoinV2MintGracefulPeriod = ZC_V2_MINT_GRACEFUL_PERIOD; @@ -441,6 +443,8 @@ class CTestNetParams : public CChainParams { // Sigma related values. consensus.nSigmaStartBlock = ZC_SIGMA_TESTNET_STARTING_BLOCK; + consensus.nSigmaPaddingBlock = ZC_SIGMA_TESTNET_PADDING_BLOCK; + consensus.nDisableUnpaddedSigmaBlock = ZC_SIGMA_TESTNET_DISABLE_UNPADDED_BLOCK; consensus.nOldSigmaBanBlock = 70416; consensus.nZerocoinV2MintMempoolGracefulPeriod = ZC_V2_MINT_TESTNET_GRACEFUL_MEMPOOL_PERIOD; consensus.nZerocoinV2MintGracefulPeriod = ZC_V2_MINT_TESTNET_GRACEFUL_PERIOD; @@ -595,6 +599,8 @@ class CRegTestParams : public CChainParams { // Sigma related values. consensus.nSigmaStartBlock = 400; + consensus.nSigmaPaddingBlock = 550; + consensus.nDisableUnpaddedSigmaBlock = 510; consensus.nOldSigmaBanBlock = 450; consensus.nZerocoinV2MintMempoolGracefulPeriod = 2; consensus.nZerocoinV2MintGracefulPeriod = 5; diff --git a/src/clientversion.h b/src/clientversion.h index 94949d058c..32ad33471f 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,7 +17,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 13 #define CLIENT_VERSION_REVISION 8 -#define CLIENT_VERSION_BUILD 5 +#define CLIENT_VERSION_BUILD 8 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/consensus/params.h b/src/consensus/params.h index 5e6adf803d..e899c7e4fe 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -128,6 +128,10 @@ struct Params { // The block number after which sigma are accepted. int nSigmaStartBlock; + int nSigmaPaddingBlock; + + int nDisableUnpaddedSigmaBlock; + // The block number after which old sigma clients are banned. int nOldSigmaBanBlock; diff --git a/src/exodus/rpctx.cpp b/src/exodus/rpctx.cpp index a64b77f30a..a8fcb7d3a0 100644 --- a/src/exodus/rpctx.cpp +++ b/src/exodus/rpctx.cpp @@ -1711,7 +1711,10 @@ UniValue exodus_sendspend(const UniValue& params, bool fHelp) std::vector payload; try { - auto spend = wallet->CreateSigmaSpend(propertyId, denomination); + + bool fPadding = chainActive.Height() >= ::Params().GetConsensus().nSigmaPaddingBlock; + + auto spend = wallet->CreateSigmaSpend(propertyId, denomination, fPadding); mint = spend.mint; payload = CreatePayload_SimpleSpend( diff --git a/src/exodus/sigma.cpp b/src/exodus/sigma.cpp index 1592dee3e3..d362a9644b 100644 --- a/src/exodus/sigma.cpp +++ b/src/exodus/sigma.cpp @@ -16,7 +16,8 @@ bool VerifySigmaSpend( SigmaDenomination denomination, SigmaMintGroup group, size_t groupSize, - const SigmaProof& proof) + const SigmaProof& proof, + bool fPadding) { std::vector anonimitySet; // Don't preallocate the vector due to it will allow attacker to crash all client. @@ -30,7 +31,7 @@ bool VerifySigmaSpend( return false; } - return proof.Verify(anonimitySet.begin(), anonimitySet.end()); + return proof.Verify(anonimitySet.begin(), anonimitySet.end(), fPadding); } } // namespace exodus diff --git a/src/exodus/sigma.h b/src/exodus/sigma.h index c8d86b7b47..18b43b263c 100644 --- a/src/exodus/sigma.h +++ b/src/exodus/sigma.h @@ -13,7 +13,8 @@ bool VerifySigmaSpend( SigmaDenomination denomination, SigmaMintGroup group, size_t groupSize, - const SigmaProof& proof); + const SigmaProof& proof, + bool fPadding); } // namespace exodus diff --git a/src/exodus/sigmaprimitives.h b/src/exodus/sigmaprimitives.h index df4085e1cb..185e3b9e79 100644 --- a/src/exodus/sigmaprimitives.h +++ b/src/exodus/sigmaprimitives.h @@ -113,10 +113,10 @@ class SigmaProof explicit SigmaProof(const SigmaParams& params); template - SigmaProof(const SigmaParams& params, const SigmaPrivateKey& key, PublicKey first, PublicKey last) : + SigmaProof(const SigmaParams& params, const SigmaPrivateKey& key, PublicKey first, PublicKey last, bool fPadding) : SigmaProof(params) { - Generate(key, first, last); + Generate(key, first, last, fPadding); } public: @@ -125,7 +125,7 @@ class SigmaProof public: template - bool Verify(PublicKey first, PublicKey last) const + bool Verify(PublicKey first, PublicKey last, bool fPadding) const { // Create commitment set. auto gs = (params.g * serial).inverse(); @@ -145,12 +145,12 @@ class SigmaProof params.m ); - return verifier.verify(commits, proof); + return verifier.verify(commits, proof, fPadding); } public: template - void Generate(const SigmaPrivateKey& priv, PublicKey first, PublicKey last) + void Generate(const SigmaPrivateKey& priv, PublicKey first, PublicKey last, bool fPadding) { if (!priv.IsValid()) { throw std::invalid_argument("Private key is not valid"); @@ -186,7 +186,7 @@ class SigmaProof params.m ); - prover.proof(commits, *index, priv.randomness, proof); + prover.proof(commits, *index, priv.randomness, fPadding, proof); serial = priv.serial; } diff --git a/src/exodus/test/create_payload_tests.cpp b/src/exodus/test/create_payload_tests.cpp index 5ec92dd6fd..a7bdbb0de9 100644 --- a/src/exodus/test/create_payload_tests.cpp +++ b/src/exodus/test/create_payload_tests.cpp @@ -560,7 +560,7 @@ BOOST_AUTO_TEST_CASE(payload_create_simple_spend) key1.Generate(); key2.Generate(); anonimitySet = { SigmaPublicKey(key1, params), SigmaPublicKey(key2, params) }; - spend.Generate(key1, anonimitySet.begin(), anonimitySet.end()); + spend.Generate(key1, anonimitySet.begin(), anonimitySet.end(), false); buffer << spend; std::vector payload; diff --git a/src/exodus/test/sigma_tests.cpp b/src/exodus/test/sigma_tests.cpp index 7c5ef3ac39..d7422e2bfd 100644 --- a/src/exodus/test/sigma_tests.cpp +++ b/src/exodus/test/sigma_tests.cpp @@ -65,7 +65,7 @@ BOOST_FIXTURE_TEST_CASE(verify_spend, SigmaDatabaseFixture) anonimitySet.push_back(mint); } - proof.Generate(key, anonimitySet.begin(), anonimitySet.end()); + proof.Generate(key, anonimitySet.begin(), anonimitySet.end(), false); // Generate spendable group. for (unsigned i = 0; i < sigmaDb->groupSize; i++) { @@ -91,13 +91,13 @@ BOOST_FIXTURE_TEST_CASE(verify_spend, SigmaDatabaseFixture) sigmaDb->RecordMint(3, 0, mint, block); } - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size(), proof), true); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() - 1, proof), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() + 1, proof), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, sigmaDb->groupSize + 1, proof), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 1, 0, sigmaDb->groupSize, proof), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(4, 0, 0, sigmaDb->groupSize, proof), false); - BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 1, sigmaDb->groupSize, proof), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size(), proof, false), true); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() - 1, proof, false), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, anonimitySet.size() + 1, proof, false), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 0, sigmaDb->groupSize + 1, proof, false), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 1, 0, sigmaDb->groupSize, proof, false), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(4, 0, 0, sigmaDb->groupSize, proof, false), false); + BOOST_CHECK_EQUAL(VerifySigmaSpend(3, 0, 1, sigmaDb->groupSize, proof, false), false); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/exodus/test/sigmaprimitives_tests.cpp b/src/exodus/test/sigmaprimitives_tests.cpp index 3f133ee550..145208dd93 100644 --- a/src/exodus/test/sigmaprimitives_tests.cpp +++ b/src/exodus/test/sigmaprimitives_tests.cpp @@ -107,10 +107,10 @@ BOOST_AUTO_TEST_CASE(proof) SigmaPublicKey(key3, params) }); - proof.Generate(key2, pubs.begin(), pubs.end()); + proof.Generate(key2, pubs.begin(), pubs.end(), false); - BOOST_CHECK_EQUAL(proof.Verify(pubs.begin(), pubs.end()), true); - BOOST_CHECK_EQUAL(proof.Verify(pubs.begin(), pubs.end() - 1), false); + BOOST_CHECK_EQUAL(proof.Verify(pubs.begin(), pubs.end(), false), true); + BOOST_CHECK_EQUAL(proof.Verify(pubs.begin(), pubs.end() - 1, false), false); } BOOST_AUTO_TEST_CASE(spend_with_large_anonimity_group) @@ -129,11 +129,11 @@ BOOST_AUTO_TEST_CASE(spend_with_large_anonimity_group) } SigmaProof validProof(params), invalidProof(params); - validProof.Generate(key, pubs.begin() + 1, pubs.end()); // prove with 2 ^ 14 coins - invalidProof.Generate(key, pubs.begin(), pubs.end()); // prove with 2 ^ 14 + 1 coins + validProof.Generate(key, pubs.begin() + 1, pubs.end(), false); // prove with 2 ^ 14 coins + invalidProof.Generate(key, pubs.begin(), pubs.end(), false); // prove with 2 ^ 14 + 1 coins - BOOST_CHECK_EQUAL(validProof.Verify(pubs.begin() + 1, pubs.end()), true); - BOOST_CHECK_EQUAL(invalidProof.Verify(pubs.begin(), pubs.end()), false); + BOOST_CHECK_EQUAL(validProof.Verify(pubs.begin() + 1, pubs.end(), false), true); + BOOST_CHECK_EQUAL(invalidProof.Verify(pubs.begin(), pubs.end(), false), false); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/exodus/test/wallet_tests.cpp b/src/exodus/test/wallet_tests.cpp index 4b3acea839..1bd1c04e9b 100644 --- a/src/exodus/test/wallet_tests.cpp +++ b/src/exodus/test/wallet_tests.cpp @@ -124,22 +124,22 @@ BOOST_AUTO_TEST_CASE(sigma_mint_create_multi) BOOST_AUTO_TEST_CASE(sigma_spend_create_no_spendable_mint) { // No any mints. - BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0), InsufficientFunds); + BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0, false), InsufficientFunds); // Different denomination and property type. auto mintId = wallet->CreateSigmaMint(3, 0); - BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 1), InsufficientFunds); - BOOST_CHECK_THROW(wallet->CreateSigmaSpend(4, 0), InsufficientFunds); + BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 1, false), InsufficientFunds); + BOOST_CHECK_THROW(wallet->CreateSigmaSpend(4, 0, false), InsufficientFunds); // Pending mint. - BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0), InsufficientFunds); + BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0, false), InsufficientFunds); // Already spent. sigmaDb->RecordMint(3, 0, mintId.pubKey, 100); wallet->SetSigmaMintUsedTransaction(mintId, uint256S("890e968f9b65dbacd576100c9b1c446f06471ed27df845ab7a24931cb640b388")); - BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0), InsufficientFunds); + BOOST_CHECK_THROW(wallet->CreateSigmaSpend(3, 0, false), InsufficientFunds); } BOOST_AUTO_TEST_CASE(sigma_spend_create_with_spendable_mints) @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(sigma_spend_create_with_spendable_mints) sigmaDb->RecordMint(3, 0, mintid.pubKey, 100 + i); } - auto spend = wallet->CreateSigmaSpend(3, 0); + auto spend = wallet->CreateSigmaSpend(3, 0, false); BOOST_CHECK_EQUAL(spend.mint, expectedMintId); BOOST_CHECK_EQUAL(spend.group, 0); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(sigma_spend_create_not_enough_anonimity) auto mintId = wallet->CreateSigmaMint(3, 0); sigmaDb->RecordMint(3, 0, mintId.pubKey, 100); - BOOST_CHECK_EXCEPTION(wallet->CreateSigmaSpend(3, 0), WalletError, [] (const WalletError& e) { + BOOST_CHECK_EXCEPTION(wallet->CreateSigmaSpend(3, 0, false), WalletError, [] (const WalletError& e) { return e.what() == std::string("Amount of coins in anonimity set is not enough to spend"); }); } diff --git a/src/exodus/test/walletmodels_tests.cpp b/src/exodus/test/walletmodels_tests.cpp index 38e87a45cc..cc709d4416 100644 --- a/src/exodus/test/walletmodels_tests.cpp +++ b/src/exodus/test/walletmodels_tests.cpp @@ -335,7 +335,7 @@ BOOST_AUTO_TEST_CASE(sigma_spend_init) SigmaMint mint(3, 0, Hash160({0x00}), Hash160({0x01})); std::vector anonimitySet = { pub1, pub2 }; - SigmaProof proof(params, key1, anonimitySet.begin(), anonimitySet.end()); + SigmaProof proof(params, key1, anonimitySet.begin(), anonimitySet.end(), false); SigmaSpend spend(id, 1, 100, proof); BOOST_CHECK_EQUAL(spend.mint, id); diff --git a/src/exodus/txprocessor.cpp b/src/exodus/txprocessor.cpp index 26118855e3..3de5cc9f96 100644 --- a/src/exodus/txprocessor.cpp +++ b/src/exodus/txprocessor.cpp @@ -158,12 +158,14 @@ int TxProcessor::ProcessSimpleSpend(const CMPTransaction& tx) auto group = tx.getGroup(); auto groupSize = tx.getGroupSize(); + bool const fPadding = block >= ::Params().GetConsensus().nSigmaPaddingBlock; + assert(spend); // check serial in database uint256 spendTx; if (sigmaDb->HasSpendSerial(property, denomination, spend->serial, spendTx) - || !VerifySigmaSpend(property, denomination, group, groupSize, *spend)) { + || !VerifySigmaSpend(property, denomination, group, groupSize, *spend, fPadding)) { PrintToLog("%s(): rejected: spend is invalid\n", __func__); return PKT_ERROR_SIGMA - 907; } diff --git a/src/exodus/wallet.cpp b/src/exodus/wallet.cpp index 8827b08b11..b25d644b4c 100644 --- a/src/exodus/wallet.cpp +++ b/src/exodus/wallet.cpp @@ -77,7 +77,7 @@ void Wallet::ClearAllChainState() mintWallet.ClearMintsChainState(); } -SigmaSpend Wallet::CreateSigmaSpend(PropertyId property, SigmaDenomination denomination) +SigmaSpend Wallet::CreateSigmaSpend(PropertyId property, SigmaDenomination denomination, bool fPadding) { LOCK(cs_main); @@ -102,9 +102,9 @@ SigmaSpend Wallet::CreateSigmaSpend(PropertyId property, SigmaDenomination denom // Create spend. auto key = GetKey(mint.get()); - SigmaProof proof(DefaultSigmaParams, key, anonimitySet.begin(), anonimitySet.end()); + SigmaProof proof(DefaultSigmaParams, key, anonimitySet.begin(), anonimitySet.end(), fPadding); - if (!VerifySigmaSpend(mint->property, mint->denomination, mint->chainState.group, anonimitySet.size(), proof)) { + if (!VerifySigmaSpend(mint->property, mint->denomination, mint->chainState.group, anonimitySet.size(), proof, fPadding)) { throw WalletError(_("Failed to create spendable spend")); } diff --git a/src/exodus/wallet.h b/src/exodus/wallet.h index bfe657e6b4..5e3aeb3ba7 100644 --- a/src/exodus/wallet.h +++ b/src/exodus/wallet.h @@ -46,7 +46,7 @@ class Wallet void ClearAllChainState(); - SigmaSpend CreateSigmaSpend(PropertyId property, SigmaDenomination denomination); + SigmaSpend CreateSigmaSpend(PropertyId property, SigmaDenomination denomination, bool fPadding); void DeleteUnconfirmedSigmaMint(SigmaMintId const &id); public: diff --git a/src/hdmint/wallet.cpp b/src/hdmint/wallet.cpp index df39f29a11..dc6394fe54 100644 --- a/src/hdmint/wallet.cpp +++ b/src/hdmint/wallet.cpp @@ -321,8 +321,10 @@ void CHDMintWallet::SyncWithChain(bool fGenerateMintPool, boost::optionalGetBlockTime(); @@ -416,8 +418,10 @@ bool CHDMintWallet::SetMintSeedSeen(std::pair mintPoolEnt CWalletTx wtx(pwalletMain, txSpend); CBlockIndex* pindex = chainActive[nHeightTx]; CBlock block; - if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) + if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { + LOCK(cs_main); wtx.SetMerkleBranch(block); + } wtx.nTimeReceived = pindex->nTime; pwalletMain->AddToWallet(wtx, false, &walletdb); diff --git a/src/libzerocoin/Zerocoin.h b/src/libzerocoin/Zerocoin.h index 45e6ba43d5..a03b3694ea 100644 --- a/src/libzerocoin/Zerocoin.h +++ b/src/libzerocoin/Zerocoin.h @@ -39,6 +39,7 @@ #define ZEROCOIN_TX_VERSION_2 2 #define ZEROCOIN_TX_VERSION_1_5 15 #define ZEROCOIN_TX_VERSION_3 30 +#define ZEROCOIN_TX_VERSION_3_1 31 // Activate multithreaded mode for proof verification #define ZEROCOIN_THREADING 1 diff --git a/src/main.cpp b/src/main.cpp index 5766efddd9..0f4edf2715 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4038,6 +4038,20 @@ bool ActivateBestChain(CValidationState &state, const CChainParams &chainparams, return false; } + //clear all old sigma spend transaction from mempool, to stat padding + if (chainActive.Height() == ::Params().GetConsensus().nSigmaPaddingBlock) { + LOCK2(cs_main, mempool.cs); + for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); + mi != mempool.mapTx.end(); ++mi) + { + auto tx = mi->GetTx(); + if(tx.IsSigmaSpend()) { + std::list removed; + mempool.removeRecursive(tx, removed); + } + } + } + return true; } diff --git a/src/miner.cpp b/src/miner.cpp index fb86a6898f..7def8a1ca4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -414,6 +414,9 @@ CBlockTemplate* BlockAssembler::CreateNewBlock( if (!chainparams.GetConsensus().IsRegtest() && (tx.IsZerocoinSpend() || tx.IsZerocoinMint())) continue; + if(tx.IsSigmaSpend() && nHeight >= chainparams.GetConsensus().nDisableUnpaddedSigmaBlock && nHeight < chainparams.GetConsensus().nSigmaPaddingBlock) + continue; + if (tx.IsSigmaSpend() || tx.IsZerocoinRemint()) { // Sigma spend and zerocoin->sigma remint are subject to the same limits CAmount spendAmount = tx.IsSigmaSpend() ? sigma::GetSpendAmount(tx) : sigma::CoinRemintToV3::GetAmount(tx); diff --git a/src/qt/sigmadialog.cpp b/src/qt/sigmadialog.cpp index a186791ebe..5e5f29e2d8 100644 --- a/src/qt/sigmadialog.cpp +++ b/src/qt/sigmadialog.cpp @@ -714,6 +714,10 @@ void SigmaDialog::processSpendCoinsReturn(const WalletModel::SendCoinsReturn &se case WalletModel::DuplicateAddress: msgParams.first = tr("Duplicate address found: addresses should only be used once each."); break; + case WalletModel::SigmaDisabled: + msgParams.first = tr("Sigma is disabled at this period!"); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; case WalletModel::TransactionCreationFailed: msgParams.first = tr("Transaction creation failed!"); msgParams.second = CClientUIInterface::MSG_ERROR; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 95f3fd6b4e..e5fe223e95 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -875,6 +875,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareSigmaSpendTransaction( } catch (const std::runtime_error& err) { if (_("Can not choose coins within limit.") == err.what()) return ExceedLimit; + if (_("Sigma is disabled at this period.") == err.what()) + return SigmaDisabled; throw err; } catch (const std::invalid_argument& err) { return ExceedLimit; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 1c186917eb..49bbc1abfe 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -115,6 +115,7 @@ class WalletModel : public QObject AmountExceedsBalance, AmountWithFeeExceedsBalance, DuplicateAddress, + SigmaDisabled, TransactionCreationFailed, // Error returned when wallet is still locked TransactionCommitFailed, AbsurdFee, diff --git a/src/secp256k1/include/GroupElement.h b/src/secp256k1/include/GroupElement.h index 3ebfb7ffb8..b4048acc17 100644 --- a/src/secp256k1/include/GroupElement.h +++ b/src/secp256k1/include/GroupElement.h @@ -52,6 +52,8 @@ class GroupElement final { bool isMember() const; + bool isInfinity() const; + GroupElement& generate(unsigned char* seed); void sha256(unsigned char* result) const; diff --git a/src/secp256k1/include/Scalar.h b/src/secp256k1/include/Scalar.h index 10daed4fc8..f8b5c53f78 100644 --- a/src/secp256k1/include/Scalar.h +++ b/src/secp256k1/include/Scalar.h @@ -71,6 +71,8 @@ class Scalar final { bool isMember() const; + bool isZero() const; + // Returns the secp object inside it. const void * get_value() const; diff --git a/src/secp256k1/src/cpp/GroupElement.cpp b/src/secp256k1/src/cpp/GroupElement.cpp index a548dad0e5..0abfc7b0e2 100644 --- a/src/secp256k1/src/cpp/GroupElement.cpp +++ b/src/secp256k1/src/cpp/GroupElement.cpp @@ -331,6 +331,11 @@ bool GroupElement::isMember() const return secp256k1_ge_is_valid_var(&v1); } +bool GroupElement::isInfinity() const +{ + return secp256k1_gej_is_infinity(reinterpret_cast(g_)); +} + void GroupElement::randomize() { unsigned char temp[32] = { 0 }; diff --git a/src/secp256k1/src/cpp/Scalar.cpp b/src/secp256k1/src/cpp/Scalar.cpp index d66ae6b0db..9ac99563e2 100644 --- a/src/secp256k1/src/cpp/Scalar.cpp +++ b/src/secp256k1/src/cpp/Scalar.cpp @@ -181,7 +181,11 @@ bool Scalar::isMember() const { return *this == temp; } -Scalar& Scalar::memberFromSeed(unsigned char* seed){ +bool Scalar::isZero() const { + return secp256k1_scalar_is_zero(reinterpret_cast(value_)); +} + +Scalar& Scalar::memberFromSeed(unsigned char* seed) { // buffer -> object deserialize(seed); do { diff --git a/src/sigma.cpp b/src/sigma.cpp index 176c12ede2..2c751a582d 100644 --- a/src/sigma.cpp +++ b/src/sigma.cpp @@ -213,7 +213,7 @@ bool CheckSigmaSpendTransaction( "CheckSigmaSpendTransaction: invalid spend transaction"); } - if (spend->getVersion() != ZEROCOIN_TX_VERSION_3) { + if (spend->getVersion() != ZEROCOIN_TX_VERSION_3 && spend->getVersion() != ZEROCOIN_TX_VERSION_3_1) { return state.DoS(100, false, NSEQUENCE_INCORRECT, @@ -275,7 +275,19 @@ bool CheckSigmaSpendTransaction( index = index->pprev; } - passVerify = spend->Verify(anonymity_set, newMetaData); + bool fPadding = spend->getVersion() >= ZEROCOIN_TX_VERSION_3_1; + if (!isVerifyDB) { + auto params = ::Params().GetConsensus(); + bool fShouldPad = (nHeight != INT_MAX && nHeight >= params.nSigmaPaddingBlock) || + (nHeight == INT_MAX && chainActive.Height() >= params.nSigmaPaddingBlock); + //Accept both padded and not padded spends at HF block + if(nHeight == params.nSigmaPaddingBlock) + fShouldPad = fPadding; + if (fPadding != fShouldPad) + return state.DoS(1, error("Incorrect sigma spend transaction version")); + } + + passVerify = spend->Verify(anonymity_set, newMetaData, fPadding); if (passVerify) { Scalar serial = spend->getCoinSerialNumber(); // do not check for duplicates in case we've seen exact copy of this tx in this block before @@ -409,6 +421,9 @@ bool CheckSigmaTransaction( realHeight = chainActive.Height(); } + if(tx.IsSigmaSpend() && realHeight >= consensus.nDisableUnpaddedSigmaBlock && realHeight < consensus.nSigmaPaddingBlock) + return state.DoS(100, error("Sigma is bisabled at this period.")); + bool allowSigma = (realHeight >= consensus.nSigmaStartBlock); if (allowSigma && sigmaState.IsSurgeConditionDetected()) { diff --git a/src/sigma/coin.cpp b/src/sigma/coin.cpp index faebc74d6b..97344cc5f0 100644 --- a/src/sigma/coin.cpp +++ b/src/sigma/coin.cpp @@ -194,7 +194,7 @@ bool PublicCoin::operator!=(const PublicCoin& other) const{ } bool PublicCoin::validate() const{ - return this->value.isMember(); + return this->value.isMember() && !this->value.isInfinity(); } size_t PublicCoin::GetSerializeSize(int nType, int nVersion) const{ diff --git a/src/sigma/coinspend.cpp b/src/sigma/coinspend.cpp index eb42060bf6..c826b0f264 100644 --- a/src/sigma/coinspend.cpp +++ b/src/sigma/coinspend.cpp @@ -8,7 +8,8 @@ CoinSpend::CoinSpend( const Params* p, const PrivateCoin& coin, const std::vector& anonymity_set, - const SpendMetaData& m) + const SpendMetaData& m, + bool fPadding) : params(p), denomination(coin.getPublicCoin().getDenomination()), @@ -45,7 +46,7 @@ CoinSpend::CoinSpend( if(!indexFound) throw ZerocoinException("No such coin in this anonymity set"); - sigmaProver.proof(C_, coinIndex, coin.getRandomness(), sigmaProof); + sigmaProver.proof(C_, coinIndex, coin.getRandomness(), fPadding, sigmaProof); updateMetaData(coin, m); } @@ -98,7 +99,8 @@ uint256 CoinSpend::signatureHash(const SpendMetaData& m) const { bool CoinSpend::Verify( const std::vector& anonymity_set, - const SpendMetaData& m) const { + const SpendMetaData& m, + bool fPadding) const { SigmaPlusVerifier sigmaVerifier(params->get_g(), params->get_h(), params->get_n(), params->get_m()); //compute inverse of g^s GroupElement gs = (params->get_g() * coinSerialNumber).inverse(); @@ -143,7 +145,7 @@ bool CoinSpend::Verify( } // Now verify the sigma proof itself. - return sigmaVerifier.verify(C_, sigmaProof); + return sigmaVerifier.verify(C_, sigmaProof, fPadding); } const Scalar& CoinSpend::getCoinSerialNumber() { @@ -161,7 +163,7 @@ int64_t CoinSpend::getIntDenomination() const { } bool CoinSpend::HasValidSerial() const { - return coinSerialNumber.isMember(); + return coinSerialNumber.isMember() && !coinSerialNumber.isZero(); } } //namespace sigma diff --git a/src/sigma/coinspend.h b/src/sigma/coinspend.h index e860f61dff..6d88a597db 100644 --- a/src/sigma/coinspend.h +++ b/src/sigma/coinspend.h @@ -25,7 +25,8 @@ class CoinSpend { CoinSpend(const Params* p, const PrivateCoin& coin, const std::vector& anonymity_set, - const SpendMetaData& m); + const SpendMetaData& m, + bool fPadding); void updateMetaData(const PrivateCoin& coin, const SpendMetaData& m); @@ -49,7 +50,7 @@ class CoinSpend { bool HasValidSerial() const; - bool Verify(const std::vector& anonymity_set, const SpendMetaData &m) const; + bool Verify(const std::vector& anonymity_set, const SpendMetaData &m, bool fPadding) const; ADD_SERIALIZE_METHODS; template diff --git a/src/sigma/r1_proof_generator.hpp b/src/sigma/r1_proof_generator.hpp index 3513cd99c5..0d56b731f2 100644 --- a/src/sigma/r1_proof_generator.hpp +++ b/src/sigma/r1_proof_generator.hpp @@ -35,7 +35,6 @@ void R1ProofGenerator::proof( std::vector& a_out, R1Proof& proof_out, bool skip_final_response) { - rA_.randomize(); rC_.randomize(); rD_.randomize(); a_out.resize(n_ * m_); @@ -50,7 +49,10 @@ void R1ProofGenerator::proof( //compute A GroupElement A; - SigmaPrimitives::commit(g_, h_, a_out, rA_, A); + while(!A.isMember() || A.isInfinity()) { + rA_.randomize(); + SigmaPrimitives::commit(g_, h_, a_out, rA_, A); + } proof_out.A_ = A; //compute C @@ -60,7 +62,10 @@ void R1ProofGenerator::proof( c[i] = (a_out[i] * (Exponent(uint64_t(1)) - (Exponent(uint64_t(2)) * b_[i]))); } GroupElement C; - SigmaPrimitives::commit(g_, h_, c, rC_, C); + while(!C.isMember() || C.isInfinity()) { + rC_.randomize(); + SigmaPrimitives::commit(g_, h_, c, rC_, C); + } proof_out.C_ = C; //compute D @@ -70,8 +75,10 @@ void R1ProofGenerator::proof( d[i] = ((a_out[i].square()).negate()); } GroupElement D; - SigmaPrimitives::commit(g_,h_, d, rD_, D); - + while(!D.isMember() || D.isInfinity()) { + rD_.randomize(); + SigmaPrimitives::commit(g_, h_, d, rD_, D); + } proof_out.D_ = D; if (!skip_final_response) { diff --git a/src/sigma/r1_proof_verifier.hpp b/src/sigma/r1_proof_verifier.hpp index 44795f94db..b7ddcffb6d 100644 --- a/src/sigma/r1_proof_verifier.hpp +++ b/src/sigma/r1_proof_verifier.hpp @@ -29,18 +29,24 @@ bool R1ProofVerifier::verify( bool skip_final_response_verification) const{ if(!(proof.A_.isMember() && - B_Commit.isMember() && + B_Commit.isMember() && proof.C_.isMember() && - proof.D_.isMember())) + proof.D_.isMember()) || + (proof.A_.isInfinity() || + B_Commit.isInfinity() || + proof.C_.isInfinity() || + proof.D_.isInfinity())) return false; const std::vector& f = proof.f_; for (std::size_t i = 0; i < f.size(); i++) { - if(!f[i].isMember()) + if(!f[i].isMember() || f[i].isZero()) return false; } if(!(proof.ZA_.isMember() && - proof.ZC_.isMember())) + proof.ZC_.isMember()) || + (proof.ZA_.isZero() || + proof.ZC_.isZero())) return false; if (!skip_final_response_verification) { @@ -58,6 +64,12 @@ bool R1ProofVerifier::verify_final_response( const Exponent& challenge_x, std::vector& f_out) const { const std::vector& f = proof.f_; + + for(unsigned int j = 0; j < f.size(); ++j) { + if(f[j] == challenge_x) + return false; + } + f_out.clear(); f_out.reserve(n_ * m_); for(int j = 0; j < m_; ++j) { diff --git a/src/sigma/sigma_primitives.hpp b/src/sigma/sigma_primitives.hpp index 5f706a0072..4666669764 100644 --- a/src/sigma/sigma_primitives.hpp +++ b/src/sigma/sigma_primitives.hpp @@ -85,13 +85,11 @@ void SigmaPrimitives::new_factor( const Exponent& x, const Exponent& a, std::vector& coefficients) { - std::vector temp; - temp.resize(coefficients.size() + 1); - for (std::size_t j = 0; j < coefficients.size(); j++) - temp[j] = x * coefficients[j]; - for(std::size_t j = 0; j < coefficients.size(); j++) - temp[j + 1] += a * coefficients[j]; - coefficients = std::move(temp); + std::size_t degree = coefficients.size(); + coefficients.push_back(x * coefficients[degree-1]); + for (std::size_t d = degree-1; d >= 1; --d) + coefficients[d] = a * coefficients[d] + x * coefficients[d-1]; + coefficients[0] *= a; } } // namespace sigma diff --git a/src/sigma/sigmaplus_prover.h b/src/sigma/sigmaplus_prover.h index 046ace315c..d1aebb1757 100644 --- a/src/sigma/sigmaplus_prover.h +++ b/src/sigma/sigmaplus_prover.h @@ -17,6 +17,7 @@ class SigmaPlusProver{ void proof(const std::vector& commits, std::size_t l, const Exponent& r, + bool fPadding, SigmaPlusProof& proof_out); private: diff --git a/src/sigma/sigmaplus_prover.hpp b/src/sigma/sigmaplus_prover.hpp index 73763dfead..741ce04e56 100644 --- a/src/sigma/sigmaplus_prover.hpp +++ b/src/sigma/sigmaplus_prover.hpp @@ -1,3 +1,4 @@ +#include namespace sigma { template @@ -17,8 +18,11 @@ void SigmaPlusProver::proof( const std::vector& commits, std::size_t l, const Exponent& r, + bool fPadding, SigmaPlusProof& proof_out) { - std::size_t N = commits.size(); + std::size_t setSize = commits.size(); + assert(setSize > 0); + Exponent rB; rB.randomize(); @@ -38,17 +42,70 @@ void SigmaPlusProver::proof( r1prover.proof(a, proof_out.r1Proof_, true /*Skip generation of final response*/); // Compute coefficients of Polynomials P_I(x), for all I from [0..N]. + std::size_t N = setSize; std::vector > P_i_k; P_i_k.resize(N); - for (std::size_t i = 0; i < N; ++i) { + + // last polynomial is special case if fPadding is true + for (std::size_t i = 0; i < (fPadding ? N-1 : N); ++i) { std::vector& coefficients = P_i_k[i]; std::vector I = SigmaPrimitives::convert_to_nal(i, n_, m_); - coefficients.push_back(sigma[I[0]]); coefficients.push_back(a[I[0]]); + coefficients.push_back(sigma[I[0]]); for (int j = 1; j < m_; ++j) { SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], coefficients); } - std::reverse(coefficients.begin(), coefficients.end()); + } + + if (fPadding) { + /* + * To optimize calculation of sum of all polynomials indices 's' = setSize-1 through 'n^m-1' we use the + * fact that sum of all of elements in each row of 'a' array is zero. Computation is done by going + * through n-ary representation of 's' and increasing "digit" at each position to 'n-1' one by one. + * During every step digits at higher positions are fixed and digits at lower positions go through all + * possible combinations with a total corresponding polynomial sum of 'x^j'. + * + * The math behind optimization (TeX notation): + * + * \sum_{i=s+1}^{N-1}p_i(x) = + * \sum_{j=0}^{m-1} + * \left[ + * \left( \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) \right) + * \left( \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k}) \right) + * x^j + * \right] + */ + + std::vector I = SigmaPrimitives::convert_to_nal(N-1, n_, m_); + std::vector lj = SigmaPrimitives::convert_to_nal(l, n_, m_); + + std::vector p_i_sum; + p_i_sum.emplace_back(uint64_t(1)); + std::vector> partial_p_s; + + // Pre-calculate product parts and calculate p_s(x) at the same time, put the latter into p_i_sum + for (int j = m_ - 1; j >= 0; j--) { + partial_p_s.push_back(p_i_sum); + SigmaPrimitives::new_factor(sigma[j * n_ + I[j]], a[j * n_ + I[j]], p_i_sum); + } + + for (int j = 0; j < m_; j++) { + // \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) + Exponent a_sum(uint64_t(0)); + for (int i = I[j] + 1; i < n_; i++) + a_sum += a[j * n_ + i]; + Exponent x_sum(uint64_t(lj[j] >= I[j]+1 ? 1 : 0)); + + // Multiply by \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k}) + std::vector &polynomial = partial_p_s[m_ - j - 1]; + SigmaPrimitives::new_factor(x_sum, a_sum, polynomial); + + // Multiply by x^j and add to the result + for (int k = 0; k < m_ - j; k++) + p_i_sum[j + k] += polynomial[k]; + } + + P_i_k[N-1] = p_i_sum; } //computing G_k`s; diff --git a/src/sigma/sigmaplus_verifier.h b/src/sigma/sigmaplus_verifier.h index 19fe073aeb..72f6c97324 100644 --- a/src/sigma/sigmaplus_verifier.h +++ b/src/sigma/sigmaplus_verifier.h @@ -14,7 +14,8 @@ class SigmaPlusVerifier{ int n, int m_); bool verify(const std::vector& commits, - const SigmaPlusProof& proof) const; + const SigmaPlusProof& proof, + bool fPadding) const; private: GroupElement g_; diff --git a/src/sigma/sigmaplus_verifier.hpp b/src/sigma/sigmaplus_verifier.hpp index 1b4701a9ba..e0117cd009 100644 --- a/src/sigma/sigmaplus_verifier.hpp +++ b/src/sigma/sigmaplus_verifier.hpp @@ -1,3 +1,4 @@ +#include namespace sigma{ template SigmaPlusVerifier::SigmaPlusVerifier( @@ -14,7 +15,8 @@ SigmaPlusVerifier::SigmaPlusVerifier( template bool SigmaPlusVerifier::verify( const std::vector& commits, - const SigmaPlusProof& proof) const { + const SigmaPlusProof& proof, + bool fPadding) const { R1ProofVerifier r1ProofVerifier(g_, h_, proof.B_, n, m); std::vector f; @@ -24,14 +26,14 @@ bool SigmaPlusVerifier::verify( return false; } - if (!(proof.B_).isMember()) { + if (!proof.B_.isMember() || proof.B_.isInfinity()) { LogPrintf("Sigma spend failed due to value of B outside of group."); return false; } const std::vector & Gk = proof.Gk_; for (int k = 0; k < m; ++k) { - if (!Gk[k].isMember()) { + if (!Gk[k].isMember() || Gk[k].isInfinity()) { LogPrintf("Sigma spend failed due to value of GK[i] outside of group."); return false; } @@ -51,15 +53,22 @@ bool SigmaPlusVerifier::verify( return false; } - if(!proof.z_.isMember()) { + if(!proof.z_.isMember() || proof.z_.isZero()) { LogPrintf("Sigma spend failed due to value of Z outside of group."); return false; } - int N = commits.size(); + if (commits.empty()) { + LogPrintf("No mints in the anonymity set"); + return false; + } + + std::size_t N = commits.size(); std::vector f_i_; f_i_.reserve(N); - for(int i = 0; i < N; ++i) { + + // if fPadding is true last index is special + for (std::size_t i = 0; i < (fPadding ? N-1 : N); ++i) { std::vector I = SigmaPrimitives::convert_to_nal(i, n, m); Exponent f_i(uint64_t(1)); for(int j = 0; j < m; ++j){ @@ -68,8 +77,44 @@ bool SigmaPlusVerifier::verify( f_i_.emplace_back(f_i); } + if (fPadding) { + /* + * Optimization for getting power for last 'commits' array element is done similarly to the one used in creating + * a proof. The fact that sum of any row in 'f' array is 'x' (challenge value) is used. + * + * Math (in TeX notation): + * + * \sum_{i=s+1}^{N-1} \prod_{j=0}^{m-1}f_{j,i_j} = + * \sum_{j=0}^{m-1} + * \left[ + * \left( \sum_{i=s_j+1}^{n-1}f_{j,i} \right) + * \left( \prod_{k=j}^{m-1}f_{k,s_k} \right) + * x^j + * \right] + */ + + Exponent pow(uint64_t(1)); + std::vector I = SigmaPrimitives::convert_to_nal(N - 1, n, m); + vector f_part_product; // partial product of f array elements for lastIndex + for (int j = m - 1; j >= 0; j--) { + f_part_product.push_back(pow); + pow *= f[j * n + I[j]]; + } + + Exponent xj(uint64_t(1));; // x^j + for (int j = 0; j < m; j++) { + Exponent fi_sum(uint64_t(0)); + for (int i = I[j] + 1; i < n; i++) + fi_sum += f[j*n + i]; + pow += fi_sum * xj * f_part_product[m - j - 1]; + xj *= challenge_x; + } + f_i_.emplace_back(pow); + } + secp_primitives::MultiExponent mult(commits, f_i_); GroupElement t1 = mult.get_multiple(); + GroupElement t2; Exponent x_k(uint64_t(1)); for(int k = 0; k < m; ++k){ diff --git a/src/sigma/test/coin_spend_tests.cpp b/src/sigma/test/coin_spend_tests.cpp index 0c7ef80f71..52c1fca030 100644 --- a/src/sigma/test/coin_spend_tests.cpp +++ b/src/sigma/test/coin_spend_tests.cpp @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(serialize_deserialize_test) std::vector anonymity_set; anonymity_set.push_back(pubcoin); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); // serialize CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(different_anonymity_set) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params,privcoin,anonymity_set, metaData); - sigma::CoinSpend coin2(params,privcoin,anonymity_set, metaData); + sigma::CoinSpend coin(params,privcoin,anonymity_set, metaData, true); + sigma::CoinSpend coin2(params,privcoin,anonymity_set, metaData, true); BOOST_CHECK(coin.getCoinSerialNumber() == coin2.getCoinSerialNumber()); @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(different_anonymity_set) anonymity_set3.push_back(pubcoin); anonymity_set3.push_back(pubcoin3); - sigma::CoinSpend coin3(params, privcoin, anonymity_set3, metaData); + sigma::CoinSpend coin3(params, privcoin, anonymity_set3, metaData, true); BOOST_CHECK(coin.getCoinSerialNumber() == coin3.getCoinSerialNumber()); } @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(out_of_anonymity_set) sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); // pubcoin of privcoin isn't in [pubcoin3] - BOOST_CHECK_THROW(sigma::CoinSpend(params, privcoin, anonymity_set3, metaData),std::exception); + BOOST_CHECK_THROW(sigma::CoinSpend(params, privcoin, anonymity_set3, metaData, true),std::exception); } BOOST_AUTO_TEST_CASE(verify_test) @@ -109,9 +109,9 @@ BOOST_AUTO_TEST_CASE(verify_test) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData, true); - BOOST_CHECK(spend_coin.Verify(anonymity_set, metaData)); + BOOST_CHECK(spend_coin.Verify(anonymity_set, metaData, true)); } BOOST_AUTO_TEST_CASE(verify_test_valid_set_plus_one) @@ -133,14 +133,14 @@ BOOST_AUTO_TEST_CASE(verify_test_valid_set_plus_one) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend spend_coin(params,privcoin,anonymity_set, metaData); + sigma::CoinSpend spend_coin(params,privcoin,anonymity_set, metaData, true); // [pubcoin,pubcoin2] std::vector anonymity_set2; anonymity_set2.push_back(pubcoin); anonymity_set2.push_back(pubcoin2); - BOOST_CHECK(!spend_coin.Verify(anonymity_set2, metaData)); + BOOST_CHECK(!spend_coin.Verify(anonymity_set2, metaData, true)); } BOOST_AUTO_TEST_CASE(verify_test_valid_set_subtract_one) @@ -163,13 +163,13 @@ BOOST_AUTO_TEST_CASE(verify_test_valid_set_subtract_one) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData, true); // [pubcoin] std::vector anonymity_set2; anonymity_set2.push_back(pubcoin); - BOOST_CHECK(!spend_coin.Verify(anonymity_set2, metaData)); + BOOST_CHECK(!spend_coin.Verify(anonymity_set2, metaData, true)); } BOOST_AUTO_TEST_CASE(verify_test_with_accumulatorBlockHash) @@ -185,9 +185,9 @@ BOOST_AUTO_TEST_CASE(verify_test_with_accumulatorBlockHash) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend spend_coin(params, privcoin, anonymity_set, metaData, true); - BOOST_CHECK(spend_coin.Verify(anonymity_set, metaData)); + BOOST_CHECK(spend_coin.Verify(anonymity_set, metaData, true)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/sigma/test/protocol_tests.cpp b/src/sigma/test/protocol_tests.cpp index 395ce1a931..4e23a1ea91 100644 --- a/src/sigma/test/protocol_tests.cpp +++ b/src/sigma/test/protocol_tests.cpp @@ -43,11 +43,57 @@ BOOST_AUTO_TEST_CASE(one_out_of_n) } sigma::SigmaPlusProof proof(n, m); - prover.proof(commits, index, r, proof); + prover.proof(commits, index, r, true, proof); sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); - BOOST_CHECK(verifier.verify(commits, proof)); + BOOST_CHECK(verifier.verify(commits, proof, true)); +} + +BOOST_AUTO_TEST_CASE(one_out_of_n_padding) +{ + auto params = sigma::Params::get_default(); + int N = 10000; + int n = params->get_n(); + int m = params->get_m(); + int index = 9999; + + secp_primitives::GroupElement g; + g.randomize(); + std::vector h_gens; + h_gens.resize(n * m); + for(int i = 0; i < n * m; ++i ){ + h_gens[i].randomize(); + } + secp_primitives::Scalar r; + r.randomize(); + sigma::SigmaPlusProver prover(g,h_gens, n, m); + + std::vector commits; + for(int i = 0; i < N; ++i){ + if(i == index){ + secp_primitives::GroupElement c; + secp_primitives::Scalar zero(uint64_t(0)); + c = sigma::SigmaPrimitives::commit(g, zero, h_gens[0], r); + commits.push_back(c); + + } + else{ + commits.push_back(secp_primitives::GroupElement()); + commits[i].randomize(); + } + } + sigma::SigmaPlusProof proof(n, m); + + prover.proof(commits, index, r, true, proof); + + sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); + + BOOST_CHECK(verifier.verify(commits, proof, true)); + + sigma::SigmaPlusProof proofNew(n, m); + prover.proof(commits, 11111, r, true, proofNew); + BOOST_CHECK(verifier.verify(commits, proofNew, true)); } BOOST_AUTO_TEST_CASE(prove_and_verify_in_different_set) @@ -86,7 +132,7 @@ BOOST_AUTO_TEST_CASE(prove_and_verify_in_different_set) sigma::SigmaPlusProof proof(n, m); - prover.proof(commits, index, r, proof); + prover.proof(commits, index, r, true, proof); sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); @@ -96,7 +142,7 @@ BOOST_AUTO_TEST_CASE(prove_and_verify_in_different_set) c = sigma::SigmaPrimitives::commit(g, zero, h_gens[0], r); commits.push_back(c); - BOOST_CHECK(!verifier.verify(commits, proof)); + BOOST_CHECK(!verifier.verify(commits, proof, true)); } BOOST_AUTO_TEST_CASE(prove_coin_out_of_index) @@ -125,10 +171,10 @@ BOOST_AUTO_TEST_CASE(prove_coin_out_of_index) sigma::SigmaPlusProof proof(n, m); - prover.proof(commits, commits.size(), r, proof); + prover.proof(commits, commits.size(), r, true, proof); sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); - BOOST_CHECK(!verifier.verify(commits,proof)); + BOOST_CHECK(!verifier.verify(commits, proof, true)); } BOOST_AUTO_TEST_CASE(prove_coin_not_in_set) @@ -157,10 +203,10 @@ BOOST_AUTO_TEST_CASE(prove_coin_not_in_set) sigma::SigmaPlusProof proof(n, m); - prover.proof(commits, index, r, proof); + prover.proof(commits, index, r, true, proof); sigma::SigmaPlusVerifier verifier(g, h_gens, n, m); - BOOST_CHECK(!verifier.verify(commits,proof)); + BOOST_CHECK(!verifier.verify(commits, proof, true)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/sigma/test/serialize_test.cpp b/src/sigma/test/serialize_test.cpp index 18921ab5c8..85f27dab43 100644 --- a/src/sigma/test/serialize_test.cpp +++ b/src/sigma/test/serialize_test.cpp @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(proof_serialize) sigma::SigmaPlusProof initial_proof(n, m); - prover.proof(commits, index, r, initial_proof); + prover.proof(commits, index, r, true, initial_proof); unsigned char buffer [initial_proof.memoryRequired()]; initial_proof.serialize(buffer); diff --git a/src/test/sigma_manymintspend_test.cpp b/src/test/sigma_manymintspend_test.cpp index 048f7782a6..1553a73f23 100644 --- a/src/test/sigma_manymintspend_test.cpp +++ b/src/test/sigma_manymintspend_test.cpp @@ -36,8 +36,8 @@ BOOST_AUTO_TEST_CASE(sigma_mintspend_many) sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState(); - // Create 400-200+1 = 201 new empty blocks. // consensus.nMintV3SigmaStartBlock = 400 - CreateAndProcessEmptyBlocks(201, scriptPubKey); + //200 blocks already mined, create another 350. See Params::nSigmaPaddingBlock + CreateAndProcessEmptyBlocks(350, scriptPubKey); pwalletMain->SetBroadcastTransactions(true); diff --git a/src/test/sigma_state_tests.cpp b/src/test/sigma_state_tests.cpp index e39937ee97..33673da530 100644 --- a/src/test/sigma_state_tests.cpp +++ b/src/test/sigma_state_tests.cpp @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(sigma_addspend) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); auto initSize = sigmaState->GetSpends().count(coinSerial); @@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(sigma_remove_spend_from_mempool_coin_in) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(sigma_remove_spend_from_mempool_coin_not_in) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -347,7 +347,7 @@ BOOST_AUTO_TEST_CASE(sigma_addspend_to_mempool_coin_used) std::vector anonymity_set; anonymity_set.push_back(pubcoin); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -378,7 +378,7 @@ BOOST_AUTO_TEST_CASE(sigma_addspendtomempool) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -405,7 +405,7 @@ BOOST_AUTO_TEST_CASE(sigma_addspendtomempool_coinin) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(sigma_canaddspendtomempool_inmempool) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -467,7 +467,7 @@ BOOST_AUTO_TEST_CASE(sigma_canaddspendtomempool_used) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -507,7 +507,7 @@ BOOST_AUTO_TEST_CASE(sigma_reset) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); auto coinSerial = coin.getCoinSerialNumber(); @@ -646,7 +646,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_sigma_addblock_minted_spend) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coinSpend(params,privcoin1,anonymity_set, metaData); + sigma::CoinSpend coinSpend(params,privcoin1,anonymity_set, metaData, true); auto spendSerial = coinSpend.getCoinSerialNumber(); @@ -702,7 +702,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_sigma_removeblock_remove) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData); + sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData, true); index2.sigmaSpentSerials.clear(); index2.sigmaSpentSerials.insert(std::make_pair(coinSpend.getCoinSerialNumber(), sigma::CSpendCoinInfo::make(coinSpend.getDenomination(), 0))); @@ -784,7 +784,7 @@ BOOST_AUTO_TEST_CASE(zerocoingetspendserialnumberv3_valid_tx_valid_vin) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData); + sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData, true); CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); serializedCoinSpend << coinSpend; @@ -817,7 +817,7 @@ BOOST_AUTO_TEST_CASE(zerocoingetspendserialnumberv3_valid_tx_valid_vin) "Expect serial number, got 0"); // add more spend vin - sigma::CoinSpend coinSpend2(params, coins[1], pubCoins, metaData); + sigma::CoinSpend coinSpend2(params, coins[1], pubCoins, metaData, true); CDataStream serializedCoinSpend2(SER_NETWORK, PROTOCOL_VERSION); serializedCoinSpend2 << coinSpend2; @@ -868,7 +868,7 @@ BOOST_AUTO_TEST_CASE(zerocoingetspendserialnumberv3_invalid_script) // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData); + sigma::CoinSpend coinSpend(params, coins[0], pubCoins, metaData, true); CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); serializedCoinSpend << coinSpend; @@ -1123,7 +1123,7 @@ namespace { // Doesn't really matter what metadata we give here, it must pass. sigma::SpendMetaData metaData(0, uint256S("120"), uint256S("120")); - sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData); + sigma::CoinSpend coin(params, privcoin, anonymity_set, metaData, true); return coin.getCoinSerialNumber(); } diff --git a/src/test/zerocoin_tests2_v3.cpp b/src/test/zerocoin_tests2_v3.cpp index d78e17e763..c683ffad80 100644 --- a/src/test/zerocoin_tests2_v3.cpp +++ b/src/test/zerocoin_tests2_v3.cpp @@ -43,10 +43,9 @@ BOOST_AUTO_TEST_CASE(zerocoin_mintspend2_v3) sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState(); vector vtxid; - //200 blocks already mined, create another 200. + //200 blocks already mined, create another 350. See Params::nSigmaPaddingBlock - // Create 400-200+1 = 201 new empty blocks. // consensus.nMintV3SigmaStartBlock = 400 - CreateAndProcessEmptyBlocks(201, scriptPubKey); + CreateAndProcessEmptyBlocks(350, scriptPubKey); std::vector denominations = {"0.1", "0.5", "1"}; for(string denomination : denominations) { diff --git a/src/wallet/sigmaspendbuilder.cpp b/src/wallet/sigmaspendbuilder.cpp index 2f806be67e..134e9dfe3f 100644 --- a/src/wallet/sigmaspendbuilder.cpp +++ b/src/wallet/sigmaspendbuilder.cpp @@ -24,21 +24,23 @@ class SigmaSpendSigner : public InputSigner const sigma::PrivateCoin coin; std::vector group; uint256 lastBlockOfGroup; + bool fPadding; public: SigmaSpendSigner(const sigma::PrivateCoin& coin) : coin(coin) { + fPadding = true; } CScript Sign(const CMutableTransaction& tx, const uint256& sig) override { // construct spend sigma::SpendMetaData meta(output.n, lastBlockOfGroup, sig); - sigma::CoinSpend spend(coin.getParams(), coin, group, meta); + sigma::CoinSpend spend(coin.getParams(), coin, group, meta, fPadding); spend.setVersion(coin.getVersion()); - if (!spend.Verify(group, meta)) { + if (!spend.Verify(group, meta, fPadding)) { throw std::runtime_error(_("The spend coin transaction failed to verify")); } @@ -68,8 +70,14 @@ static std::unique_ptr CreateSigner(const CSigmaEntry& coin) throw std::runtime_error(_("One of the minted coin is invalid")); } + int version; + { + LOCK(cs_main); + version = chainActive.Height() >= ::Params().GetConsensus().nSigmaPaddingBlock ? ZEROCOIN_TX_VERSION_3_1 + : ZEROCOIN_TX_VERSION_3; + } // construct private part of the mint - sigma::PrivateCoin priv(params, denom, ZEROCOIN_TX_VERSION_3); + sigma::PrivateCoin priv(params, denom, version); priv.setSerialNumber(coin.serialNumber); priv.setRandomness(coin.randomness); @@ -100,6 +108,9 @@ static std::unique_ptr CreateSigner(const CSigmaEntry& coin) throw std::runtime_error(_("Has to have at least two mint coins with at least 6 confirmation in order to spend a coin")); } + if(version < ZEROCOIN_TX_VERSION_3_1) + signer->fPadding = false; + return signer; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fb681c0e44..3c502b6daf 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5535,12 +5535,18 @@ bool CWallet::CreateSigmaSpendTransaction( privateCoin.setSerialNumber(coinToUse.serialNumber); privateCoin.setEcdsaSeckey(coinToUse.ecdsaSecretKey); - sigma::CoinSpend spend(sigmaParams, privateCoin, anonimity_set, metaData); + bool fPadding = false; + if(chainActive.Height() >= ::Params().GetConsensus().nSigmaPaddingBlock) { + txVersion = ZEROCOIN_TX_VERSION_3_1; + fPadding = true; + } + + sigma::CoinSpend spend(sigmaParams, privateCoin, anonimity_set, metaData, fPadding); spend.setVersion(txVersion); // This is a sanity check. The CoinSpend object should always verify, // but why not check before we put it onto the wire? - if (!spend.Verify(anonimity_set, metaData)) { + if (!spend.Verify(anonimity_set, metaData,fPadding)) { strFailReason = _("the spend coin transaction did not verify"); return false; } @@ -5651,6 +5657,9 @@ CWalletTx CWallet::CreateSigmaSpendTransaction( bool& fChangeAddedToFee, const CCoinControl *coinControl) { + int nHeight = chainActive.Height(); + if(nHeight >= ::Params().GetConsensus().nDisableUnpaddedSigmaBlock && nHeight < ::Params().GetConsensus().nSigmaPaddingBlock) + throw std::runtime_error(_("Sigma is disabled at this period.")); // sanity check EnsureMintWalletAvailable(); @@ -6166,7 +6175,7 @@ bool CWallet::CreateMultipleSigmaSpendTransaction( // Construct the CoinSpend object. This acts like a signature on the // transaction. sigma::PrivateCoin privateCoin(sigmaParams, denomination); - int txVersion = ZEROCOIN_TX_VERSION_3; + int txVersion = chainActive.Height() >= ::Params().GetConsensus().nSigmaPaddingBlock ? ZEROCOIN_TX_VERSION_3_1 : ZEROCOIN_TX_VERSION_3; LogPrintf("CreateZerocoinSpendTransaction: tx version=%d, tx metadata hash=%s\n", txVersion, txNew.GetHash().ToString()); @@ -6213,6 +6222,7 @@ bool CWallet::CreateMultipleSigmaSpendTransaction( uint256 txHashForMetadata = txTemp.GetHash(); LogPrintf("txNew.GetHash: %s\n", txHashForMetadata.ToString()); + std::vector spends; // Iterator of std::vector>::const_iterator for (auto it = denominations.begin(); it != denominations.end(); it++) @@ -6229,15 +6239,18 @@ bool CWallet::CreateMultipleSigmaSpendTransaction( TempStorage tempStorage = tempStorages.at(index); CSigmaEntry coinToUse = tempStorage.coinToUse; + bool fPadding = tempStorage.txVersion >= ZEROCOIN_TX_VERSION_3_1; + // Recreate CoinSpend object sigma::CoinSpend spend(sigmaParams, tempStorage.privateCoin, tempStorage.anonimity_set, - metaData); + metaData, + fPadding); spend.setVersion(tempStorage.txVersion); spends.push_back(spend); // Verify the coinSpend - if (!spend.Verify(tempStorage.anonimity_set, metaData)) { + if (!spend.Verify(tempStorage.anonimity_set, metaData, fPadding)) { strFailReason = _("the spend coin transaction did not verify"); return false; } diff --git a/src/zerocoin_params.h b/src/zerocoin_params.h index 601275fe5a..9b9a0883da 100644 --- a/src/zerocoin_params.h +++ b/src/zerocoin_params.h @@ -42,6 +42,14 @@ static const int64_t DUST_HARD_LIMIT = 1000; // 0.00001 XZC mininput #define ZC_SIGMA_STARTING_BLOCK 184200 //Approx July 30th, 2019, 8:00 AM UTC #define ZC_SIGMA_TESTNET_STARTING_BLOCK 50000 +// Block after which anonymity sets are being padded. +#define ZC_SIGMA_PADDING_BLOCK 220720 //Approx December 5th 12PM UTC +#define ZC_SIGMA_TESTNET_PADDING_BLOCK 110000 + +//Block after whinch we are disabling sigma to enable after starting padding +#define ZC_SIGMA_DISABLE_UNPADDED_BLOCK 219904 //December 2nd 12PM UTC +#define ZC_SIGMA_TESTNET_DISABLE_UNPADDED_BLOCK 109160 + // The block number after which old sigma clients are banned. #define ZC_OLD_SIGMA_BAN_BLOCK 181850 //Approx July 22nd, 2019, 4:00 AM UTC