diff --git a/configure.ac b/configure.ac index 3088b2f578..ea88a1c26b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 14) -define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_REVISION, 6) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2021) define(_COPYRIGHT_HOLDERS,[The %s developers]) diff --git a/src/Makefile.am b/src/Makefile.am index af6ef6728f..a1f9890f86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -672,7 +672,7 @@ liblelantus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) liblelantus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) liblelantus_a_SOURCES = \ liblelantus/challenge_generator.h \ - liblelantus/challenge_generator.cpp \ + liblelantus/challenge_generator_impl.h \ liblelantus/lelantus_primitives.h \ liblelantus/lelantus_primitives.cpp \ liblelantus/lelantus_proof.h \ diff --git a/src/batchproof_container.cpp b/src/batchproof_container.cpp index e37ca42860..e6cadd5890 100644 --- a/src/batchproof_container.cpp +++ b/src/batchproof_container.cpp @@ -21,12 +21,12 @@ void BatchProofContainer::init() { } void BatchProofContainer::finalize() { - if(fCollectProofs) { - for(const auto& itr : tempSigmaProofs) { + if (fCollectProofs) { + for (const auto& itr : tempSigmaProofs) { sigmaProofs[itr.first].insert(sigmaProofs[itr.first].begin(), itr.second.begin(), itr.second.end()); } - for(const auto& itr : tempLelantusSigmaProofs) { + for (const auto& itr : tempLelantusSigmaProofs) { lelantusSigmaProofs[itr.first].insert(lelantusSigmaProofs[itr.first].begin(), itr.second.begin(), itr.second.end()); } } else { @@ -48,28 +48,30 @@ void BatchProofContainer::add(sigma::CoinSpend* spend, void BatchProofContainer::add(lelantus::JoinSplit* joinSplit, const std::map& setSizes, - const Scalar& challenge) { + const Scalar& challenge, + bool fStartLelantusBlacklist) { const std::vector& sigma_proofs = joinSplit->getLelantusProof().sigma_proofs; const std::vector& serials = joinSplit->getCoinSerialNumbers(); const std::vector& groupIds = joinSplit->getCoinGroupIds(); - for(size_t i = 0; i < sigma_proofs.size(); i++) { + for (size_t i = 0; i < sigma_proofs.size(); i++) { int coinGroupId = groupIds[i] % (CENT / 1000); int64_t intDenom = (groupIds[i] - coinGroupId); intDenom *= 1000; sigma::CoinDenomination denomination; - bool isSigma = sigma::IntegerToDenomination(intDenom, denomination) && joinSplit->getVersion() == SIGMA_TO_LELANTUS_JOINSPLIT; - std::pair idAndFlag = std::make_pair(groupIds[i], isSigma); + bool isSigma = sigma::IntegerToDenomination(intDenom, denomination) && joinSplit->isSigmaToLelantus(); + // pair(pair(set id, fAfterFixes), isSigmaToLelantus) + std::pair, bool> idAndFlag = std::make_pair(std::make_pair(groupIds[i], fStartLelantusBlacklist), isSigma); tempLelantusSigmaProofs[idAndFlag].push_back(LelantusSigmaProofData(sigma_proofs[i], serials[i], challenge, setSizes.at(groupIds[i]))); } } void BatchProofContainer::removeSigma(const sigma::spend_info_container& spendSerials) { - for(auto& spendSerial : spendSerials) { + for (auto& spendSerial : spendSerials) { bool foundAtSigma = false; - for(auto& itr :sigmaProofs) { - if(itr.first.first == spendSerial.second.denomination && itr.first.second.first == spendSerial.second.coinGroupId) { + for (auto& itr :sigmaProofs) { + if (itr.first.first == spendSerial.second.denomination && itr.first.second.first == spendSerial.second.coinGroupId) { auto& vProofs = itr.second; for (auto dataItr = vProofs.begin(); dataItr != vProofs.end(); dataItr++) { if (dataItr->coinSerialNumber == spendSerial.first) { @@ -80,40 +82,53 @@ void BatchProofContainer::removeSigma(const sigma::spend_info_container& spendSe } } } - if(!foundAtSigma) { + if (!foundAtSigma) { int64_t denom; sigma::DenominationToInteger(spendSerial.second.denomination, denom); int id = denom / 1000 + spendSerial.second.coinGroupId; - std::pair key = std::make_pair(id, true); - if (lelantusSigmaProofs.count(key) > 0) { - auto &vProofs = lelantusSigmaProofs[key]; - for (auto dataItr = vProofs.begin(); dataItr != vProofs.end(); dataItr++) { - if (dataItr->serialNumber == spendSerial.first) { - vProofs.erase(dataItr); - break; - } + // afterFixes bool with the pair of set id is considered separate set identifiers, so try to find in one set, if not found try also in another + std::pair, bool> key1 = std::make_pair(std::make_pair(id, false), true); + std::pair, bool> key2 = std::make_pair(std::make_pair(id, true), true); + std::vector* vProofs; + if (lelantusSigmaProofs.count(key1) > 0) + vProofs = &lelantusSigmaProofs[key1]; + else if (lelantusSigmaProofs.count(key2) > 0) + vProofs = &lelantusSigmaProofs[key2]; + else + continue; + for (auto dataItr = vProofs->begin(); dataItr != vProofs->end(); dataItr++) { + if (dataItr->serialNumber == spendSerial.first) { + vProofs->erase(dataItr); + break; } } } } } void BatchProofContainer::removeLelantus(std::unordered_map spentSerials) { - for(auto& spendSerial : spentSerials) { - std::pair key = std::make_pair(spendSerial.second, false); - if (lelantusSigmaProofs.count(key) > 0) { - auto &vProofs = lelantusSigmaProofs[key]; - for (auto dataItr = vProofs.begin(); dataItr != vProofs.end(); dataItr++) { - if (dataItr->serialNumber == spendSerial.first) { - vProofs.erase(dataItr); - break; - } + for (auto& spendSerial : spentSerials) { + // afterFixes bool with the pair of set id is considered separate set identifiers, so try to find in one set, if not found try also in another + std::pair, bool> key1 = std::make_pair(std::make_pair(spendSerial.second, false), true); + std::pair, bool> key2 = std::make_pair(std::make_pair(spendSerial.second, true), true); + std::vector* vProofs; + if (lelantusSigmaProofs.count(key1) > 0) + vProofs = &lelantusSigmaProofs[key1]; + else if (lelantusSigmaProofs.count(key2) > 0) + vProofs = &lelantusSigmaProofs[key2]; + else + continue; + + for (auto dataItr = vProofs->begin(); dataItr != vProofs->end(); dataItr++) { + if (dataItr->serialNumber == spendSerial.first) { + vProofs->erase(dataItr); + break; } } } } void BatchProofContainer::batch_sigma() { - for(const auto& itr : sigmaProofs) { + for (const auto& itr : sigmaProofs) { std::vector anonymity_set; sigma::CSigmaState* sigmaState = sigma::CSigmaState::GetState(); sigmaState->GetAnonymitySet( @@ -132,7 +147,7 @@ void BatchProofContainer::batch_sigma() { vector> proofs; proofs.reserve(m); - for(auto& proofData : itr.second) { + for (auto& proofData : itr.second) { serials.emplace_back(proofData.coinSerialNumber); fPadding.emplace_back(proofData.fPadding); setSizes.emplace_back(proofData.anonymitySetSize); @@ -142,7 +157,7 @@ void BatchProofContainer::batch_sigma() { auto params = sigma::Params::get_default(); sigma::SigmaPlusVerifier sigmaVerifier(params->get_g(), params->get_h(), params->get_n(), params->get_m()); - if(!sigmaVerifier.batch_verify(anonymity_set, serials, fPadding, setSizes, proofs)) { + if (!sigmaVerifier.batch_verify(anonymity_set, serials, fPadding, setSizes, proofs)) { LogPrintf("Sigma batch verification failed."); throw std::invalid_argument("Sigma batch verification failed, please run Firo with -reindex -batching=0"); } @@ -153,24 +168,21 @@ void BatchProofContainer::batch_sigma() { void BatchProofContainer::batch_lelantus() { auto params = lelantus::Params::get_default(); - for(const auto& itr : lelantusSigmaProofs) { + for (const auto& itr : lelantusSigmaProofs) { std::vector anonymity_set; - if(!itr.first.second) { + if (!itr.first.second) { lelantus::CLelantusState* state = lelantus::CLelantusState::GetState(); std::vector coins; - uint256 blockHash; - state->GetCoinSetForSpend( - &chainActive, - chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1), // required 2 confirmation for mint to spend - itr.first.first, - blockHash, + state->GetAnonymitySet( + itr.first.first.first, + itr.first.first.second, coins); anonymity_set.reserve(coins.size()); - for(auto& coin : coins) + for (auto& coin : coins) anonymity_set.emplace_back(coin.getValue()); } else { - int coinGroupId = itr.first.first % (CENT / 1000); - int64_t intDenom = (itr.first.first - coinGroupId); + int coinGroupId = itr.first.first.first % (CENT / 1000); + int64_t intDenom = (itr.first.first.first - coinGroupId); intDenom *= 1000; sigma::CoinDenomination denomination; sigma::IntegerToDenomination(intDenom, denomination); @@ -184,7 +196,7 @@ void BatchProofContainer::batch_lelantus() { coins); anonymity_set.reserve(coins.size()); - for(auto& coin : coins) + for (auto& coin : coins) anonymity_set.emplace_back(coin + params->get_h1() * intDenom); } @@ -198,7 +210,7 @@ void BatchProofContainer::batch_lelantus() { std::vector challenges; challenges.reserve(m); - for(auto& proofData : itr.second) { + for (auto& proofData : itr.second) { serials.emplace_back(proofData.serialNumber); setSizes.emplace_back(proofData.anonymitySetSize); proofs.emplace_back(proofData.lelantusSigmaProof); @@ -208,7 +220,16 @@ void BatchProofContainer::batch_lelantus() { lelantus::SigmaExtendedVerifier sigmaVerifier(params->get_g(), params->get_sigma_h(), params->get_sigma_n(), params->get_sigma_m()); - if(!sigmaVerifier.batchverify(anonymity_set, challenges, serials, setSizes, proofs)) { + bool isFail = false; + try { + if (!sigmaVerifier.batchverify(anonymity_set, challenges, serials, setSizes, proofs)) { + isFail = true; + } + } catch (std::invalid_argument&) { + isFail = true; + } + + if (isFail) { LogPrintf("Lelantus batch verification failed."); throw std::invalid_argument("Lelantus batch verification failed, please run Firo with -reindex -batching=0"); } diff --git a/src/batchproof_container.h b/src/batchproof_container.h index 39b508cb71..e6fd45f654 100644 --- a/src/batchproof_container.h +++ b/src/batchproof_container.h @@ -24,7 +24,8 @@ class BatchProofContainer { void add(lelantus::JoinSplit* joinSplit, const std::map& setSizes, - const Scalar& challenge); + const Scalar& challenge, + bool fStartLelantusBlacklist); void removeSigma(const sigma::spend_info_container& spendSerials); void removeLelantus(std::unordered_map spentSerials); @@ -70,15 +71,15 @@ class BatchProofContainer { private: static std::unique_ptr instance; - // map (denom, id) to (sigma proof, serial, set size) // temp containers, to forget in case block connection fails + // map (denom, id) to (sigma proof, serial, set size) std::map>, std::vector> tempSigmaProofs; - // map (id, fIsSigmaToLelantus) to (sigma proof, serial, set size, challenge) - std::map, std::vector> tempLelantusSigmaProofs; + // map ((id, afterFixes), fIsSigmaToLelantus) to (sigma proof, serial, set size, challenge) + std::map, bool>, std::vector> tempLelantusSigmaProofs; // containers to keep proofs for batching std::map>, std::vector> sigmaProofs; - std::map, std::vector> lelantusSigmaProofs; + std::map, bool>, std::vector> lelantusSigmaProofs; }; #endif //FIRO_BATCHPROOF_CONTAINER_H diff --git a/src/blacklists.h b/src/blacklists.h index aed313e7ca..36572b2c78 100644 --- a/src/blacklists.h +++ b/src/blacklists.h @@ -1659,6 +1659,211 @@ std::set const sigma_blacklist { } // end of namespace sigma. +namespace lelantus { +std::set const lelantus_blacklist { + "be4bb8adf7879f191c671d7a38740d6ce26d114be483bfc644b95e99de2c0ec00100", + "cf5becd9222dbde30b65716f29b306a1f9cf388c82d28d844a30bc8961e868820000", + "e9c946155eb025fb105807b3a0593a18445073beb47b60589389a5e361e4ac590100", + "c6e584767777ef3997619cc423cc830b0248e9e1402acc46da19b5e5dc2b25c00100", + "7ee85f9978f1ae66e57a1ab5e0c32e7abf2f4d35b02048139dff0c7637f7c57e0000", + "80eb308d153bfb7949e19ed5a734193882b24448171569752c69e7df49870f9b0100", + "51f44345b421a05f697a6cfbd75a4535b380916f8c9e43af34b2c086fc2332750000", + "d29459b1ccca3337ef19784ffdb6269993443e8df8c61444b4c2eb4d5ad778410000", + "7732f0b4428d336228cf100e6f8737873dc12e068e5b9a607d91098d45fa43860100", + "133f7b521aacb38332f5684501695066aedbd7eec844e9231ff8fccc9f9882000100", + "f1b1996d35ac2e5d72c1c06809cc47cdc825ea86b977a94fa135e3031ef88f600100", + "04c3ca1cf88bfeaf44fb17182d326d0f95e1eac32ac12814a98a5613450f4cc30100", + "504ebfaf2799a3ad5394e0dcaa12f5b38e6707e428655ef450277fe7d56b42fe0100", + "b1f94a0c502521514ce0d71823526d34ab28372d25e0cff009516d19051814fe0100", + "9d7b8ae32b38f3c508d8eedbe024aad0d32932ba66c82c3f73f56db21c089bc20000", + "08ee98bef75cc83494000fb5500bcbae4eb0a9977cf5be9785d59fc04bf5d97e0100", + "65d901c4a5e2f763ee0626700cfb53121d2f6cbe418c6f5b0038096374d161910000", + "200d7cbc74d746543245601e2654fc6046a0731795417dcff5c47df5b362859e0000", + "875cffac926d7f0216bc1459abe5de4f2374c719b6b36597c2d6ed5b17dfb9fb0100", + "b943041d19c6c66a6a6a58d7f92fdeafad989de4c64b55ca1491288be4d37e7f0100", + "3debe61244b74bec967577a11409a255284cb25b3595523a196ad12dc370a8830000", + "f22c9d4fbe1fef5ed99eabc901a54e9d01c55ddf867736fd7811bab35cd864650100", + "42f46b1d1a9dce4b13bd9a7f416079940350ab04cb8b8b9f5beed5743633cf0c0000", + "b47f9ef21130509e4e20074a8cb9468949b35cc32b0ba14b7abfa9ceab22ea350000", + "8a5caa82b26513f97bf7201b03db74559e8d8db9eb5d98e31877268cd14ac61e0100", + "eafee8d9f8eb01ee8b7b68aa4787eaf24c3d85a8f50f2ca76cf48fc4c413eda20100", + "67e770a559deceed7494dee0a1913effd0bf677a0bd7c9e13742b9cbb88be8610000", + "71d791065f85939e546080675d73d7020d7d884720d7598b9c1f51b9204913590100", + "2c74755af2888b47d2aeae6d109396313b0353d251f5829e0d428012874c57920000", + "75f2d8f131a3a1ea660fa358646cccb4c574211b37d0407ae3a6ff2a86da42e90000", + "35d90ed3c8a29e00bab0be5703ee7106400ddc14ad64545e2b2246fe498dedcf0000", + "4be412215cb9a564404aad92b20ec2a01a39fa682e3747017380309d604f44010000", + "5bda04673c389fe0e9fc45f10f7d52035f8a15ccc171d7f30a4ee2810c59d9ff0000", + "e5daa39825c7d9b838a133f43a54167cce8c485ed0458f58b72417cb91e875440100", + "7932186d282a9f5032c9ef96e5091a76c8c0b74617b3e6ca7af5334c4dc0b9a10100", + "9f44caf75b3572b6437cfe567dd21f3ff661a9eb8157ea6155c6564efd78a7b70100", + "2021c430fb91108a99097157fe8d313c04d0ff5fd5694788b8453ad782d192c00100", + "94de7d0be405dfac6ad7f40050f3da7162b652f1bc9615c4ad77c1acb66357f50100", + "3ffad60fd20dee9dcc52f2e7f99c4791df9f23959203628905dd5a505657c60e0100", + "efc24187078b84d5deb072dee0c0dea83c6f0a9d1ef41ccb78755dcb5d5d59ec0100", + "fa8b9d7dc3c92ec632928e3fe53f52cd0d9f69c1a53b36a215ee9dc75caed7c20100", + "b98eb5bd6476f400743757f5fcd0fba652038d626f4a7ed407a1dfb6129fbc5d0000", + "b4e962c0f63db69160dacb72a05bd30824202b0946775f34336d3b7ebf5718210100", + "d608a379517e0baa86bfe9d03a6cf9610a7772708883aee98fa4b6506250421b0100", + "cfae5243bb8f585bd1b84687f00333619933a046ac819d6bdee984c690d73d300000", + "820f9a5ac9954643f851d4c18695f3bb6475618ef0495b798c3b6d3af407a32f0100", + "82798c203e19ff81299ad5f0b6e8bb216dc5908d6c90373359c8a0038863208e0000", + "d92d566ccf4b9d06570fc521b77c213fe832cf1ac2607d0b07de6c37eba5b0060000", + "026d5c53d441c6f4fd39ccf40eaf8140c4b340368382dc9d83b0e43045ce70220100", + "5256359235c6bfd90116ed256668f7593dae744f146a1913302b7f1e0ceaba140100", + "033f58935dd7eee57b6723e5c4c09b455271e6c5a1e6e80c25aaae06018173a40100", + "f99eccf9aff7ccad163b7cd5d104a5dfea441fb0afff277cd0d2282ed099411d0000", + "5528ebff8837ccde9b123a0ad3ab5df7427576f472a14d36597a9fd3fbc026140000", + "8bcd1b4cd8403d9a0ee9e805077741745e2cf3dbaedf305d8324b1f1e2e83a8f0000", + "7a1297468b7e9302d8985a2b217577183032086654c9d56567a11e2df155c4160100", + "3c972d7c6e74e13fd63f6a63283622aeec28d854191dac1e176795ec59b10e230000", + "04dbd1b6c9b2dd52300c7565017fe605d916a17d93d49451cf3ca5f1edc5a3b80100", + "b12ab99c9279a12986dbc43db3f572d369389af70cacf2e7e88c76994b18e5aa0100", + "ae12bfa5939e6433dfb405aea9be9af8e8f003bf69523c52e43de67715afe2620100", + "c3092f5569f2f46abf38ed8421d964f8c5235746e324ee1e81739eab640bfdb40000", + "4b8ac0daf815dcca717ed9cd062ce91d2a319e270f387bb07635b70c4224ea2a0100", + "f1ba0f5f578eb45557e5f15af41c6be009d1cb33dee2089ab0094866f8bcf08f0100", + "6cb06d24425bad11234d449a41c890dbaf20b0a45c22e4a0ba21a83125f832f30000", + "9c8fc80bb0b59c312236e5f82bebb00278a3d417391465b4089d969f66ae9c900000", + "697d664b075c3ed3a94e65be99ebcdc4e2aba2ad33180e5e92a88011dcf33a9d0100", + "a82abb894724801dd9d3294fe3d58d6c3028dc4fbc911c2b0d40f168e9a3fc930000", + "0f6d6068312f775217b57b05dfc4b357b7b2c58064107feebe9f7c5a7fee464f0100", + "80ef969c69a1424aeae699b3b3e33bcead408d77e2cac22d85f7eec338d137f70000", + "3583aa3fb052b1113992f24300124b70d4e7fbfb0886ad2725eada939c31c3b30100", + "5347ef78917bbca6f3693b3415bad9b9b5c428efd7082e7b2b54038783cfb7ec0000", + "a2ce0966ef7385da9ace59c552ec5b2065bd443a7b442a6076f25f2f898e01550100", + "d2fe129d80fc17fac1b4ded10731c3700ce95ba682d37c7a123eaf45f06c976e0000", + "63124502c8c3b992d276ec228c5c22e4a5c0151cb153029d8c1a4afacfb31ca60000", + "9a96155cb7ce5f44090ce25c1e0cbd253cfa6a11821ab83294f07626982d4e0b0000", + "8334cffec5ff1854205135bed0395027eaa5f9b92b0da3402250cec0b2c1dcfc0000", + "a37fc029936ba1048ea41697b67ff2674bbfb7cc796bc44e17ac1c93a81b11bd0100", + "01ab6ee37d20fa3b695caed63e1730e1aa3ce6e73335fc5149d7a5f5a6c5c60e0000", + "d760b240bb178417dac2f688186221940065271bbb7270c725c55763b36849fa0100", + "30a608bcf0a31771a7c22f09bb10ea212aecfc6e0bc2d2e906b9937cfb661d130000", + "982d747ce13bda1e5e53f60c35bdfec7552b10a17daf52d485dabc87484aa0590000", + "ad4c22117d4eba202a1682d7ccfb1a8c587c68f0207c4ea05a1849b57ee0b9ca0100", + "f7502b34752ae606aebb959b98ab781fd8009153741ba9e9aa5093f8cdb6f09f0100", + "7cb6b5738cc34dce755331ed07bd7f119d39a0a724eef15ac2cf822c54d8ac480000", + "9e29cfe462647552c617ca777dd1a1890f254e1b22648e1743c89fb81dd1a7520000", + "1c6912383427ef067cb007f90f891f4a56420d0d6b2e8e60ee285ba2248e0ea40100", + "47b42f69e1c3be670063407595bff999f2e94448dceee46af736afdb42d199ad0000", + "b75a1dc3a5ba7610c8bebf6c537dde8b2a92ebfcbe3a6787e451c906bd662b060100", + "f923cb3d0de40f65a6d2fee176f2d042f991999c66a0215e5b67219059528ec10100", + "929249e5ed3d760ce29109dc466f43e7a63513079102614f5e6219d613e5bf170100", + "da2955e8ee7836b01828cb46e1369e321f529f63209e04aaa12c5dee05e3a9a90100", + "1c13d45ad848370d4a455d160302767bf326df0509fb334afc8365354f8c207c0000", + "4340070e04b6834c72112d8d7d01ece98ac21900d76e73e44e270e1cc530b5bf0000", + "156076a84120089063b48e5d6624cd83dcac0a156e00f2f8cb74b3f39247f0340000", + "8cb107cf8436396499500c978bdf300c535a305142e8e2b0b0f9478f66aa68e30100", + "77dde59b218e1cf7a66d11bbc258efd69198b0d0891031787b698e62c4081a310100", + "34f1a73a7d3a3e08ff5f53073dd36175a8ce254b452bcbd7c1f2dd86dfef45540000", + "21576bc8ac8353b4314928093f3f797edbf6683726a3d8bd88af7e6d13e3382b0000", + "3d6f283f1831e0ebcc80b6976607e84a51bc366b63aacb0890feb37410eef5bf0100", + "0a865e0b2f781d3a8f9885901bfe438847c04d78fb5f53eafc96485bc1cc01210000", + "fc696f66d7e9c915f35f8200923996945da2dbae48615db6c4dcd061807d7f600100", + "724c45464a6aeea9d6d0d72d4f17b8c36563585cf7d5e8bbaa05f51499cca1f20000", + "f48e5aac821cd8a59c2e55e6037812074e63ee38091a623ce61ed6b712365a3c0100", + "0767bf88e95a8c36711726e991857fe1ca7d0177bfe9e27548a6321ccfb0bca10100", + "7f75fcc94eccc45c854870e7901eb92c51e7e08a15e29ca789c639953e6989900100", + "d40f3d9751ca2f0db0dd48a03a68ff567aa6f1e7e516f14c4233c4d4773dab460100", + "b4ca64f6099bff76e6c4568f421d118f269f5211cb858195cc4a5144773f7e1b0000", + "0bba0f6be357d5af550d73055373efe356d59fa4c30a7760252c5bcf7cf48e0d0000", + "a659f4dd0b2884a7cab3ea796fc0d2d6a2a27ab96a5532a290166ea736d379bf0000", + "b8983ef4e13a93b20a1916997321a628eec995f3015923791d96c6a6b2b533110000", + "f78c33d5588a8c2f3041f743c5cd6df5314cc910123e763e7f619597ba88bb350000", + "1e57add7cfa91f53e5a6504f80434a09c4149ef05c2324f4435955a091d849b10000", + "6054ec5145b29262b97061ec4817e087a3b0bd0bdad6e94cf55996e38de147650100", + "cad5e85bdc76104fd41211d8bb66e1e3c77ac38abd3331392bd0090115381fb00100", + "f19587733c2b77f8db714dc633debbabc4079df374defd228741525d1ed4b0ca0100", + "087676acc498c597fcbf7c9de96aac703733005266e77dd60dc1916db782769a0100", + "d48acbc70b4cde9ed53e39080733e1327dca543693d02b26257df48e0134178b0100", + "407f9e76e1ae81994df461f85daa56736cb6d44470c6da039da5515d6a91e78c0100", + "c60cd1f65af6b9de04c6eae0471fd1b58e6b20ce1219fe333a5890e92dc937f80000", + "31b2c9ed284a82f82fd88fa4741d58aefde53bfdd87cbf07f078cc56ddcd13bd0000", + "0dfd4fa44779db5e882dc7864b087d90bd1b6c3db69b060c893e4bf2722ec3560100", + "4a25df42def0c488caec4fbfbbe39639c4f36433d06e151dd8124ecc26f7e3510100", + "fd79811d759ea20bbb1d5f352b28b2dd32c4878e159116486db839f75ab992b70100", + "74bba39c8d9d7a485c337f2c5a3d1ca40402a392decc091e8f3629f3f69df4000000", + "2a957e5eda9e40fb127308f41eb6ebc32fbf63a646fcc28e50268bc0e4a5c8330000", + "0fd505ec990bab6e11ae6e18706cea8e9eb3c29524a863df453cc8bad9621e700100", + "7de27998cd1231b7c318309e1958c6c89c7c8d6295482b72720705bfd484ac760100", + "20e37e800479f4e6d0eaa6cd108a5181afb1f69c1aa4626f525963f87f3292cf0000", + "e0197fe381351ca1e22f3ff93f1d6cce24d14141fde42e33785bebef3c382ad80000", + "6db4af182ddc15456a4bd069f5e044bf09742078b0d396b5e24bade2c047a1d80100", + "e7a1a9fb66a3675e88ca9e9b2afd121b9a8c21162b6c9a33453e2af0fe3cda200100", + "984b69243544b9757c3b1e04b4b56b0aaa05d49b8656d7bab78fcde53ade7efd0100", + "fd112a45837f25c96448af192894638f8d3a1cd7016ce32c956cfe79fa4b03bd0000", + "c239d9e71bd019ee4c5acd01348495910fc2430274028dd7b13cf9ac9a0cba7d0100", + "ec4a7a4a15d3194e1cd47af4414d4c5cbbcae605ac7ee63f502a2772344cc4ed0100", + "9eca6ac8ac8079a39cc185ac822ddd997c17a634339302461364d91d207cc36e0100", + "e4a7caebe0119e79b29927d77da90878e955fe97975b35afb004e277e0b0412f0000", + "7bd23e30f9ac4232a22d385f2d409af7267e53dfacf000d647d48777a1d7572c0100", + "d28befabd686cd782849e032e09bbbe6c0119b3cefc5b6dff05d54e3d210ffc20100", + "7d4cec76341cee02204864e3d8bf8745f0552314688de1d6a9b8bf7d6e47dc6a0000", + "b194a3afbecf5b9c1a59ddc7600898921e07ce55fd9ae06af299d2c4ffac32e90100", + "1d9053670053a610b71e94ba1c69e1398fb747288aaf56c3f243f6e9385b530a0000", + "aef120e37dbf733e2c58d50ea2e8d18849c06ca148cf898f0f9926f8db5e6d940100", + "0eb54d8aa0f85da9458eb7f8e8116149d705acd86e58fee13b27bf72601ab0a30000", + "1eb99f2c1416ddb096adc021bc0a499b354950141b0803b4220d599bc0d1dcae0000", + "8993ce4d5342759daad0bafbd7c0ce27930480a083c729cf9c540ad0dec8cef50000", + "d72d9753c732790ea7c0497d583b046f042210f91a6faae6b1bb80dda8d19ede0000", + "c14ceb8365c04eb6052b327810ee9c81d3f5866d6ac474b98d3433cfd5a85d530100", + "d8d013a2b55fbf39c6225a8ea15a475d80be01864cd01004b9fb70da4d0c6ad70000", + "bc6ecfc15559c35cfe0b5982e300f9ad69a6fdbbeebb7314ecaacd5808407c5f0000", + "26e824c2fdec79a3b8bb78f778751fed93fb060c3a6c6b68100cb85f198a46be0100", + "759640a43b6183da72f935783b59b4441ef363f3c8ce6a330ced0f1fc7f11cfa0000", + "d701a061863742f80adab19cca3b9cbd8630dd47e7df5fc9236749588dce0fd00000", + "3fcae1408e33e5db0f39e09936b95bf4dffcb985ef5c619cb22aa3c613b8e7180100", + "0e36b34fd32574d57a7b5ca440260d7ed232330b7802e16cb9ee39184ac341590000", + "827914ed0907857a9914a5a1084be50b648a1069b33b6856e4df8e290d9444800000", + "e1da1a618b646d8981773291c6c964744fbf496f93a562f731fada36b7659e600000", + "b942f31a28fb69794ff3df126d30ad8b28f57bfe1e28bbb7a7bef1d7143d0dad0100", + "0ddf3f8618f14013232d0d9ca32e4df908a62a1595b724b5780c2fb9b4b729d70000", + "0c50f5844b1be38f9a64f2595a89e87928057d314ba5a5be4f29ec0c51cc4ec60000", + "b13dda3639500b7edf4298766e4d89fb8f79630ecaf950d825b4bfdfbb476eaa0000", + "dcee3208a7ef8d0b02d8093a92cf572e25974370a3908e1643ca66fb7ecdae150000", + "c1c652449646d0fc5863c5f901acc9a54723b3a020b8b01d8a8e64c8dfacf3920100", + "2f8533267a56e698fb69232873dd3c7c8058d5598ef18d4c7ee399137228ccbe0000", + "dad2f518390068c8cc51ced3bde122058e57e7460ea397d3511d66b85ef8481f0100", + "487c070d9fd9fc51a362cc0bb44346b03d5651ae51455539af75a80e2d9bb7450100", + "59350c73c212e6b0569b47fbef9d1cdb7df0dd577e754f81e2d2828afda8d2540000", + "1299abbba97c6eebdbf654582c17801d3933e5c4d7e79149b7ae1fdd7908fbea0100", + "8ce3c891e93c5ce4f7259dae2926df910b3f524ae57d0e45d0243e2d0a1221e40000", + "5f329206a635711f5c258c48150b227c608881ca30fb84504ff310d8d2baad970000", + "c92fe56826054ed4a71b97daf1c78492cee26d50337831d8bf924c4cf2a99ebe0000", + "7683f28aa8f9ca68fe4c3fc918d474ce6552c06fec88ed725d61c7b841cb72c70000", + "cb8c5b47f8597aa8a9ae937923275d50953b7db59a315d0f1269ac4926e429ee0000", + "654c09ee7a2aef93c1bd19bf66006ec23ccc5cd0cf877ee2c226cecb09f90bff0000", + "f63eff6cfc1cafefbf47cdc8a395f66d4b43b636ad14a4a08ede434adefa6cc60100", + "2d2d8e1262b23bfe4067990084bbf3fe8ad93a9825ab8bb26012beb13338ef7a0100", + "566713aa90c3096c454f0038be3c57790de060a190c2c610619a65c319ba11fd0000", + "2b894c709956eb9ec5cd4e21ee030a77d94f49e5a80092ae9bd635df4d70db6b0100", + "d8328fcfee9d223710f3288c618389174d2174ed0274b692914397ef62d38f880000", + "bcb72f05c38f6392af8762c38cdb4b8ec4d6f1bfa976683caa37efd02fd8c3470000", + "ef2257e2418c0617d8894dfdded303a8824761885bba2bbdd9210f233d1434f90000", + "2feb3f93c116ec153a6e59ac39d430ad92722a7a59b2fc215683a8b6130f896b0000", + "4fde7415f06454d07326a7fe0143a42bbbfb071c5d2ba9585bd872bfbff3288c0000", + "ad7ba6cd9236fe335e5dc2be5f607ad4b33d2703ec586524135c99a303571b560100", + "842c40925d18b11fc0e12b6145bc388132dc4089ec45b2044cb9ee52efeb6b790000", + "d095d025ccde36480a4917e700436bfbf0bf0667d173a3861c9c3bf68a9cf6a50100", + "eb02aac39c2b8aefcccd6273b8f5ce8c578be082a8652483ad131af3516578f60100", + "343c84bda64996b0ff1fd7e85acad94775c2653155693ff24e348c4f91a583270000", + "ca949a0066245f58a636fc9a63f9d6782343039f308c886bc99fa6c06f1c2be90000", + "521cc4b3630fdaeff43a102cae83e14dc9b6e5dec08f59d5be3c702686703a1b0000", + "f9d4b7e856a12a368fe5a1f805a20a1fef6e1b0049f51100e22c55a20fac15910000" +}; + +std::set const lelantus_testnet_blacklist { + "60413731c57c642b22ab5b02593db2c11fe22d3f3ee39aa7801950c494aa277d0000", + "b6293e17d5a58ca60ad8a3d7602724b9e2c228252b6f465261b685731f6b70c10000", + "3bfc84d144a05dfa178de0d19d6cc32075af52d085aa3f6a0c4b66bf6c33984c0100", + "e5e9348339d3c0215534cf02876f50bb008bfc471f0105888a2a8e5ccf60c7db0000", + "c2c855dd44a4e062b1b978bab03da54b7cb7cb4b7cb0a03b9c854becf958b7cd0100", + "fdbb43011f72180ff0d47a330e1ba1411a35452319fd12af52c5b3836bfd5b4a0000" +}; + +} // end of namespace lelantus. + std::set const txid_blacklist { "83890738940d7afd1f94a67db072f8fc4fdeea60c1f32e46f082f86ff4be3a48", "b3f4928f1aa4fc3d165ea2575edbcad04f9e007b9c6f51c7085101844395d7d5", diff --git a/src/chain.h b/src/chain.h index b2e3076d38..b981956ee4 100644 --- a/src/chain.h +++ b/src/chain.h @@ -245,6 +245,8 @@ class CBlockIndex std::map, vector> sigmaMintedPubCoins; //! Map id to std::map>> lelantusMintedPubCoins; + //! Map id to + std::map> anonymitySetHash; //! Values of coin serials spent in this block sigma::spend_info_container sigmaSpentSerials; @@ -282,6 +284,7 @@ class CBlockIndex mintedPubCoins.clear(); sigmaMintedPubCoins.clear(); lelantusMintedPubCoins.clear(); + anonymitySetHash.clear(); accumulatorChanges.clear(); spentSerials.clear(); sigmaSpentSerials.clear(); @@ -510,6 +513,9 @@ class CDiskBlockIndex : public CBlockIndex } else READWRITE(lelantusMintedPubCoins); READWRITE(lelantusSpentSerials); + + if (nHeight >= params.nLelantusFixesStartBlock) + READWRITE(anonymitySetHash); } if (!(s.GetType() & SER_GETHASH) && nHeight >= params.nEvoSporkStartBlock && nHeight < params.nEvoSporkStopBlock) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f0ccd704e4..a3deac245b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -12,6 +12,7 @@ #include "util.h" #include "utilstrencodings.h" #include "libzerocoin/bitcoin_bignum/bignum.h" +#include "blacklists.h" #include @@ -373,6 +374,7 @@ class CMainParams : public CChainParams { consensus.nRestartSigmaWithBlacklistCheck = 296900; consensus.nOldSigmaBanBlock = ZC_OLD_SIGMA_BAN_BLOCK; consensus.nLelantusStartBlock = ZC_LELANTUS_STARTING_BLOCK; + consensus.nLelantusFixesStartBlock = ZC_LELANTUS_FIXES_START_BLOCK; consensus.nZerocoinV2MintMempoolGracefulPeriod = ZC_V2_MINT_GRACEFUL_MEMPOOL_PERIOD; consensus.nZerocoinV2MintGracefulPeriod = ZC_V2_MINT_GRACEFUL_PERIOD; consensus.nZerocoinV2SpendMempoolGracefulPeriod = ZC_V2_SPEND_GRACEFUL_MEMPOOL_PERIOD; @@ -388,6 +390,12 @@ class CMainParams : public CChainParams { consensus.nMaxValueLelantusMint = ZC_LELANTUS_MAX_MINT; consensus.nZerocoinToSigmaRemintWindowSize = 50000; + for (const auto& str : lelantus::lelantus_blacklist) { + GroupElement coin; + coin.deserialize(ParseHex(str).data()); + consensus.lelantusBlacklist.insert(coin); + } + consensus.evoSporkKeyID = "a78fERshquPsTv2TuKMSsxTeKom56uBwLP"; consensus.nEvoSporkStartBlock = ZC_LELANTUS_STARTING_BLOCK; consensus.nEvoSporkStopBlock = ZC_LELANTUS_STARTING_BLOCK + 24*12*365; // one year after lelantus @@ -623,6 +631,7 @@ class CTestNetParams : public CChainParams { consensus.nOldSigmaBanBlock = 1; consensus.nLelantusStartBlock = ZC_LELANTUS_TESTNET_STARTING_BLOCK; + consensus.nLelantusFixesStartBlock = ZC_LELANTUS_TESTNET_FIXES_START_BLOCK; consensus.nZerocoinV2MintMempoolGracefulPeriod = ZC_V2_MINT_TESTNET_GRACEFUL_MEMPOOL_PERIOD; consensus.nZerocoinV2MintGracefulPeriod = ZC_V2_MINT_TESTNET_GRACEFUL_PERIOD; @@ -639,6 +648,12 @@ class CTestNetParams : public CChainParams { consensus.nMaxValueLelantusMint = 1001 * COIN; consensus.nZerocoinToSigmaRemintWindowSize = 0; + for (const auto& str : lelantus::lelantus_testnet_blacklist) { + GroupElement coin; + coin.deserialize(ParseHex(str).data()); + consensus.lelantusBlacklist.insert(coin); + } + consensus.evoSporkKeyID = "TWSEa1UsZzDHywDG6CZFDNdeJU6LzhbbBL"; consensus.nEvoSporkStartBlock = 22000; consensus.nEvoSporkStopBlock = 40000; @@ -829,6 +844,7 @@ class CRegTestParams : public CChainParams { consensus.nRestartSigmaWithBlacklistCheck = INT_MAX; consensus.nOldSigmaBanBlock = 450; consensus.nLelantusStartBlock = 1000; + consensus.nLelantusFixesStartBlock = 1000; consensus.nZerocoinV2MintMempoolGracefulPeriod = 2; consensus.nZerocoinV2MintGracefulPeriod = 5; consensus.nZerocoinV2SpendMempoolGracefulPeriod = 10; diff --git a/src/clientversion.h b/src/clientversion.h index 3f60035256..5fbfd54f08 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -16,8 +16,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 14 -#define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 3 +#define CLIENT_VERSION_REVISION 6 +#define CLIENT_VERSION_BUILD 0 //! 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 94fcfb25e3..5c1a86f5db 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace Consensus { @@ -229,6 +231,11 @@ struct Params { // The block number after which lelantus is accepted. int nLelantusStartBlock; + int nLelantusFixesStartBlock; + + // Lelantus Blacklist + std::unordered_set lelantusBlacklist; + // The block number introducing evo sporks int nEvoSporkStartBlock; diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index e538c43b6a..7ac85243ea 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -770,6 +770,11 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (!dmn) { return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash"); } + + if (newList.HasUniqueProperty(proTx.pubKeyOperator) && newList.GetUniquePropertyMN(proTx.pubKeyOperator)->proTxHash != proTx.proTxHash) { + return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-key"); + } + auto newState = std::make_shared(*dmn->pdmnState); if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) { // reset all operator related fields and put MN into PoSe-banned state in case the operator key changes diff --git a/src/lelantus.cpp b/src/lelantus.cpp index 853577efbc..38408ef1f8 100644 --- a/src/lelantus.cpp +++ b/src/lelantus.cpp @@ -13,6 +13,7 @@ #include "liblelantus/coin.h" #include "liblelantus/schnorr_prover.h" #include "liblelantus/schnorr_verifier.h" +#include "liblelantus/challenge_generator_impl.h" #include "primitives/zerocoin.h" #include "policy/policy.h" #include "coins.h" @@ -54,6 +55,27 @@ static bool CheckLelantusSpendSerial( return true; } + +std::vector GetAnonymitySetHash(CBlockIndex *index, int group_id, bool generation = false) { + std::vector out_hash; + + CLelantusState::LelantusCoinGroupInfo coinGroup; + if (!lelantusState.GetCoinGroupInfo(group_id, coinGroup)) + return out_hash; + + if ((coinGroup.firstBlock == coinGroup.lastBlock && generation) || (coinGroup.nCoins == 0)) + return out_hash; + + while (index != coinGroup.firstBlock) { + if (index->anonymitySetHash.count(group_id) > 0) { + out_hash = index->anonymitySetHash[group_id]; + break; + } + index = index->pprev; + } + return out_hash; +} + bool IsLelantusAllowed() { LOCK(cs_main); @@ -74,9 +96,26 @@ void GenerateMintSchnorrProof(const lelantus::PrivateCoin& coin, CDataStream& s { auto params = lelantus::Params::get_default(); + LOCK(cs_main); SchnorrProof schnorrProof; - SchnorrProver schnorrProver(params->get_g(), params->get_h0()); - schnorrProver.proof(coin.getSerialNumber(), coin.getRandomness(), schnorrProof); + + // after nLelantusFixesStartBlock block start to pass whole data to transcript + bool afterFixes = chainActive.Height() >= ::Params().GetConsensus().nLelantusFixesStartBlock; + SchnorrProver schnorrProver(params->get_g(), params->get_h0(), afterFixes); + Scalar v = coin.getVScalar(); + secp_primitives::GroupElement commit = coin.getPublicCoin().getValue(); + secp_primitives::GroupElement comm = commit + (params->get_h1() * v.negate()); + + unique_ptr challengeGenerator; + if (afterFixes) { + // start to use CHash256 which is more secure + challengeGenerator = std::make_unique>(1); + } else { + challengeGenerator = std::make_unique>(0); + } + + // commit (G^s*H1^v*H2^r), comm (G^s*H2^r), and H1^v are used in challenge generation if nLelantusFixesStartBlock is passed + schnorrProver.proof(coin.getSerialNumber(), coin.getRandomness(), comm, commit, (params->get_h1() * v), challengeGenerator, schnorrProof); serializedSchnorrProof << schnorrProof; } @@ -85,9 +124,21 @@ bool VerifyMintSchnorrProof(const uint64_t& v, const secp_primitives::GroupEleme { auto params = lelantus::Params::get_default(); + LOCK(cs_main); + // after nLelantusFixesStartBlock block start to pass whole data to transcript + bool afterFixes = chainActive.Height() >= ::Params().GetConsensus().nLelantusFixesStartBlock; secp_primitives::GroupElement comm = commit + (params->get_h1() * Scalar(v).negate()); - SchnorrVerifier verifier(params->get_g(), params->get_h0()); - return verifier.verify(comm, schnorrProof); + SchnorrVerifier verifier(params->get_g(), params->get_h0(), afterFixes); + unique_ptr challengeGenerator; + if (afterFixes) { + // start to use CHash256 which is more secure + challengeGenerator = std::make_unique>(1); + } else { + challengeGenerator = std::make_unique>(0); + } + + // commit (G^s*H1^v*H2^r), comm (G^s*H2^r), and H1^v are used in challenge generation if nLelantusFixesStartBlock is passed + return verifier.verify(comm, commit, (params->get_h1() * Scalar(v)), schnorrProof, challengeGenerator); } void ParseLelantusMintScript(const CScript& script, secp_primitives::GroupElement& pubcoin, SchnorrProof& schnorrProof, uint256& mintTag) @@ -318,7 +369,10 @@ bool CheckLelantusJoinSplitTransaction( "CheckLelantusJoinSplitTransaction: invalid joinsplit transaction"); } - if (joinsplit->getVersion() != LELANTUS_TX_VERSION_4 && joinsplit->getVersion() != SIGMA_TO_LELANTUS_JOINSPLIT ) { + int jSplitVersion = joinsplit->getVersion(); + + if (jSplitVersion < LELANTUS_TX_VERSION_4 || + (!isVerifyDB && nHeight >= params.nLelantusFixesStartBlock && jSplitVersion != LELANTUS_TX_VERSION_4_5 && jSplitVersion != SIGMA_TO_LELANTUS_JOINSPLIT_FIXED)) { return state.DoS(100, false, NSEQUENCE_INCORRECT, @@ -334,7 +388,7 @@ bool CheckLelantusJoinSplitTransaction( txHashForMetadata = txTemp.GetHash(); LogPrintf("CheckLelantusJoinSplitTransaction: tx version=%d, tx metadata hash=%s\n", - joinsplit->getVersion(), txHashForMetadata.ToString()); + jSplitVersion, txHashForMetadata.ToString()); if (!fStatefulSigmaCheck) { return true; @@ -356,14 +410,16 @@ bool CheckLelantusJoinSplitTransaction( } } - for(auto& idAndHash : joinsplit->getIdAndBlockHashes()) { + std::vector> anonymity_set_hashes; + + for (auto& idAndHash : joinsplit->getIdAndBlockHashes()) { auto& anonymity_set = anonymity_sets[idAndHash.first]; int coinGroupId = idAndHash.first % (CENT / 1000); int64_t intDenom = (idAndHash.first - coinGroupId); intDenom *= 1000; sigma::CoinDenomination denomination; - if(joinsplit->getVersion() == SIGMA_TO_LELANTUS_JOINSPLIT && sigma::IntegerToDenomination(intDenom, denomination)) { + if (joinsplit->isSigmaToLelantus() && sigma::IntegerToDenomination(intDenom, denomination)) { sigma::CSigmaState::SigmaCoinGroupInfo coinGroup; sigma::CSigmaState *sigmaState = sigma::CSigmaState::GetState(); @@ -380,13 +436,13 @@ bool CheckLelantusJoinSplitTransaction( pair denominationAndId = std::make_pair(denomination, coinGroupId); auto lelantusParams = lelantus::Params::get_default(); - while(true) { - if(index->sigmaMintedPubCoins.count(denominationAndId) > 0) { + while (true) { + if (index->sigmaMintedPubCoins.count(denominationAndId) > 0) { BOOST_FOREACH( const sigma::PublicCoin &pubCoinValue, index->sigmaMintedPubCoins[denominationAndId]) { std::vector vch = pubCoinValue.getValue().getvch(); - if(sigma::sigma_blacklist.count(HexStr(vch.begin(), vch.end())) > 0) { + if (sigma::sigma_blacklist.count(HexStr(vch.begin(), vch.end())) > 0) { continue; } lelantus::PublicCoin publicCoin(pubCoinValue.getValue() + lelantusParams->get_h1() * intDenom); @@ -405,10 +461,17 @@ bool CheckLelantusJoinSplitTransaction( CBlockIndex *index = coinGroup.lastBlock; + // find index for block with hash of accumulatorBlockHash or set index to the coinGroup.firstBlock if not found while (index != coinGroup.firstBlock && index->GetBlockHash() != idAndHash.second) index = index->pprev; + // take the hash from last block of anonymity set, it is used at challenge generation if nLelantusFixesStartBlock is passed + if (nHeight >= params.nLelantusFixesStartBlock) { + std::vector set_hash = GetAnonymitySetHash(index, idAndHash.first); + if (!set_hash.empty()) + anonymity_set_hashes.push_back(set_hash); + } // Build a vector with all the public coins with given id before // the block on which the spend occured. // This list of public coins is required by function "Verify" of JoinSplit. @@ -418,6 +481,12 @@ bool CheckLelantusJoinSplitTransaction( BOOST_FOREACH( const auto& pubCoinValue, index->lelantusMintedPubCoins[idAndHash.first]) { + // skip mints from blacklist if nLelantusFixesStartBlock is passed + if (chainActive.Height() >= ::Params().GetConsensus().nLelantusFixesStartBlock) { + if (::Params().GetConsensus().lelantusBlacklist.count(pubCoinValue.first.getValue()) > 0) { + continue; + } + } anonymity_set.push_back(pubCoinValue.first); } } @@ -432,7 +501,7 @@ bool CheckLelantusJoinSplitTransaction( BatchProofContainer* batchProofContainer = BatchProofContainer::get_instance(); Scalar challenge; // if we are collecting proofs, skip verification and collect proofs - passVerify = joinsplit->Verify(anonymity_sets, Cout, Vout, txHashForMetadata, challenge, batchProofContainer->fCollectProofs); + passVerify = joinsplit->Verify(anonymity_sets, anonymity_set_hashes, Cout, Vout, txHashForMetadata, challenge, batchProofContainer->fCollectProofs); // add proofs into container if(batchProofContainer->fCollectProofs) { @@ -441,7 +510,7 @@ bool CheckLelantusJoinSplitTransaction( for(auto itr : anonymity_sets) idAndSizes[itr.first] = itr.second.size(); - batchProofContainer->add(joinsplit.get(), idAndSizes, challenge); + batchProofContainer->add(joinsplit.get(), idAndSizes, challenge, nHeight >= params.nLelantusFixesStartBlock); } if (passVerify) { @@ -478,7 +547,7 @@ bool CheckLelantusJoinSplitTransaction( error("CheckLelantusJoinSplitTransaction: sized of serials and group ids don't match.")); } - if (joinsplit->getVersion() == SIGMA_TO_LELANTUS_JOINSPLIT) { + if (joinsplit->isSigmaToLelantus()) { if (sigmaTxInfo && !sigmaTxInfo->fInfoIsComplete) { for (size_t i = 0; i < serials.size(); i++) { int coinGroupId = ids[i] % (CENT / 1000); @@ -624,7 +693,7 @@ bool CheckLelantusTransaction( } // Check Mint Lelantus Transaction - if (allowLelantus) { + if (allowLelantus && !isVerifyDB) { for (const CTxOut &txout : tx.vout) { if (!txout.scriptPubKey.empty() && txout.scriptPubKey.IsLelantusMint()) { if (!CheckLelantusMintTransaction(txout, state, hashTx, fStatefulSigmaCheck, lelantusTxInfo)) @@ -757,6 +826,7 @@ bool ConnectBlockLelantus( if (!fJustCheck) { pindexNew->lelantusMintedPubCoins.clear(); pindexNew->lelantusSpentSerials.clear(); + pindexNew->anonymitySetHash.clear(); } if (!CheckLelantusBlock(state, *pblock)) { @@ -783,8 +853,52 @@ bool ConnectBlockLelantus( if (fJustCheck) return true; + auto& params = ::Params().GetConsensus(); + CHash256 hash; + std::vector data(GroupElement::serialize_size); + bool updateHash = false; + + // create first anonymity set hash with whole existing set, at HF block + if (pindexNew->nHeight == params.nLelantusFixesStartBlock) { + updateHash = true; + std::vector coins; + lelantusState.GetAnonymitySet(1, false, coins); + for (auto &coin : coins) { + coin.getValue().serialize(data.data()); + hash.Write(data.data(), data.size()); + } + } + if (!pblock->lelantusTxInfo->mints.empty()) { lelantusState.AddMintsToStateAndBlockIndex(pindexNew, pblock); + int latestCoinId = lelantusState.GetLatestCoinID(); + // add coins into hasher, for generating set hash + // if this is HF block just add mint from this block too, + // else hasher is supposed to be empty, so add previous hash first, then coins + if (pindexNew->nHeight >= params.nLelantusFixesStartBlock) { + updateHash = true; + + if (pindexNew->nHeight > params.nLelantusFixesStartBlock) { + // get previous hash of the set, if there is no such, don't write anything + std::vector prev_hash = GetAnonymitySetHash(pindexNew->pprev, latestCoinId, true); + if (!prev_hash.empty()) + hash.Write(prev_hash.data(), 32); + } + + for (auto &coin : pindexNew->lelantusMintedPubCoins[latestCoinId]) { + coin.first.getValue().serialize(data.data()); + hash.Write(data.data(), data.size()); + } + } + } + + // generate hash if we need it + if (updateHash) { + unsigned char hash_result[CSHA256::OUTPUT_SIZE]; + hash.Finalize(hash_result); + auto &out_hash = pindexNew->anonymitySetHash[lelantusState.GetLatestCoinID()]; + out_hash.clear(); + out_hash.insert(out_hash.begin(), std::begin(hash_result), std::end(hash_result)); } } else if (!fJustCheck) { @@ -1240,7 +1354,8 @@ int CLelantusState::GetCoinSetForSpend( int maxHeight, int coinGroupID, uint256& blockHash_out, - std::vector& coins_out) { + std::vector& coins_out, + std::vector& setHash_out) { coins_out.clear(); @@ -1269,13 +1384,22 @@ int CLelantusState::GetCoinSetForSpend( if (id) { if (numberOfCoins == 0) { // latest block satisfying given conditions - // remember block hash + // remember block hash and set hash blockHash_out = block->GetBlockHash(); + setHash_out = GetAnonymitySetHash(block, id); } numberOfCoins += block->lelantusMintedPubCoins[id].size(); - if(block->lelantusMintedPubCoins.count(id) > 0) { - for (const auto &coin : block->lelantusMintedPubCoins[id]) + if (block->lelantusMintedPubCoins.count(id) > 0) { + for (const auto &coin : block->lelantusMintedPubCoins[id]) { + LOCK(cs_main); + // skip mints from blacklist if nLelantusFixesStartBlock is passed + if (chainActive.Height() >= ::Params().GetConsensus().nLelantusFixesStartBlock) { + if (::Params().GetConsensus().lelantusBlacklist.count(coin.first.getValue()) > 0) { + continue; + } + } coins_out.push_back(coin.first); + } } } @@ -1287,6 +1411,58 @@ int CLelantusState::GetCoinSetForSpend( return numberOfCoins; } +void CLelantusState::GetAnonymitySet( + int coinGroupID, + bool fStartLelantusBlacklist, + std::vector& coins_out) { + + coins_out.clear(); + + if (coinGroups.count(coinGroupID) == 0) { + return; + } + + LelantusCoinGroupInfo &coinGroup = coinGroups[coinGroupID]; + auto params = ::Params().GetConsensus(); + LOCK(cs_main); + int maxHeight = fStartLelantusBlacklist ? (chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1)) : (params.nLelantusFixesStartBlock - 1); + + for (CBlockIndex *block = coinGroup.lastBlock;; block = block->pprev) { + + // ignore block heigher than max height + if (block->nHeight > maxHeight) { + continue; + } + + // check coins in group coinGroupID - 1 in the case that using coins from prev group. + int id = 0; + if (CountCoinInBlock(block, coinGroupID)) { + id = coinGroupID; + } else if (CountCoinInBlock(block, coinGroupID - 1)) { + id = coinGroupID - 1; + } + + if (id) { + if(block->lelantusMintedPubCoins.count(id) > 0) { + for (const auto &coin : block->lelantusMintedPubCoins[id]) { + if (fStartLelantusBlacklist && + chainActive.Height() >= ::Params().GetConsensus().nLelantusFixesStartBlock) { + std::vector vch = coin.first.getValue().getvch(); + if (::Params().GetConsensus().lelantusBlacklist.count(coin.first.getValue()) > 0) { + continue; + } + } + coins_out.push_back(coin.first); + } + } + } + + if (block == coinGroup.firstBlock) { + break ; + } + } +} + std::pair CLelantusState::GetMintedCoinHeightAndId( const lelantus::PublicCoin& pubCoin) { auto coinIt = containers.GetMints().find(pubCoin); diff --git a/src/lelantus.h b/src/lelantus.h index 6cfd814844..bcf3d586f2 100644 --- a/src/lelantus.h +++ b/src/lelantus.h @@ -187,7 +187,13 @@ friend bool BuildLelantusStateFromIndex(CChain *, set &); int maxHeight, int id, uint256& blockHash_out, - std::vector& coins_out); + std::vector& coins_out, + std::vector& setHash_out); + + void GetAnonymitySet( + int coinGroupID, + bool fStartLelantusBlacklist, + std::vector& coins_out); // Return height of mint transaction and id of minted coin std::pair GetMintedCoinHeightAndId(const lelantus::PublicCoin& pubCoin); diff --git a/src/liblelantus/challenge_generator.cpp b/src/liblelantus/challenge_generator.cpp deleted file mode 100644 index b1f8f7c71a..0000000000 --- a/src/liblelantus/challenge_generator.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "challenge_generator.h" - -namespace lelantus { - -ChallengeGenerator::ChallengeGenerator() { - data.resize(GroupElement::serialize_size); - scalar_data.resize(32); -} - -void ChallengeGenerator::add(const GroupElement& group_element) { - group_element.serialize(data.data()); - hash.Write(data.data(), data.size()); -} - - -void ChallengeGenerator::add(const std::vector& group_elements) { - for (size_t i = 0; i < group_elements.size(); ++i) { - add(group_elements[i]); - } -} - -void ChallengeGenerator::add(const Scalar& scalar) { - scalar.serialize(scalar_data.data()); - hash.Write(scalar_data.data(), scalar_data.size()); -} - -void ChallengeGenerator::add(const std::vector& scalars) { - for (size_t i = 0; i < scalars.size(); ++i) { - add(scalars[i]); - } -} - -void ChallengeGenerator::get_challenge(Scalar& result_out) { - unsigned char result_data[CSHA256::OUTPUT_SIZE]; - do { - CSHA256 temp_hash = hash; - hash.Finalize(result_data); - hash = temp_hash; - result_out = result_data; - add(result_out); - } while (result_out.isZero() || !result_out.isMember()); -} -}// namespace lelantus diff --git a/src/liblelantus/challenge_generator.h b/src/liblelantus/challenge_generator.h index 362a7f551e..d599d54525 100644 --- a/src/liblelantus/challenge_generator.h +++ b/src/liblelantus/challenge_generator.h @@ -1,28 +1,19 @@ #ifndef FIRO_LELANTUS_CHALLENGE_GENERATOR_H #define FIRO_LELANTUS_CHALLENGE_GENERATOR_H - -#include "../../crypto/sha256.h" #include #include - namespace lelantus { - using namespace secp_primitives; class ChallengeGenerator { - public: - ChallengeGenerator(); - void add(const GroupElement& group_element); - void add(const std::vector& group_elements); - void add(const Scalar& scalar); - void add(const std::vector& scalars); - void get_challenge(Scalar& result_out); - -private: - CSHA256 hash; - std::vector data; - std::vector scalar_data; + virtual ~ChallengeGenerator() {}; + virtual void add(const GroupElement& group_element) = 0; + virtual void add(const std::vector& group_elements) = 0; + virtual void add(const Scalar& scalar) = 0; + virtual void add(const std::vector& scalars) = 0; + virtual void add(const std::vector& data_) = 0; + virtual void get_challenge(Scalar& result_out) = 0; }; }// namespace lelantus diff --git a/src/liblelantus/challenge_generator_impl.h b/src/liblelantus/challenge_generator_impl.h new file mode 100644 index 0000000000..4b2154d0df --- /dev/null +++ b/src/liblelantus/challenge_generator_impl.h @@ -0,0 +1,78 @@ +#ifndef FIRO_LELANTUS_CHALLENGE_GENERATOR_IMPL_H +#define FIRO_LELANTUS_CHALLENGE_GENERATOR_IMPL_H + +#include +#include +#include "../../crypto/sha256.h" +#include "challenge_generator.h" +#include +namespace lelantus { + +using namespace secp_primitives; + +template +class ChallengeGeneratorImpl : public ChallengeGenerator { + +public: + ChallengeGeneratorImpl(int version_ = 0) { + version = version_; + data.resize(GroupElement::serialize_size); + scalar_data.resize(32); + } + + void add(const GroupElement& group_element) { + group_element.serialize(data.data()); + hash.Write(data.data(), data.size()); + } + + void add(const std::vector& group_elements) { + addSize(group_elements.size()); + for (size_t i = 0; i < group_elements.size(); ++i) { + add(group_elements[i]); + } + } + + void add(const Scalar& scalar) { + scalar.serialize(scalar_data.data()); + hash.Write(scalar_data.data(), scalar_data.size()); + } + + void add(const std::vector& scalars) { + addSize(scalars.size()); + for (size_t i = 0; i < scalars.size(); ++i) { + add(scalars[i]); + } + } + + void add(const std::vector& data_) { + hash.Write(data_.data(), data_.size()); + } + + void get_challenge(Scalar& result_out) { + unsigned char result_data[CSHA256::OUTPUT_SIZE]; + do { + Hasher temp_hash = hash; + hash.Finalize(result_data); + hash = temp_hash; + result_out = result_data; + add(result_out); + } while (result_out.isZero() || !result_out.isMember()); + } + +private: + void addSize(uint32_t size) { + if (version >= 1) { + Scalar s(size); + add(s); + } + } +private: + int version; + Hasher hash; + std::vector data; + std::vector scalar_data; +}; + +}// namespace lelantus + +#endif //FIRO_LELANTUS_CHALLENGE_GENERATOR_IMPL_H diff --git a/src/liblelantus/coin.cpp b/src/liblelantus/coin.cpp index 31b3168ec4..66b79fbc82 100644 --- a/src/liblelantus/coin.cpp +++ b/src/liblelantus/coin.cpp @@ -1,4 +1,5 @@ #include "coin.h" +#include "lelantus_primitives.h" #include "primitives/zerocoin.h" namespace lelantus { diff --git a/src/liblelantus/coin.h b/src/liblelantus/coin.h index 2c51eb5580..b5de5c1076 100644 --- a/src/liblelantus/coin.h +++ b/src/liblelantus/coin.h @@ -1,9 +1,9 @@ #ifndef FIRO_LIBLELANTUS_COIN_H #define FIRO_LIBLELANTUS_COIN_H -#include "lelantus_primitives.h" #include "params.h" #include "../sigma/openssl_context.h" +#include "../uint256.h" namespace lelantus { diff --git a/src/liblelantus/innerproduct_proof_generator.cpp b/src/liblelantus/innerproduct_proof_generator.cpp index abb664da8c..b6a36651bd 100755 --- a/src/liblelantus/innerproduct_proof_generator.cpp +++ b/src/liblelantus/innerproduct_proof_generator.cpp @@ -6,10 +6,12 @@ namespace lelantus { InnerProductProofGenerator::InnerProductProofGenerator( const std::vector& g, const std::vector& h, - const GroupElement& u) + const GroupElement& u, + int version) : g_(g) , h_(h) , u_(u) + , version_(version) { } @@ -17,11 +19,13 @@ InnerProductProofGenerator::InnerProductProofGenerator( const std::vector& g, const std::vector& h, const GroupElement& u, - const GroupElement& P) + const GroupElement& P, + int version) : g_(g) , h_(h) , u_(u) , P_(P) + , version_(version) { } @@ -29,18 +33,20 @@ void InnerProductProofGenerator::generate_proof( const std::vector& a, const std::vector& b, const Scalar& x, + unique_ptr& challengeGenerator, InnerProductProof& proof_out) { const Scalar c = LelantusPrimitives::scalar_dot_product(a.begin(), a.end(), b.begin(), b.end()); compute_P(a, b, P_initial); u_ *= x; proof_out.c_ = c; P_ = (P_initial + u_ * c); - generate_proof_util(a, b, proof_out); + generate_proof_util(a, b, challengeGenerator, proof_out); } void InnerProductProofGenerator::generate_proof_util( const std::vector& a, const std::vector& b, + unique_ptr& challengeGenerator, InnerProductProof& proof_out) { if(a.size() != b.size()) @@ -70,7 +76,14 @@ void InnerProductProofGenerator::generate_proof_util( //Get challenge x Scalar x; std::vector group_elements = {L, R}; - LelantusPrimitives::generate_challenge(group_elements, x); + + // if(version_ >= 2) we should be using CHash256, + // we want to link transcripts from previous iteration in each step, so we are not restarting in that case, + if (version_ < 2) { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(x); //Compute g prime and p prime std::vector g_p; @@ -86,7 +99,7 @@ void InnerProductProofGenerator::generate_proof_util( GroupElement p_p = LelantusPrimitives::p_prime(P_, L, R, x); // Recursive call of protocol 2 - InnerProductProofGenerator(g_p, h_p, u_, p_p).generate_proof_util(a_p, b_p, proof_out); + InnerProductProofGenerator(g_p, h_p, u_, p_p, version_).generate_proof_util(a_p, b_p, challengeGenerator, proof_out); } void InnerProductProofGenerator::compute_P( diff --git a/src/liblelantus/innerproduct_proof_generator.h b/src/liblelantus/innerproduct_proof_generator.h index fe1f97aa81..e3add6186e 100755 --- a/src/liblelantus/innerproduct_proof_generator.h +++ b/src/liblelantus/innerproduct_proof_generator.h @@ -2,6 +2,7 @@ #define FIRO_LIBLELANTUS_INNERP_RODUCT_PROOF_GENERATOR_H #include "lelantus_primitives.h" +#include "challenge_generator_impl.h" namespace lelantus { @@ -12,12 +13,14 @@ class InnerProductProofGenerator { InnerProductProofGenerator( const std::vector& g, const std::vector& h, - const GroupElement& u); + const GroupElement& u, + int version); // if(version >= 2) we should pass CHash256 in generate_proof function void generate_proof( const std::vector& a, const std::vector& b, const Scalar& x, + unique_ptr& challengeGenerator, InnerProductProof& proof_out); const GroupElement& get_P(); @@ -28,11 +31,13 @@ class InnerProductProofGenerator { const std::vector& g, const std::vector& h, const GroupElement& u, - const GroupElement& P); + const GroupElement& P, + int version); void generate_proof_util( const std::vector& a, const std::vector& b, + unique_ptr& challengeGenerator, InnerProductProof& proof_out); void l(typename std::vector::const_iterator a_start, @@ -64,6 +69,7 @@ class InnerProductProofGenerator { GroupElement u_; GroupElement P_; GroupElement P_initial; + int version_; }; diff --git a/src/liblelantus/innerproduct_proof_verifier.cpp b/src/liblelantus/innerproduct_proof_verifier.cpp index 69361b8712..2a9f0e22d7 100755 --- a/src/liblelantus/innerproduct_proof_verifier.cpp +++ b/src/liblelantus/innerproduct_proof_verifier.cpp @@ -1,32 +1,37 @@ #include "innerproduct_proof_verifier.h" + namespace lelantus { InnerProductProofVerifier::InnerProductProofVerifier( const std::vector& g, const std::vector& h, const GroupElement& u, - const GroupElement& P) + const GroupElement& P, + int version) : g_(g) , h_(h) , u_(u) , P_(P) + , version_(version) { } bool InnerProductProofVerifier::verify( const Scalar& x, - const InnerProductProof& proof) { + const InnerProductProof& proof, + unique_ptr& challengeGenerator) { auto itr_l = proof.L_.begin(); auto itr_r = proof.R_.begin(); u_ *= x; P_ += u_ * proof.c_; - return verify_util(proof, itr_l, itr_r); + return verify_util(proof, itr_l, itr_r, challengeGenerator); } bool InnerProductProofVerifier::verify_util( const InnerProductProof& proof, typename std::vector::const_iterator itr_l, - typename std::vector::const_iterator itr_r) { + typename std::vector::const_iterator itr_r, + unique_ptr& challengeGenerator) { if(itr_l == proof.L_.end()){ Scalar c = proof.a_ * proof.b_; GroupElement uc = u_ * c; @@ -37,7 +42,14 @@ bool InnerProductProofVerifier::verify_util( //Get challenge x Scalar x; std::vector group_elements = {*itr_l, *itr_r}; - LelantusPrimitives::generate_challenge(group_elements, x); + + // if(version >= 2) we should be using CHash256, + // we want to link transcripts from previous iteration in each step, so we are not restarting in that case, + if (version_ < 2) { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(x); //Compute g prime and p prime std::vector g_p; @@ -47,25 +59,33 @@ bool InnerProductProofVerifier::verify_util( //Compute P prime GroupElement p_p = LelantusPrimitives::p_prime(P_, *itr_l, *itr_r, x); - return InnerProductProofVerifier(g_p, h_p, u_, p_p).verify_util(proof, itr_l + 1, itr_r + 1); + return InnerProductProofVerifier(g_p, h_p, u_, p_p, version_).verify_util(proof, itr_l + 1, itr_r + 1, challengeGenerator); } -bool InnerProductProofVerifier::verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof) { +bool InnerProductProofVerifier::verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr& challengeGenerator) { u_ *= x; P_ += u_ * proof.c_; - return verify_fast_util(n, proof); + return verify_fast_util(n, proof, challengeGenerator); } bool InnerProductProofVerifier::verify_fast_util( uint64_t n, - const InnerProductProof& proof){ + const InnerProductProof& proof, + unique_ptr& challengeGenerator){ std::size_t log_n = proof.L_.size(); std::vector x_j; x_j.resize(log_n); for (std::size_t i = 0; i < log_n; ++i) { std::vector group_elements = {proof.L_[i], proof.R_[i]}; - LelantusPrimitives::generate_challenge(group_elements, x_j[i]); + + // if(version_ >= 2) we should be using CHash256, + // we want to link transcripts from previous iteration in each step, so we are not restarting in that case, + if (version_ < 2) { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(x_j[i]); } std::vector s, s_inv; s.resize(n); diff --git a/src/liblelantus/innerproduct_proof_verifier.h b/src/liblelantus/innerproduct_proof_verifier.h index 2b18ba78c1..b89d83e077 100755 --- a/src/liblelantus/innerproduct_proof_verifier.h +++ b/src/liblelantus/innerproduct_proof_verifier.h @@ -2,6 +2,7 @@ #define FIRO_LIBLELANTUS_INNER_PRODUCT_PROOF_VERIFIER_H #include "lelantus_primitives.h" +#include "challenge_generator_impl.h" namespace lelantus { @@ -13,24 +14,27 @@ class InnerProductProofVerifier { const std::vector& g, const std::vector& h, const GroupElement& u, - const GroupElement& P); + const GroupElement& P, + int version); // if(version >= 2) we should pass CHash256 in verify - bool verify(const Scalar& x, const InnerProductProof& proof); - bool verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof); + bool verify(const Scalar& x, const InnerProductProof& proof, unique_ptr& challengeGenerator); + bool verify_fast(uint64_t n, const Scalar& x, const InnerProductProof& proof, unique_ptr& challengeGenerator); private: bool verify_util( const InnerProductProof& proof, typename std::vector::const_iterator ltr_l, - typename std::vector::const_iterator itr_r); + typename std::vector::const_iterator itr_r, + unique_ptr& challengeGenerator); - bool verify_fast_util(uint64_t n, const InnerProductProof& proof); + bool verify_fast_util(uint64_t n, const InnerProductProof& proof, unique_ptr& challengeGenerator); private: const std::vector& g_; const std::vector& h_; GroupElement u_; GroupElement P_; + int version_; }; diff --git a/src/liblelantus/joinsplit.cpp b/src/liblelantus/joinsplit.cpp index 2f2ff0bb9d..fd2374657e 100644 --- a/src/liblelantus/joinsplit.cpp +++ b/src/liblelantus/joinsplit.cpp @@ -9,14 +9,17 @@ namespace lelantus { JoinSplit::JoinSplit(const Params *p, const std::vector>& Cin, const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const Scalar& Vout, const std::vector& Cout, uint64_t fee, const std::map& groupBlockHashes, - const uint256& txHash) + const uint256& txHash, + unsigned int nVersion) : params (p), - fee (fee){ + fee (fee), + version (nVersion) { serialNumbers.reserve(Cin.size()); for(size_t i = 0; i < Cin.size(); i++) { @@ -43,9 +46,11 @@ JoinSplit::JoinSplit(const Params *p, coinNum = Cin.size(); - LelantusProver prover(p); + // generate public keys here, as we need it for challenge generation starting from LELANTUS_TX_VERSION_4_5 + generatePubKeys(Cin); - prover.proof(anonymity_sets, uint64_t(0), Cin, indexes, Vout, Cout, fee, lelantusProof); + LelantusProver prover(p, version); + prover.proof(anonymity_sets, anonymity_set_hashes, uint64_t(0), Cin, indexes, ecdsaPubkeys, Vout, Cout, fee, lelantusProof, qkSchnorrProof); if(groupBlockHashes.size() != anonymity_sets.size()) throw std::invalid_argument("Mismatch blockHashes and anonymity sets sizes."); @@ -57,24 +62,14 @@ JoinSplit::JoinSplit(const Params *p, coinGroupIdAndBlockHash = m.coinGroupIdAndBlockHash; } -void JoinSplit::signMetaData(const std::vector>& Cin, const SpendMetaData& m, size_t coutSize) { - // Proves that the coin is correct w.r.t. serial number and hidden coin secret - // (This proof is bound to the coin 'metadata', i.e., transaction hash) - uint256 metahash = signatureHash(m, coutSize); - - - ecdsaSignatures.resize(Cin.size()); +void JoinSplit::generatePubKeys(const std::vector>& Cin) { ecdsaPubkeys.resize(Cin.size()); - for(size_t i = 0; i < Cin.size(); i++) { // Sign each spend under the public key associate with the serial number. secp256k1_pubkey pubkey; size_t pubkeyLen = 33; - secp256k1_ecdsa_signature sig; - - ecdsaSignatures[i].resize(64); - ecdsaPubkeys[i].resize(33); + ecdsaPubkeys[i].resize(pubkeyLen); // TODO timing channel, since secp256k1_ec_pubkey_serialize does not expect its output to be secret. // See main_impl.h of ecdh module on secp256k1 if (!secp256k1_ec_pubkey_create( @@ -86,7 +81,20 @@ void JoinSplit::signMetaData(const std::vector> &this->ecdsaPubkeys[i][0], &pubkeyLen, &pubkey, SECP256K1_EC_COMPRESSED)) { throw std::invalid_argument("Unable to serialize public key"); } + } +} + +void JoinSplit::signMetaData(const std::vector>& Cin, const SpendMetaData& m, size_t coutSize) { + // Proves that the coin is correct w.r.t. serial number and hidden coin secret + // (This proof is bound to the coin 'metadata', i.e., transaction hash) + uint256 metahash = signatureHash(m, coutSize); + + ecdsaSignatures.resize(Cin.size()); + for(size_t i = 0; i < Cin.size(); i++) { + // Sign each spend under the public key associate with the serial number. + secp256k1_ecdsa_signature sig; + ecdsaSignatures[i].resize(64); if (1 != secp256k1_ecdsa_sign( OpenSSLContext::get_context(), &sig, metahash.begin(), Cin[i].first.getEcdsaSeckey(), NULL, NULL)) { @@ -96,23 +104,23 @@ void JoinSplit::signMetaData(const std::vector> OpenSSLContext::get_context(), &this->ecdsaSignatures[i][0], &sig)) { throw std::invalid_argument("Unable to serialize ecdsa_signature."); } - } - } bool JoinSplit::Verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& Cout, uint64_t Vout, const uint256& txHash) const { Scalar challenge; bool fSkipVerification = false; - return Verify(anonymity_sets, Cout, Vout, txHash, challenge, fSkipVerification); + return Verify(anonymity_sets, anonymity_set_hashes, Cout, Vout, txHash, challenge, fSkipVerification); } bool JoinSplit::Verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& Cout, uint64_t Vout, const uint256& txHash, @@ -171,8 +179,8 @@ bool JoinSplit::Verify( } // Now verify lelantus proof - LelantusVerifier verifier(params); - return verifier.verify(anonymity_sets, serialNumbers, groupIds, uint64_t(0),Vout, fee, Cout, lelantusProof, challenge, fSkipVerification); + LelantusVerifier verifier(params, version); + return verifier.verify(anonymity_sets, anonymity_set_hashes, serialNumbers, ecdsaPubkeys, groupIds, uint64_t(0),Vout, fee, Cout, lelantusProof, qkSchnorrProof, challenge, fSkipVerification); } @@ -219,4 +227,8 @@ bool JoinSplit::HasValidSerials() const { return true; } +bool JoinSplit::isSigmaToLelantus() const { + return version == SIGMA_TO_LELANTUS_JOINSPLIT || version == SIGMA_TO_LELANTUS_JOINSPLIT_FIXED; +} + } //namespace lelantus \ No newline at end of file diff --git a/src/liblelantus/joinsplit.h b/src/liblelantus/joinsplit.h index ff10d0cc6b..d5975019b6 100644 --- a/src/liblelantus/joinsplit.h +++ b/src/liblelantus/joinsplit.h @@ -4,6 +4,7 @@ #include "coin.h" #include "lelantus_proof.h" #include "spend_metadata.h" +#include "../libzerocoin/Zerocoin.h" namespace lelantus { @@ -18,24 +19,30 @@ class JoinSplit { JoinSplit(const Params* p, const std::vector>& Cin, const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const Scalar& Vout, const std::vector& Cout, uint64_t fee, const std::map& groupBlockHashes, - const uint256& txHash); + const uint256& txHash, + unsigned int nVersion); bool Verify(const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& Cout, uint64_t Vout, const uint256& txHash) const; bool Verify(const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& Cout, uint64_t Vout, const uint256& txHash, Scalar& challenge, bool fSkipVerification = false) const; + void generatePubKeys(const std::vector>& Cin); + void signMetaData(const std::vector>& Cin, const SpendMetaData& m, size_t coutSize); uint256 signatureHash(const SpendMetaData& m, size_t coutSize) const; @@ -62,6 +69,8 @@ class JoinSplit { bool HasValidSerials() const; + bool isSigmaToLelantus() const; + ADD_SERIALIZE_METHODS; template void SerializationOp(Stream& s, Operation ser_action) @@ -97,6 +106,9 @@ class JoinSplit { READWRITE(fee); READWRITE(version); + if (version >= LELANTUS_TX_VERSION_4_5) + READWRITE(qkSchnorrProof); + if (ser_action.ForRead()) { serialNumbers.resize(coinNum); for(size_t i = 0; i < coinNum; i++) { @@ -114,6 +126,7 @@ class JoinSplit { const Params* params; unsigned int version = 0; LelantusProof lelantusProof; + SchnorrProof qkSchnorrProof; uint8_t coinNum; std::vector serialNumbers; std::vector groupIds; diff --git a/src/liblelantus/lelantus_primitives.cpp b/src/liblelantus/lelantus_primitives.cpp index 624161a380..486463886f 100644 --- a/src/liblelantus/lelantus_primitives.cpp +++ b/src/liblelantus/lelantus_primitives.cpp @@ -1,24 +1,35 @@ #include "lelantus_primitives.h" -#include "challenge_generator.h" +#include "challenge_generator_impl.h" namespace lelantus { + +static std::string lts("LELANTUS_SIGMA"); void LelantusPrimitives::generate_challenge( const std::vector& group_elements, + const std::string& domain_separator, Scalar& result_out) { if (group_elements.empty()) throw std::runtime_error("Group elements empty while generating a challenge."); - ChallengeGenerator challengeGenerator; - challengeGenerator.add(group_elements); - challengeGenerator.get_challenge(result_out); + std::unique_ptr challengeGenerator; + if (domain_separator != "") { + challengeGenerator = std::make_unique>(1); + std::vector pre(domain_separator.begin(), domain_separator.end()); + challengeGenerator->add(pre); + } else { + challengeGenerator = std::make_unique>(0); + } + + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(result_out); } void LelantusPrimitives::commit(const GroupElement& g, - const std::vector& h, - const std::vector& exp, - const Scalar& r, - GroupElement& result_out) { + const std::vector& h, + const std::vector& exp, + const Scalar& r, + GroupElement& result_out) { secp_primitives::MultiExponent mult(h, exp); result_out = g * r + mult.get_multiple(); } @@ -80,28 +91,47 @@ std::vector LelantusPrimitives::convert_to_nal( void LelantusPrimitives::generate_Lelantus_challenge( const std::vector& proofs, + const std::vector>& anonymity_set_hashes, + const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& Cout, + unsigned int version, + unique_ptr& challengeGenerator, Scalar& result_out) { result_out = uint64_t(1); - ChallengeGenerator challengeGenerator; - if(Cout.size() > 0) { - for(auto coin : Cout) - challengeGenerator.add(coin); + // starting from LELANTUS_TX_VERSION_4_5 we are using CHash256, and adding domain separator, version, pubkeys and serials into it + if (version >= LELANTUS_TX_VERSION_4_5) { + challengeGenerator = std::make_unique>(1); + std::string domainSeparator = lts + std::to_string(version); + std::vector pre(domainSeparator.begin(), domainSeparator.end()); + challengeGenerator->add(pre); + for (const auto& hash : anonymity_set_hashes) + challengeGenerator->add(hash); + for (const auto& pubkey : ecdsaPubkeys) + challengeGenerator->add(pubkey); + challengeGenerator->add(serialNumbers); + } else { + challengeGenerator = std::make_unique>(0); + } + + if (Cout.size() > 0) { + for (auto coin : Cout) + challengeGenerator->add(coin); } if (proofs.size() > 0) { for (std::size_t i = 0; i < proofs.size(); ++i) { - challengeGenerator.add(proofs[i].A_); - challengeGenerator.add(proofs[i].B_); - challengeGenerator.add(proofs[i].C_); - challengeGenerator.add(proofs[i].D_); - challengeGenerator.add(proofs[i].Gk_); - challengeGenerator.add(proofs[i].Qk); + challengeGenerator->add(proofs[i].A_); + challengeGenerator->add(proofs[i].B_); + challengeGenerator->add(proofs[i].C_); + challengeGenerator->add(proofs[i].D_); + challengeGenerator->add(proofs[i].Gk_); + challengeGenerator->add(proofs[i].Qk); } - challengeGenerator.get_challenge(result_out); + challengeGenerator->get_challenge(result_out); } } diff --git a/src/liblelantus/lelantus_primitives.h b/src/liblelantus/lelantus_primitives.h index 79890c57b7..e045d58cc3 100644 --- a/src/liblelantus/lelantus_primitives.h +++ b/src/liblelantus/lelantus_primitives.h @@ -9,6 +9,7 @@ #include "schnorr_proof.h" #include "innerproduct_proof.h" #include "range_proof.h" +#include "challenge_generator.h" #include "serialize.h" #include "../libzerocoin/Zerocoin.h" @@ -25,8 +26,11 @@ struct NthPower { NthPower(const Scalar& num_) : num(num_), pow(uint64_t(1)) {} NthPower(const Scalar& num_, const Scalar& pow_) : num(num_), pow(pow_) {} + // be careful and verify that you have catch on upper level void go_next() { pow *= num; + if (pow == Scalar(uint64_t(1))) + throw std::invalid_argument("NthPower resulted 1"); } }; @@ -36,6 +40,7 @@ class LelantusPrimitives { ////common functions static void generate_challenge( const std::vector& group_elements, + const std::string& domain_separator, Scalar& result_out); static GroupElement commit( @@ -63,7 +68,15 @@ class LelantusPrimitives { static std::vector convert_to_nal(uint64_t num, uint64_t n, uint64_t m); - static void generate_Lelantus_challenge(const std::vector& proofs, const std::vector& Cout, Scalar& result_out); + static void generate_Lelantus_challenge( + const std::vector& proofs, + const std::vector>& anonymity_set_hashes, + const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, + const std::vector& Cout, + unsigned int version, + unique_ptr& challengeGenerator, + Scalar& result_out); static void new_factor(const Scalar& x, const Scalar& a, std::vector& coefficients); //// functions for bulletproofs diff --git a/src/liblelantus/lelantus_proof.h b/src/liblelantus/lelantus_proof.h index 0e8db835c5..463c7ac276 100644 --- a/src/liblelantus/lelantus_proof.h +++ b/src/liblelantus/lelantus_proof.h @@ -1,6 +1,7 @@ #ifndef FIRO_LIBLELANTUS_LELANTUSPROOF_H #define FIRO_LIBLELANTUS_LELANTUSPROOF_H +#include "sigmaextended_proof.h" #include "schnorr_proof.h" #include "range_proof.h" #include "params.h" diff --git a/src/liblelantus/lelantus_prover.cpp b/src/liblelantus/lelantus_prover.cpp index 8d374c1492..39654f3cd9 100644 --- a/src/liblelantus/lelantus_prover.cpp +++ b/src/liblelantus/lelantus_prover.cpp @@ -2,18 +2,21 @@ namespace lelantus { -LelantusProver::LelantusProver(const Params* p) : params(p) { +LelantusProver::LelantusProver(const Params* p, unsigned int v) : params(p), version(v) { } void LelantusProver::proof( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const Scalar& Vin, const std::vector>& Cin, const std::vector& indexes, + const std::vector>& ecdsaPubkeys, const Scalar& Vout, const std::vector& Cout, const Scalar& fee, - LelantusProof& proof_out) { + LelantusProof& proof_out, + SchnorrProof& qkSchnorrProof) { Scalar input = Vin; for (std::size_t i = 0; i < Cin.size(); ++i) input += Cin[i].first.getV(); @@ -23,13 +26,15 @@ void LelantusProver::proof( out += Cout[i].getV(); out += fee; - if(input != out) + if (input != out) throw ZerocoinException("Input and output are not equal"); Scalar x; std::vector Yk_sum; Yk_sum.resize(Cin.size()); - generate_sigma_proofs(anonymity_sets, Cin, Cout, indexes, x, Yk_sum, proof_out.sigma_proofs); + // we are passing challengeGenerator ptr here, as after LELANTUS_TX_VERSION_4_5 we need it back, with filled data, to use in schnorr proof, + unique_ptr challengeGenerator; + generate_sigma_proofs(anonymity_sets, anonymity_set_hashes, Cin, Cout, indexes, ecdsaPubkeys, x, challengeGenerator, Yk_sum, proof_out.sigma_proofs, qkSchnorrProof); generate_bulletproofs(Cout, proof_out.bulletproofs); @@ -38,35 +43,46 @@ void LelantusProver::proof( Scalar X_; Scalar So; Scalar Ro; + GroupElement A; for (std::size_t i = 0; i < Cout.size(); ++i) { So += Cout[i].getSerialNumber(); Ro += Cout[i].getRandomness(); + A += Cout[i].getPublicCoin().getValue(); } X_ = So * x_m; - + A *= x_m; + A += params->get_h1() * ((Vout + fee) * x_m); Scalar Y_; Scalar Ri; + Scalar Vi = Vin; for (std::size_t i = 0; i < Cin.size(); ++i) { Ri += Cin[i].first.getRandomness() * x_m + Yk_sum[i]; + Vi += Cin[i].first.getVScalar(); } Y_ = Ro * x_m - Ri; - - SchnorrProver schnorrProver(params->get_g(), params->get_h0()); - - schnorrProver.proof(X_, Y_, proof_out.schnorrProof); - + Vi *= x_m; + // we are calculating A, B amd Y here as after LELANTUS_TX_VERSION_4_5 we need them for challenge generation in schnorr proof + // also we are getting challengeGenerator with filled data from sigma, + GroupElement B = params->get_h1() * Vi + params->get_h0() * Ri; + GroupElement Y = A + B.inverse(); + SchnorrProver schnorrProver(params->get_g(), params->get_h0(), version >= LELANTUS_TX_VERSION_4_5); + schnorrProver.proof(X_, Y_, Y, A, B, challengeGenerator, proof_out.schnorrProof); } void LelantusProver::generate_sigma_proofs( const std::map>& c, + const std::vector>& anonymity_set_hashes, const std::vector>& Cin, const std::vector& Cout, const std::vector& indexes, + const std::vector>& ecdsaPubkeys, Scalar& x, + unique_ptr& challengeGenerator, std::vector& Yk_sum, - std::vector& sigma_proofs) { + std::vector& sigma_proofs, + SchnorrProof& qkSchnorrProof) { SigmaExtendedProver sigmaProver(params->get_g(), params->get_sigma_h(), params->get_sigma_n(), params->get_sigma_m()); sigma_proofs.resize(Cin.size()); std::size_t N = Cin.size(); @@ -83,12 +99,15 @@ void LelantusProver::generate_sigma_proofs( Yk.resize(N); std::vector> a; a.resize(N); + std::vector serialNumbers; + serialNumbers.reserve(N); for (std::size_t i = 0; i < N; ++i) { if (!c.count(Cin[i].second)) throw std::invalid_argument("No such anonymity set or id is not correct"); GroupElement gs = (params->get_g() * Cin[i].first.getSerialNumber().negate()); + serialNumbers.emplace_back(Cin[i].first.getSerialNumber()); std::vector C_; C_.reserve(c.size()); @@ -114,7 +133,15 @@ void LelantusProver::generate_sigma_proofs( PubcoinsOut.reserve(Cout.size()); for(auto coin : Cout) PubcoinsOut.emplace_back(coin.getPublicCoin().getValue()); - LelantusPrimitives::generate_Lelantus_challenge(sigma_proofs, PubcoinsOut, x); + LelantusPrimitives::generate_Lelantus_challenge( + sigma_proofs, + anonymity_set_hashes, + serialNumbers, + ecdsaPubkeys, + PubcoinsOut, + version, + challengeGenerator, + x); std::vector x_ks; x_ks.reserve(params->get_sigma_m()); @@ -130,35 +157,60 @@ void LelantusProver::generate_sigma_proofs( } } - for(std::size_t i = 0; i < N; ++i){ + for (std::size_t i = 0; i < N; ++i){ const Scalar& v = Cin[i].first.getV(); const Scalar& r = Cin[i].first.getRandomness(); sigmaProver.sigma_response(sigma[i], a[i], rA[i], rB[i], rC[i], rD[i], v, r, Tk[i], Pk[i], x, sigma_proofs[i]); } + + // generate schnorr proof to prove that Q_k is generated honestly; + if (version >= LELANTUS_TX_VERSION_4_5) { + Scalar q_k_x; + challengeGenerator->get_challenge(q_k_x); + NthPower qk_x_n(q_k_x); + + Scalar Pk_sum(uint64_t(0)); + Scalar Tk_Yk_sum(uint64_t(0)); + std::vector Qk; + Qk.reserve(N * params->get_sigma_m()); + for (std::size_t i = 0; i < N; ++i) { + for (std::size_t j = 0; j < params->get_sigma_m(); ++j) { + Pk_sum += (Pk[i][j] * qk_x_n.pow); + Tk_Yk_sum += ((Tk[i][j] + Yk[i][j]) * qk_x_n.pow); + qk_x_n.go_next(); + Qk.emplace_back(sigma_proofs[i].Qk[j]); + } + } + + SchnorrProver schnorrProver(params->get_h1(), params->get_h0(), true); + schnorrProver.proof(Pk_sum, Tk_Yk_sum, Qk, qkSchnorrProof); + } } void LelantusProver::generate_bulletproofs( - const std::vector & Cout, + const std::vector& Cout, RangeProof& bulletproofs) { - if(Cout.empty()) + if (Cout.empty()) return; std::vector v_s, serials, randoms; std::size_t n = params->get_bulletproofs_n(); std::size_t m = Cout.size() * 2; - while(m & (m - 1)) + while (m & (m - 1)) m++; v_s.reserve(m); serials.reserve(m); randoms.reserve(m); + std::vector commitments(Cout.size()); for (std::size_t i = 0; i < Cout.size(); ++i) { v_s.push_back(Cout[i].getV()); v_s.push_back(Cout[i].getVScalar() + params->get_limit_range()); serials.insert(serials.end(), 2, Cout[i].getSerialNumber()); randoms.insert(randoms.end(), 2, Cout[i].getRandomness()); + commitments.emplace_back(Cout[i].getPublicCoin().getValue()); } v_s.resize(m); @@ -173,8 +225,8 @@ void LelantusProver::generate_bulletproofs( g_.insert(g_.end(), params->get_bulletproofs_g().begin(), params->get_bulletproofs_g().begin() + (n * m)); h_.insert(h_.end(), params->get_bulletproofs_h().begin(), params->get_bulletproofs_h().begin() + (n * m)); - RangeProver rangeProver(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n); - rangeProver.batch_proof(v_s, serials, randoms, bulletproofs); + RangeProver rangeProver(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n, version); + rangeProver.batch_proof(v_s, serials, randoms, commitments, bulletproofs); } diff --git a/src/liblelantus/lelantus_prover.h b/src/liblelantus/lelantus_prover.h index b19af05632..1f266684be 100644 --- a/src/liblelantus/lelantus_prover.h +++ b/src/liblelantus/lelantus_prover.h @@ -10,26 +10,33 @@ namespace lelantus { class LelantusProver { public: - LelantusProver(const Params* p); + LelantusProver(const Params* p, unsigned int v); void proof( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const Scalar& Vin, const std::vector>& Cin, const std::vector & indexes, + const std::vector>& ecdsaPubkeys, const Scalar& Vout, const std::vector & Cout, const Scalar& fee, - LelantusProof& proof_out); + LelantusProof& proof_out, + SchnorrProof& qkSchnorrProof); private: void generate_sigma_proofs( const std::map>& c, + const std::vector>& anonymity_set_hashes, const std::vector>& Cin, const std::vector& Cout, const std::vector& indexes, + const std::vector>& ecdsaPubkeys, Scalar& x, + unique_ptr& challengeGenerator, std::vector& Yk_sum, - std::vector& sigma_proofs); + std::vector& sigma_proofs, + SchnorrProof& qkSchnorrProof); void generate_bulletproofs( const std::vector & Cout, @@ -37,6 +44,7 @@ class LelantusProver { private: const Params* params; + unsigned int version; }; }// namespace lelantus diff --git a/src/liblelantus/lelantus_verifier.cpp b/src/liblelantus/lelantus_verifier.cpp index 9b4e083c6e..5ac8350958 100644 --- a/src/liblelantus/lelantus_verifier.cpp +++ b/src/liblelantus/lelantus_verifier.cpp @@ -5,40 +5,58 @@ namespace lelantus { -LelantusVerifier::LelantusVerifier(const Params* p) : params(p) { +LelantusVerifier::LelantusVerifier(const Params* p, unsigned int v) : params(p), version(v) { } bool LelantusVerifier::verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& groupIds, const Scalar& Vin, uint64_t Vout, uint64_t fee, const std::vector& Cout, - const LelantusProof& proof) { + const LelantusProof& proof, + const SchnorrProof& qkSchnorrProof) { Scalar x; bool fSkipVerification = 0; - return verify(anonymity_sets, serialNumbers, groupIds, Vin, Vout, fee, Cout, proof, x, fSkipVerification); + return verify(anonymity_sets, anonymity_set_hashes, serialNumbers, ecdsaPubkeys, groupIds, Vin, Vout, fee, Cout, proof, qkSchnorrProof, x, fSkipVerification); } bool LelantusVerifier::verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& groupIds, const Scalar& Vin, uint64_t Vout, uint64_t fee, const std::vector& Cout, const LelantusProof& proof, + const SchnorrProof& qkSchnorrProof, Scalar& x, bool fSkipVerification) { //check the overflow of Vout and fee - if(!(Vout <= uint64_t(::Params().GetConsensus().nMaxValueLelantusSpendPerTransaction) && fee < (1000 * CENT))) { // 1000 * CENT is the value of max fee defined at validation.h + if (!(Vout <= uint64_t(::Params().GetConsensus().nMaxValueLelantusSpendPerTransaction) && fee < (1000 * CENT))) { // 1000 * CENT is the value of max fee defined at validation.h LogPrintf("Lelantus verification failed due to transparent values check failed."); return false; } + // number of serials should be equal to number of sigma proofs, we need one proof for each serial + if (serialNumbers.size() != proof.sigma_proofs.size()) { + LogPrintf("Lelantus verification failed due to sizes of serials and sigma proofs are not equal."); + return false; + } + + // max possible number of output coins is 8, + if (Cout.size() > (params->get_bulletproofs_max_m() / 2)) { + LogPrintf("Number of output coins are more than allowed."); + return false; + } + std::vector> vAnonymity_sets; std::vector> vSin; vAnonymity_sets.reserve(anonymity_sets.size()); @@ -46,7 +64,7 @@ bool LelantusVerifier::verify( size_t i = 0; auto itr = vSin.begin(); - for(const auto& set : anonymity_sets) { + for (const auto& set : anonymity_sets) { vAnonymity_sets.emplace_back(set.second); while (i < groupIds.size() && groupIds[i] == set.first) { @@ -56,36 +74,57 @@ bool LelantusVerifier::verify( } Scalar zV, zR; - if(!(verify_sigma(vAnonymity_sets, vSin, Cout, proof.sigma_proofs, x, zV, zR, fSkipVerification) && - verify_rangeproof(Cout, proof.bulletproofs) && - verify_schnorrproof(x, zV, zR, Vin, Vout, fee, Cout, proof))) + unique_ptr challengeGenerator; + try { + // we are passing challengeGenerator ptr here, as after LELANTUS_TX_VERSION_4_5 we need it back, with filled data, to use in schnorr proof, + if (!(verify_sigma(vAnonymity_sets, anonymity_set_hashes, vSin, serialNumbers, ecdsaPubkeys, Cout, proof.sigma_proofs, qkSchnorrProof, x, challengeGenerator, zV, zR, fSkipVerification) && + verify_rangeproof(Cout, proof.bulletproofs) && + verify_schnorrproof(x, zV, zR, Vin, Vout, fee, Cout, proof, challengeGenerator))) + return false; + } catch (std::invalid_argument&) { return false; + } + return true; } bool LelantusVerifier::verify_sigma( const std::vector>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector>& Sin, + const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& Cout, const std::vector &sigma_proofs, + const SchnorrProof& qkSchnorrProof, Scalar& x, + unique_ptr& challengeGenerator, Scalar& zV, Scalar& zR, bool fSkipVerification) { std::vector PubcoinsOut; PubcoinsOut.reserve(Cout.size()); - for(auto coin : Cout) + for (auto coin : Cout) PubcoinsOut.emplace_back(coin.getValue()); - LelantusPrimitives::generate_Lelantus_challenge(sigma_proofs, PubcoinsOut, x); + LelantusPrimitives::generate_Lelantus_challenge( + sigma_proofs, + anonymity_set_hashes, + serialNumbers, + ecdsaPubkeys, + PubcoinsOut, + version, + challengeGenerator, + x); + SigmaExtendedVerifier sigmaVerifier(params->get_g(), params->get_sigma_h(), params->get_sigma_n(), params->get_sigma_m()); - if(Sin.size() != anonymity_sets.size()) + if (Sin.size() != anonymity_sets.size()) throw std::invalid_argument("Number of anonymity sets and number of vectors containing serial numbers must be equal"); int t = 0; - for(std::size_t k = 0; k < Sin.size(); k++) { + for (std::size_t k = 0; k < Sin.size(); k++) { std::vector sigma_proofs_k; for (std::size_t i = 0; i < Sin[k].size(); ++i, ++t) { @@ -95,7 +134,7 @@ bool LelantusVerifier::verify_sigma( } //skip verification if we are collecting proofs for later batch verification - if(fSkipVerification) + if (fSkipVerification) continue; std::vector C_; @@ -108,13 +147,42 @@ bool LelantusVerifier::verify_sigma( return false; } } + + // verify schnorr proof to verify that Q_k is generated honestly; + if (version >= LELANTUS_TX_VERSION_4_5) { + Scalar q_k_x; + challengeGenerator->get_challenge(q_k_x); + + NthPower qK_x_n(q_k_x); + GroupElement Gk_sum; + std::vector Qks; + Qks.reserve(sigma_proofs.size() * params->get_sigma_m()); + for (std::size_t t = 0; t < sigma_proofs.size(); ++t) + { + const std::vector& Qk = sigma_proofs[t].Qk; + for (std::size_t k = 0; k < Qk.size(); ++k) + { + Gk_sum += (Qk[k]) * qK_x_n.pow; + qK_x_n.go_next(); + + Qks.emplace_back(Qk[k]); + } + } + + SchnorrVerifier schnorrVerifier(params->get_h1(), params->get_h0(), version >= LELANTUS_TX_VERSION_4_5); + if (!schnorrVerifier.verify(Gk_sum, Qks, qkSchnorrProof)) { + LogPrintf("Lelantus verification failed due to Qk schnorr proof verification failed."); + return false; + } + } + return true; } bool LelantusVerifier::verify_rangeproof( const std::vector& Cout, const RangeProof& bulletproofs) { - if(Cout.empty()) + if (Cout.empty()) return true; std::size_t n = params->get_bulletproofs_n(); @@ -131,16 +199,18 @@ bool LelantusVerifier::verify_rangeproof( std::vector V; V.reserve(m); + std::vector commitments(Cout.size()); for (std::size_t i = 0; i < Cout.size(); ++i) { V.push_back(Cout[i].getValue()); V.push_back(Cout[i].getValue() + params->get_h1_limit_range()); + commitments.emplace_back(Cout[i].getValue()); } for (std::size_t i = Cout.size() * 2; i < m; ++i) V.push_back(GroupElement()); - RangeVerifier rangeVerifier(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n); - if (!rangeVerifier.verify_batch(V, bulletproofs)) { + RangeVerifier rangeVerifier(params->get_h1(), params->get_h0(), params->get_g(), g_, h_, n, version); + if (!rangeVerifier.verify_batch(V, commitments, bulletproofs)) { LogPrintf("Lelantus verification failed due range proof verification failed."); return false; } @@ -155,11 +225,12 @@ bool LelantusVerifier::verify_schnorrproof( const Scalar& Vout, const Scalar fee, const std::vector& Cout, - const LelantusProof& proof) { + const LelantusProof& proof, + unique_ptr& challengeGenerator) { GroupElement A; for (std::size_t i = 0; i < Cout.size(); ++i) A += Cout[i].getValue(); - if(Cout.size() > 0) + if (Cout.size() > 0) A *= x.exponent(params->get_sigma_m()); A += params->get_h1() * ((Vout + fee) * x.exponent(params->get_sigma_m())); @@ -187,10 +258,11 @@ bool LelantusVerifier::verify_schnorrproof( Comm += Comm_t; } B += Comm; - SchnorrVerifier schnorrVerifier(params->get_g(), params->get_h0()); + SchnorrVerifier schnorrVerifier(params->get_g(), params->get_h0(), version >= LELANTUS_TX_VERSION_4_5); const SchnorrProof& schnorrProof = proof.schnorrProof; GroupElement Y = A + B * (Scalar(uint64_t(1)).negate()); - if(!schnorrVerifier.verify(Y, schnorrProof)) { + // after LELANTUS_TX_VERSION_4_5 we are getting challengeGenerator with filled data from sigma, + if (!schnorrVerifier.verify(Y, A, B, schnorrProof, challengeGenerator)) { LogPrintf("Lelantus verification failed due schnorr proof verification failed."); return false; } diff --git a/src/liblelantus/lelantus_verifier.h b/src/liblelantus/lelantus_verifier.h index a00c881de4..3515715a96 100644 --- a/src/liblelantus/lelantus_verifier.h +++ b/src/liblelantus/lelantus_verifier.h @@ -6,40 +6,52 @@ #include "range_verifier.h" #include "lelantus_primitives.h" #include "coin.h" + namespace lelantus { class LelantusVerifier { public: - LelantusVerifier(const Params* p); + LelantusVerifier(const Params* p, unsigned int v); bool verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& groupIds, const Scalar& Vin, uint64_t Vout, uint64_t fee, const std::vector& Cout, - const LelantusProof& proof); + const LelantusProof& proof, + const SchnorrProof& qkSchnorrProof); bool verify( const std::map>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& groupIds, const Scalar& Vin, uint64_t Vout, uint64_t fee, const std::vector& Cout, const LelantusProof& proof, + const SchnorrProof& qkSchnorrProof, Scalar& x, bool fSkipVerification = false); private: bool verify_sigma( const std::vector>& anonymity_sets, + const std::vector>& anonymity_set_hashes, const std::vector>& Sin, + const std::vector& serialNumbers, + const std::vector>& ecdsaPubkeys, const std::vector& Cout, const std::vector &sigma_proofs, + const SchnorrProof& qkSchnorrProof, Scalar& x, + unique_ptr& challengeGenerator, Scalar& zV, Scalar& zR, bool fSkipVerification = false); @@ -54,10 +66,12 @@ class LelantusVerifier { const Scalar& Vout, const Scalar fee, const std::vector& Cout, - const LelantusProof& proof); + const LelantusProof& proof, + unique_ptr& challengeGenerator); private: const Params* params; + unsigned int version; }; }// namespace lelantus diff --git a/src/liblelantus/params.cpp b/src/liblelantus/params.cpp index ebbbfcb182..79bf2ba3b2 100644 --- a/src/liblelantus/params.cpp +++ b/src/liblelantus/params.cpp @@ -17,7 +17,7 @@ Params const* Params::get_default() { //fixing generator G; GroupElement g; - if(!(::Params().GetConsensus().IsTestnet())) { + if (!(::Params().GetConsensus().IsTestnet())) { unsigned char buff[32] = {0}; GroupElement base; base.set_base_g(); @@ -83,46 +83,50 @@ Params::Params(const GroupElement& g_, int n_sigma_, int m_sigma_, int n_rangePr h1_limit_range = get_h1() * limit_range; } -const GroupElement& Params::get_g() const{ +const GroupElement& Params::get_g() const { return g; } -const GroupElement& Params::get_h0() const{ +const GroupElement& Params::get_h0() const { return h_sigma[0]; } -const GroupElement& Params::get_h1() const{ +const GroupElement& Params::get_h1() const { return h_sigma[1]; } -const std::vector& Params::get_sigma_h() const{ +const std::vector& Params::get_sigma_h() const { return h_sigma; } -const std::vector& Params::get_bulletproofs_g() const{ +const std::vector& Params::get_bulletproofs_g() const { return g_rangeProof; } -const std::vector& Params::get_bulletproofs_h() const{ +const std::vector& Params::get_bulletproofs_h() const { return h_rangeProof; } -int Params::get_sigma_n() const{ +int Params::get_sigma_n() const { return n_sigma; } -int Params::get_sigma_m() const{ +int Params::get_sigma_m() const { return m_sigma; } -int Params::get_bulletproofs_n() const{ +int Params::get_bulletproofs_n() const { return n_rangeProof; } -const Scalar& Params::get_limit_range() const{ +int Params::get_bulletproofs_max_m() const { + return max_m_rangeProof; +} + +const Scalar& Params::get_limit_range() const { return limit_range; } -const GroupElement& Params::get_h1_limit_range() const{ +const GroupElement& Params::get_h1_limit_range() const { return h1_limit_range; } diff --git a/src/liblelantus/params.h b/src/liblelantus/params.h index b4d936a6ba..a1760f5e58 100644 --- a/src/liblelantus/params.h +++ b/src/liblelantus/params.h @@ -22,6 +22,7 @@ class Params { int get_sigma_n() const; int get_sigma_m() const; int get_bulletproofs_n() const; + int get_bulletproofs_max_m() const; const Scalar& get_limit_range() const; const GroupElement& get_h1_limit_range() const; diff --git a/src/liblelantus/range_prover.cpp b/src/liblelantus/range_prover.cpp index 25cdc730fe..4a4a4042e0 100644 --- a/src/liblelantus/range_prover.cpp +++ b/src/liblelantus/range_prover.cpp @@ -1,5 +1,5 @@ #include "range_prover.h" -#include "challenge_generator.h" +#include "challenge_generator_impl.h" namespace lelantus { @@ -9,19 +9,22 @@ RangeProver::RangeProver( const GroupElement& h2, const std::vector& g_vector, const std::vector& h_vector, - uint64_t n) + uint64_t n, + unsigned int v) : g (g) , h1 (h1) , h2 (h2) , g_(g_vector) , h_(h_vector) , n (n) + , version (v) {} void RangeProver::batch_proof( const std::vector& v, const std::vector& serialNumbers, const std::vector& randomness, + const std::vector& commitments, RangeProof& proof_out) { std::size_t m = v.size(); std::vector> bits; @@ -59,10 +62,21 @@ void RangeProver::batch_proof( LelantusPrimitives::commit(h1, ro, g_, sL, h_, sR, proof_out.S); Scalar y, z; - ChallengeGenerator challengeGenerator; - challengeGenerator.add({proof_out.A, proof_out.S}); - challengeGenerator.get_challenge(y); - challengeGenerator.get_challenge(z); + unique_ptr challengeGenerator; + if (version >= LELANTUS_TX_VERSION_4_5) { + challengeGenerator = std::make_unique>(1); + // add domain separator and transaction version into transcript + std::string domain_separator = "RANGE_PROOF" + std::to_string(version); + std::vector pre(domain_separator.begin(), domain_separator.end()); + challengeGenerator->add(pre); + challengeGenerator->add(commitments); + } else { + challengeGenerator = std::make_unique>(0); + } + + challengeGenerator->add({proof_out.A, proof_out.S}); + challengeGenerator->get_challenge(y); + challengeGenerator->get_challenge(z); //compute l(x) and r(x) polynomials std::vector> l_x, r_x; @@ -119,8 +133,8 @@ void RangeProver::batch_proof( proof_out.T2 = LelantusPrimitives::double_commit(g, t2, h1, T_12, h2, T_22); Scalar x; - challengeGenerator.add({proof_out.T1, proof_out.T2}); - challengeGenerator.get_challenge(x); + challengeGenerator->add({proof_out.T1, proof_out.T2}); + challengeGenerator->get_challenge(x); //computing l and r std::vector l; @@ -147,14 +161,22 @@ void RangeProver::batch_proof( y_i_inv.go_next(); } - InnerProductProofGenerator InnerProductProofGenerator(g_, h_prime, g); + int inner_product_version = version >= LELANTUS_TX_VERSION_4_5 ? 2 : 1; + InnerProductProofGenerator InnerProductProofGenerator(g_, h_prime, g, inner_product_version); //t^ is calculated inside inner product proof generation with name c Scalar x_u; - challengeGenerator.add({proof_out.T_x1, proof_out.T_x2, proof_out.u}); - challengeGenerator.get_challenge(x_u); - - InnerProductProofGenerator.generate_proof(l, r, x_u, proof_out.innerProductProof); + challengeGenerator->add({proof_out.T_x1, proof_out.T_x2, proof_out.u}); + challengeGenerator->get_challenge(x_u); + + if (version >= LELANTUS_TX_VERSION_4_5) { + // add domain separator in each step + std::string domain_separator = "INNER_PRODUCT"; + std::vector pre(domain_separator.begin(), domain_separator.end()); + challengeGenerator->add(pre); + } + // if(inner_product_version >= 2) link range proof data to inner product transcript with passing already filled challengeGenerator + InnerProductProofGenerator.generate_proof(l, r, x_u, challengeGenerator, proof_out.innerProductProof); } }//namespace lelantus \ No newline at end of file diff --git a/src/liblelantus/range_prover.h b/src/liblelantus/range_prover.h index f11d613323..47f0c9b6ac 100644 --- a/src/liblelantus/range_prover.h +++ b/src/liblelantus/range_prover.h @@ -13,12 +13,15 @@ class RangeProver { , const GroupElement& h2 , const std::vector& g_vector , const std::vector& h_vector - , uint64_t n); + , uint64_t n + , unsigned int v); + // commitments are included into transcript if version >= LELANTUS_TX_VERSION_4_5 void batch_proof( const std::vector& v , const std::vector& serialNumbers , const std::vector& randomness + , const std::vector& commitments , RangeProof& proof_out); private: @@ -28,6 +31,7 @@ class RangeProver { std::vector g_; std::vector h_; uint64_t n; + unsigned int version; }; diff --git a/src/liblelantus/range_verifier.cpp b/src/liblelantus/range_verifier.cpp index 0f3fbe9076..302a10fca6 100644 --- a/src/liblelantus/range_verifier.cpp +++ b/src/liblelantus/range_verifier.cpp @@ -1,5 +1,5 @@ #include "range_verifier.h" -#include "challenge_generator.h" +#include "challenge_generator_impl.h" namespace lelantus { @@ -9,44 +9,71 @@ RangeVerifier::RangeVerifier( const GroupElement& h2, const std::vector& g_vector, const std::vector& h_vector, - uint64_t n) + uint64_t n, + unsigned int v) : g (g) , h1 (h1) , h2 (h2) , g_(g_vector) , h_(h_vector) , n (n) + , version (v) {} -bool RangeVerifier::verify_batch(const std::vector& V, const RangeProof& proof) { +bool RangeVerifier::verify_batch(const std::vector& V, const std::vector& commitments, const RangeProof& proof) { if(!membership_checks(proof)) return false; uint64_t m = V.size(); //computing challenges Scalar x, x_u, y, z; + unique_ptr challengeGenerator; + if (version >= LELANTUS_TX_VERSION_4_5) { + challengeGenerator = std::make_unique>(1); + // add domain separator and transaction version into transcript + std::string domain_separator = "RANGE_PROOF" + std::to_string(version); + std::vector pre(domain_separator.begin(), domain_separator.end()); + challengeGenerator->add(pre); + challengeGenerator->add(commitments); + } else { + challengeGenerator = std::make_unique>(0); + } + challengeGenerator->add({proof.A, proof.S}); + challengeGenerator->get_challenge(y); + challengeGenerator->get_challenge(z); - ChallengeGenerator challengeGenerator; - challengeGenerator.add({proof.A, proof.S}); - challengeGenerator.get_challenge(y); - challengeGenerator.get_challenge(z); - - challengeGenerator.add({proof.T1, proof.T2}); - challengeGenerator.get_challenge(x); + challengeGenerator->add({proof.T1, proof.T2}); + challengeGenerator->get_challenge(x); Scalar x_neg = x.negate(); - challengeGenerator.add({proof.T_x1, proof.T_x2, proof.u}); - challengeGenerator.get_challenge(x_u); + challengeGenerator->add({proof.T_x1, proof.T_x2, proof.u}); + challengeGenerator->get_challenge(x_u); auto log_n = RangeProof::int_log2(n * m); const InnerProductProof& innerProductProof = proof.innerProductProof; std::vector x_j, x_j_inv; x_j.resize(log_n); x_j_inv.reserve(log_n); + + if (version >= LELANTUS_TX_VERSION_4_5) { + // add domain separator in each step + std::string domain_separator = "INNER_PRODUCT"; + std::vector pre(domain_separator.begin(), domain_separator.end()); + challengeGenerator->add(pre); + } + for (int i = 0; i < log_n; ++i) { std::vector group_elements_i = {innerProductProof.L_[i], innerProductProof.R_[i]}; - LelantusPrimitives::generate_challenge(group_elements_i, x_j[i]); + + // if(version >= LELANTUS_TX_VERSION_4_5) we should be using CHash256, + // we want to link transcripts from range proof and from previous iteration in each step, so we are not restarting in that case, + if (version < LELANTUS_TX_VERSION_4_5) { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + + challengeGenerator->add(group_elements_i); + challengeGenerator->get_challenge(x_j[i]); x_j_inv.emplace_back((x_j[i].inverse())); } diff --git a/src/liblelantus/range_verifier.h b/src/liblelantus/range_verifier.h index 3a094e82dc..96fb79e6ff 100644 --- a/src/liblelantus/range_verifier.h +++ b/src/liblelantus/range_verifier.h @@ -14,9 +14,11 @@ class RangeVerifier { , const GroupElement& h2 , const std::vector& g_vector , const std::vector& h_vector - , uint64_t n); + , uint64_t n + , unsigned int v); - bool verify_batch(const std::vector& V, const RangeProof& proof); + // commitments are included into transcript if version >= LELANTUS_TX_VERSION_4_5 + bool verify_batch(const std::vector& V, const std::vector& commitments, const RangeProof& proof); private: bool membership_checks(const RangeProof& proof); @@ -28,6 +30,7 @@ class RangeVerifier { const std::vector& g_; const std::vector& h_; uint64_t n; + unsigned int version; }; }//namespace lelantus diff --git a/src/liblelantus/schnorr_prover.cpp b/src/liblelantus/schnorr_prover.cpp index 2b402870fd..bcc12ecb99 100644 --- a/src/liblelantus/schnorr_prover.cpp +++ b/src/liblelantus/schnorr_prover.cpp @@ -1,14 +1,20 @@ #include "schnorr_prover.h" +#include "challenge_generator_impl.h" +#include "challenge_generator_impl.h" namespace lelantus { -SchnorrProver::SchnorrProver(const GroupElement& g, const GroupElement& h): - g_(g), h_(h) { +SchnorrProver::SchnorrProver(const GroupElement& g, const GroupElement& h, bool withFixes_): + g_(g), h_(h), withFixes(withFixes_) { } void SchnorrProver::proof( const Scalar& P, const Scalar& T, + const GroupElement& y, + const GroupElement& a, + const GroupElement& b, + unique_ptr& challengeGenerator, SchnorrProof& proof_out){ Scalar P0; Scalar T0; @@ -18,7 +24,44 @@ void SchnorrProver::proof( proof_out.u = u; Scalar c; std::vector group_elements = {u}; - LelantusPrimitives::generate_challenge(group_elements, c); + + std::string shts = ""; + if (withFixes) { + shts = "SCHNORR_PROOF"; + std::vector pre(shts.begin(), shts.end()); + group_elements = {u, y, a, b}; + challengeGenerator->add(pre); + } else { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(c); + proof_out.P1 = P0 - c * P; + proof_out.T1 = T0 - c * T; +} + +void SchnorrProver::proof( + const Scalar& P, + const Scalar& T, + const std::vector& group_elements, + SchnorrProof& proof_out){ + Scalar P0; + Scalar T0; + P0.randomize(); + T0.randomize(); + GroupElement u = LelantusPrimitives::commit(g_,P0, h_, T0); + proof_out.u = u; + Scalar c; + + ChallengeGeneratorImpl challengeGenerator(1); + std::string shts = "SCHNORR_PROOF"; + std::vector pre(shts.begin(), shts.end()); + challengeGenerator.add(pre); + challengeGenerator.add(group_elements); + challengeGenerator.add(u); + + challengeGenerator.get_challenge(c); + proof_out.P1 = P0 - c * P; proof_out.T1 = T0 - c * T; } diff --git a/src/liblelantus/schnorr_prover.h b/src/liblelantus/schnorr_prover.h index 227d8974b3..323ad4cc29 100644 --- a/src/liblelantus/schnorr_prover.h +++ b/src/liblelantus/schnorr_prover.h @@ -8,13 +8,16 @@ namespace lelantus { class SchnorrProver { public: //g and h are being kept by reference, be sure it will not be modified from outside - SchnorrProver(const GroupElement& g, const GroupElement& h); + SchnorrProver(const GroupElement& g, const GroupElement& h, bool withFixes_); - void proof(const Scalar& P, const Scalar& T, SchnorrProof& proof_out); + // values a, b and y are included into transcript if(withFixes_), also better to use CHash256 in that case + void proof(const Scalar& P, const Scalar& T, const GroupElement& y, const GroupElement& a, const GroupElement& b, unique_ptr& challengeGenerator, SchnorrProof& proof_out); + void proof(const Scalar& P, const Scalar& T, const std::vector& groupElements, SchnorrProof& proof_out); private: const GroupElement& g_; const GroupElement& h_; + bool withFixes; }; }//namespace lelantus diff --git a/src/liblelantus/schnorr_verifier.cpp b/src/liblelantus/schnorr_verifier.cpp index ee1c2723b2..08f14cb0a5 100644 --- a/src/liblelantus/schnorr_verifier.cpp +++ b/src/liblelantus/schnorr_verifier.cpp @@ -1,28 +1,76 @@ #include "schnorr_verifier.h" +#include "challenge_generator_impl.h" namespace lelantus { -SchnorrVerifier::SchnorrVerifier(const GroupElement& g, const GroupElement& h): - g_(g), h_(h) { +SchnorrVerifier::SchnorrVerifier(const GroupElement& g, const GroupElement& h, bool withFixes_): + g_(g), h_(h), withFixes(withFixes_) { } bool SchnorrVerifier::verify( const GroupElement& y, - const SchnorrProof& proof){ + const GroupElement& a, + const GroupElement& b, + const SchnorrProof& proof, + unique_ptr& challengeGenerator){ const GroupElement& u = proof.u; Scalar c; std::vector group_elements = {u}; - LelantusPrimitives::generate_challenge(group_elements, c); + + std::string shts = ""; + if (withFixes) { + shts = "SCHNORR_PROOF"; + std::vector pre(shts.begin(), shts.end()); + group_elements = {u, y, a, b}; + challengeGenerator->add(pre); + } else { + challengeGenerator.reset(new ChallengeGeneratorImpl(0)); + } + challengeGenerator->add(group_elements); + challengeGenerator->get_challenge(c); + + const Scalar P1 = proof.P1; + const Scalar T1 = proof.T1; + + if (!(u.isMember() && y.isMember() && P1.isMember() && T1.isMember()) || + u.isInfinity() || y.isInfinity() || P1.isZero() || T1.isZero()) + return false; + + GroupElement right = y * c + g_ * P1 + h_ * T1; + if (u == right) { + return true; + } + + return false; +} + +bool SchnorrVerifier::verify( + const GroupElement& y, + const std::vector& groupElements, + const SchnorrProof& proof){ + + const GroupElement& u = proof.u; + Scalar c; + + ChallengeGeneratorImpl challengeGenerator(1); + std::string shts = "SCHNORR_PROOF"; + std::vector pre(shts.begin(), shts.end()); + challengeGenerator.add(pre); + challengeGenerator.add(groupElements); + challengeGenerator.add(u); + + challengeGenerator.get_challenge(c); + const Scalar P1 = proof.P1; const Scalar T1 = proof.T1; - if(!(u.isMember() && y.isMember() && P1.isMember() && T1.isMember()) || + if (!(u.isMember() && y.isMember() && P1.isMember() && T1.isMember()) || u.isInfinity() || y.isInfinity() || P1.isZero() || T1.isZero()) return false; GroupElement right = y * c + g_ * P1 + h_ * T1; - if(u == right) { + if (u == right) { return true; } diff --git a/src/liblelantus/schnorr_verifier.h b/src/liblelantus/schnorr_verifier.h index d333487f1e..228c7f9fa3 100644 --- a/src/liblelantus/schnorr_verifier.h +++ b/src/liblelantus/schnorr_verifier.h @@ -8,13 +8,16 @@ namespace lelantus { class SchnorrVerifier { public: //g and h are being kept by reference, be sure it will not be modified from outside - SchnorrVerifier(const GroupElement& g, const GroupElement& h); + SchnorrVerifier(const GroupElement& g, const GroupElement& h, bool withFixes_); - bool verify(const GroupElement& y, const SchnorrProof& proof); + // values a, b and y are included into transcript if(withFixes_), also better to use CHash256 in that case + bool verify(const GroupElement& y, const GroupElement& a, const GroupElement& b,const SchnorrProof& proof, unique_ptr& challengeGenerator); + bool verify(const GroupElement& y, const std::vector& groupElements,const SchnorrProof& proof); private: const GroupElement& g_; const GroupElement& h_; + bool withFixes; }; }//namespace lelantus diff --git a/src/liblelantus/sigmaextended_prover.cpp b/src/liblelantus/sigmaextended_prover.cpp index a453556c74..9b5b9e32aa 100644 --- a/src/liblelantus/sigmaextended_prover.cpp +++ b/src/liblelantus/sigmaextended_prover.cpp @@ -13,33 +13,6 @@ SigmaExtendedProver::SigmaExtendedProver( , m_(m) { } -void SigmaExtendedProver::proof( - const std::vector& commits, - int l, - const Scalar& v, - const Scalar& r, - SigmaExtendedProof& proof_out) { - Scalar rA, rB, rC, rD; - rA.randomize(); - rB.randomize(); - rC.randomize(); - rD.randomize(); - std::vector sigma; - std::vector Tk, Pk, Yk; - Tk.resize(m_); - Pk.resize(m_); - Yk.resize(m_); - std::vector a; - a.resize(n_ * m_); - sigma_commit(commits, l, rA, rB, rC, rD, a, Tk, Pk, Yk, sigma, proof_out); - Scalar x; - std::vector group_elements = {proof_out.A_, proof_out.B_, proof_out.C_, proof_out.D_}; - group_elements.insert(group_elements.end(), proof_out.Gk_.begin(), proof_out.Gk_.end()); - group_elements.insert(group_elements.end(), proof_out.Qk.begin(), proof_out.Qk.end()); - LelantusPrimitives::generate_challenge(group_elements, x); - sigma_response(sigma, a, rA, rB, rC, rD, v, r, Tk, Pk, x, proof_out); -} - void SigmaExtendedProver::sigma_commit( const std::vector& commits, int l, diff --git a/src/liblelantus/sigmaextended_prover.h b/src/liblelantus/sigmaextended_prover.h index f832e1f874..e923d7778c 100644 --- a/src/liblelantus/sigmaextended_prover.h +++ b/src/liblelantus/sigmaextended_prover.h @@ -10,11 +10,7 @@ class SigmaExtendedProver{ public: SigmaExtendedProver(const GroupElement& g, const std::vector& h_gens, uint64_t n, uint64_t m); - void proof(const std::vector& commits, - int l, - const Scalar& v, - const Scalar& r, - SigmaExtendedProof& proof_out); + void sigma_commit( const std::vector& commits, int l, diff --git a/src/liblelantus/sigmaextended_verifier.cpp b/src/liblelantus/sigmaextended_verifier.cpp index 623c7ddad8..6f2d04715e 100644 --- a/src/liblelantus/sigmaextended_verifier.cpp +++ b/src/liblelantus/sigmaextended_verifier.cpp @@ -14,99 +14,6 @@ SigmaExtendedVerifier::SigmaExtendedVerifier( , m(m){ } -bool SigmaExtendedVerifier::verify( - const std::vector& commits, - const SigmaExtendedProof& proof) const { - Scalar x; - std::vector group_elements = {proof.A_, proof.B_, proof.C_, proof.D_}; - group_elements.insert(group_elements.end(), proof.Gk_.begin(), proof.Gk_.end()); - group_elements.insert(group_elements.end(), proof.Qk.begin(), proof.Qk.end()); - LelantusPrimitives::generate_challenge(group_elements, x); - return verify(commits, x, proof); -} - -bool SigmaExtendedVerifier::verify( - const std::vector& commits, - const Scalar& x, - const SigmaExtendedProof& proof) const { - if (commits.empty()) { - LogPrintf("Sigma verification failed due to commits are empty."); - return false; - } - - if(!membership_checks(proof)) { - LogPrintf("Sigma verification failed due to membership checks failed."); - return false; - } - - std::vector f_; - - if(!compute_fs(proof, x, f_) || !abcd_checks(proof, x, f_)) { - LogPrintf("Sigma verification failed due to f computations or abcd checks failed."); - return false; - } - - int N = commits.size(); - std::vector f_i_; - f_i_.resize(N); - - compute_fis(m, f_, f_i_); - - /* - * 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] - */ - - Scalar pow(uint64_t(1)); - std::vector I = LelantusPrimitives::convert_to_nal(N - 1, n, m); - vector f_part_product; // partial product of f array elements for lastIndex - for (int64_t j = m - 1; j >= 0; j--) { - f_part_product.push_back(pow); - pow *= f_[j * n + I[j]]; - } - - NthPower xj(x); - for (uint64_t j = 0; j < m; j++) { - Scalar fi_sum(uint64_t(0)); - for (uint64_t i = I[j] + 1; i < n; i++) - fi_sum += f_[j*n + i]; - pow += fi_sum * xj.pow * f_part_product[m - j - 1]; - xj.go_next(); - } - f_i_[N - 1] = pow; - - secp_primitives::MultiExponent mult(commits, f_i_); - GroupElement t1 = mult.get_multiple(); - - const std::vector & Gk = proof.Gk_; - const std::vector & Qk = proof.Qk; - GroupElement t2; - NthPower x_k(x); - for (std::size_t k = 0; k < m; ++k) - { - t2 += ((Gk[k] + Qk[k] )* (x_k.pow.negate())); - x_k.go_next(); - } - - GroupElement left(t1 + t2); - if(left != LelantusPrimitives::double_commit(g_, Scalar(uint64_t(0)), h_[1], proof.zV_, h_[0], proof.zR_)) { - LogPrintf("Sigma verification failed due to last check failed."); - return false; - } - - return true; -} - bool SigmaExtendedVerifier::batchverify( const std::vector& commits, const Scalar& x, @@ -347,13 +254,13 @@ bool SigmaExtendedVerifier::batchverify( GroupElement left(t1 + t2); right += g_ * exp; - if(left != right) + if (left != right) return false; return true; } bool SigmaExtendedVerifier::membership_checks(const SigmaExtendedProof& proof) const { - if(!(proof.A_.isMember() && + if (!(proof.A_.isMember() && proof.B_.isMember() && proof.C_.isMember() && proof.D_.isMember()) || @@ -423,12 +330,12 @@ bool SigmaExtendedVerifier::abcd_checks( // Aggregating two checks into one, B^x * A = Comm(..) and C^x * D = Comm(..) std::vector f_plus_f_prime; f_plus_f_prime.reserve(f_.size()); - for(std::size_t i = 0; i < f_.size(); i++) + for (std::size_t i = 0; i < f_.size(); i++) f_plus_f_prime.emplace_back(f_[i] * c + f_[i] * (x - f_[i])); GroupElement right; LelantusPrimitives::commit(g_, h_, f_plus_f_prime, proof.ZA_ * c + proof.ZC_, right); - if(((proof.B_ * x + proof.A_) * c + proof.C_ * x + proof.D_) != right) + if (((proof.B_ * x + proof.A_) * c + proof.C_ * x + proof.D_) != right) return false; return true; } @@ -448,7 +355,7 @@ void SigmaExtendedVerifier::compute_fis( j--; if (j == -1) { - if(ptr < end_ptr) + if (ptr < end_ptr) *ptr++ += f_i; return; } diff --git a/src/liblelantus/sigmaextended_verifier.h b/src/liblelantus/sigmaextended_verifier.h index 27c2ed1c6c..25494b8f49 100644 --- a/src/liblelantus/sigmaextended_verifier.h +++ b/src/liblelantus/sigmaextended_verifier.h @@ -11,13 +11,7 @@ class SigmaExtendedVerifier{ SigmaExtendedVerifier(const GroupElement& g, const std::vector& h_gens, uint64_t n, uint64_t m_); - //gets commitments divided into g^s - bool verify(const std::vector& commits, - const Scalar& x, - const SigmaExtendedProof& proof) const; - //gets commitments divided into g^s - bool verify(const std::vector& commits, - const SigmaExtendedProof& proof) const; + //gets initial double-blinded Pedersen commitments, //verifies proofs from single transaction, where set size and challenge are the same bool batchverify(const std::vector& commits, diff --git a/src/liblelantus/test/challenge_generator_tests.cpp b/src/liblelantus/test/challenge_generator_tests.cpp index 1e860cb9c8..21e7fa5b5d 100644 --- a/src/liblelantus/test/challenge_generator_tests.cpp +++ b/src/liblelantus/test/challenge_generator_tests.cpp @@ -1,6 +1,6 @@ #include "lelantus_test_fixture.h" -#include "../challenge_generator.h" +#include "../challenge_generator_impl.h" #include #include @@ -11,7 +11,7 @@ namespace lelantus { class ChallengeGeneratorTests : public LelantusTestingSetup { public: - ChallengeGenerator generator; + ChallengeGeneratorImpl generator; }; BOOST_FIXTURE_TEST_SUITE(lelantus_challenge_generator_tests, ChallengeGeneratorTests) diff --git a/src/liblelantus/test/coin_tests.cpp b/src/liblelantus/test/coin_tests.cpp index 04806e500b..01c0779f56 100644 --- a/src/liblelantus/test/coin_tests.cpp +++ b/src/liblelantus/test/coin_tests.cpp @@ -1,5 +1,6 @@ #include "../coin.h" #include "../params.h" +#include "../lelantus_primitives.h" #include "streams.h" diff --git a/src/liblelantus/test/inner_product_test.cpp b/src/liblelantus/test/inner_product_test.cpp index b5a6ec4d8c..f36491a524 100755 --- a/src/liblelantus/test/inner_product_test.cpp +++ b/src/liblelantus/test/inner_product_test.cpp @@ -1,5 +1,6 @@ #include "../innerproduct_proof_generator.h" #include "../innerproduct_proof_verifier.h" +#include "../challenge_generator_impl.h" #include "./lelantus_test_fixture.h" @@ -56,11 +57,12 @@ BOOST_AUTO_TEST_CASE(prove_verify_one) Scalar x; x.randomize(); + unique_ptr challengeGenerator = std::make_unique>(1); // generating proofs Proof proof; - ProofGenerator prover(gens_g, gens_h, u); - prover.generate_proof(a, b, x, proof); + ProofGenerator prover(gens_g, gens_h, u, 2); + prover.generate_proof(a, b, x, challengeGenerator, proof); BOOST_CHECK_EQUAL(ComputePInit(), prover.get_P()); @@ -72,8 +74,10 @@ BOOST_AUTO_TEST_CASE(prove_verify_one) BOOST_CHECK_EQUAL(log2_n, proof.R_.size()); // verify - BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify(x, proof)); - BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify_fast(n, x, proof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify(x, proof, challengeGenerator)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify_fast(n, x, proof, challengeGenerator)); } BOOST_AUTO_TEST_CASE(prove_verify) @@ -85,11 +89,12 @@ BOOST_AUTO_TEST_CASE(prove_verify) Scalar x; x.randomize(); + unique_ptr challengeGenerator = std::make_unique>(1); // generating proofs Proof proof; - ProofGenerator prover(gens_g, gens_h, u); - prover.generate_proof(a, b, x, proof); + ProofGenerator prover(gens_g, gens_h, u, 2); + prover.generate_proof(a, b, x, challengeGenerator, proof); BOOST_CHECK_EQUAL(ComputePInit(), prover.get_P()); @@ -99,8 +104,10 @@ BOOST_AUTO_TEST_CASE(prove_verify) BOOST_CHECK_EQUAL(log2_n, proof.R_.size()); // verify - BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify(x, proof)); - BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify_fast(n, x, proof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify(x, proof, challengeGenerator)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify_fast(n, x, proof, challengeGenerator)); } BOOST_AUTO_TEST_CASE(fake_proof_not_verify) @@ -112,22 +119,27 @@ BOOST_AUTO_TEST_CASE(fake_proof_not_verify) Scalar x; x.randomize(); + unique_ptr challengeGenerator = std::make_unique>(1); // generating genertor Proof proof; - ProofGenerator(gens_g, gens_h, u).generate_proof(a, b, x, proof); + ProofGenerator(gens_g, gens_h, u, 2).generate_proof(a, b, x, challengeGenerator, proof); // verify with fake P GroupElement fakeP; fakeP.randomize(); - BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, fakeP).verify(x, proof)); - BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, fakeP).verify_fast(n, x, proof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, fakeP, 2).verify(x, proof, challengeGenerator)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, fakeP, 2).verify_fast(n, x, proof, challengeGenerator)); // verify with fake proof auto verify = [&](Scalar const &_x, Proof const &_p) -> void { - BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify(_x, _p)); - BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, ComputePInit()).verify_fast(n, _x, _p)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify(_x, _p, challengeGenerator)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!ProofVerifier(gens_g, gens_h, u, ComputePInit(), 2).verify_fast(n, _x, _p, challengeGenerator)); }; auto fakeProof = proof; diff --git a/src/liblelantus/test/joinsplit_tests.cpp b/src/liblelantus/test/joinsplit_tests.cpp index 040a05e04c..66be528d83 100644 --- a/src/liblelantus/test/joinsplit_tests.cpp +++ b/src/liblelantus/test/joinsplit_tests.cpp @@ -89,15 +89,17 @@ BOOST_AUTO_TEST_CASE(verify) params, cin, anons, + {}, vout, // vout {privs[3]}, // cout CENT, // fee groupBlockHashes, - ArithToUint256(3)); + ArithToUint256(3), + 0); std::vector expectedGroupIds = {1, 1, 2}; BOOST_CHECK(expectedGroupIds == joinSplit.getCoinGroupIds()); - BOOST_CHECK(joinSplit.Verify(anons, {privs[3].getPublicCoin()}, vout, ArithToUint256(3))); + BOOST_CHECK(joinSplit.Verify(anons, {}, {privs[3].getPublicCoin()}, vout, ArithToUint256(3))); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/liblelantus/test/lelantus_primitives_tests.cpp b/src/liblelantus/test/lelantus_primitives_tests.cpp index 9c9c911ad5..26aaa86e09 100644 --- a/src/liblelantus/test/lelantus_primitives_tests.cpp +++ b/src/liblelantus/test/lelantus_primitives_tests.cpp @@ -1,7 +1,7 @@ #include "lelantus_test_fixture.h" #include "../lelantus_primitives.h" - +#include "../challenge_generator_impl.h" #include "../../test/test_bitcoin.h" #include "../../utilstrencodings.h" @@ -20,8 +20,8 @@ BOOST_AUTO_TEST_CASE(generate_challenge) auto gs1 = GenerateGroupElements(5); secp_primitives::Scalar s0, s1; - Primitives::generate_challenge(gs0, s0); - Primitives::generate_challenge(gs1, s1); + Primitives::generate_challenge(gs0, "", s0); + Primitives::generate_challenge(gs1, "", s1); BOOST_CHECK_EQUAL( "7486c200ca76a53a40715a64982705276181c4c8fe6335425607ddc696ca739f", @@ -149,7 +149,8 @@ BOOST_AUTO_TEST_CASE(generate_lelantus_challenge) } Scalar out; - Primitives::generate_Lelantus_challenge(proofs, {}, out); + unique_ptr challengeGenerator = std::make_unique>(); + Primitives::generate_Lelantus_challenge(proofs, {}, {}, {}, {}, 0, challengeGenerator, out); BOOST_CHECK_EQUAL( "0739d8484b29d53410510c38ffd5b6a43187fa0775175f97d12c61e81147245b", diff --git a/src/liblelantus/test/lelantus_test.cpp b/src/liblelantus/test/lelantus_test.cpp index 886dcfdef3..51c4503588 100644 --- a/src/liblelantus/test/lelantus_test.cpp +++ b/src/liblelantus/test/lelantus_test.cpp @@ -79,16 +79,17 @@ BOOST_AUTO_TEST_CASE(prove_verify) uint64_t f(1); LelantusProof proof; + SchnorrProof qkSchnorrProof; - LelantusProver prover(params); - prover.proof(anonymity_sets, Vin, Cin, indexes, Vout, Cout, f, proof); + LelantusProver prover(params, LELANTUS_TX_VERSION_4_5); + prover.proof(anonymity_sets, {}, Vin, Cin, indexes, {}, Vout, Cout, f, proof, qkSchnorrProof); std::vector groupIds; auto Sin = ExtractSerials(anonymity_sets.size(), Cin, groupIds); auto Cout_Public = ExtractPublicCoins(Cout); - lelantus::LelantusVerifier verifier(params); - BOOST_CHECK(verifier.verify(anonymity_sets, Sin, groupIds, Vin, Vout, f, Cout_Public, proof)); + lelantus::LelantusVerifier verifier(params, LELANTUS_TX_VERSION_4_5); + BOOST_CHECK(verifier.verify(anonymity_sets, {}, Sin, {}, groupIds, Vin, Vout, f, Cout_Public, proof, qkSchnorrProof)); } BOOST_AUTO_TEST_CASE(prove_verify_many_coins) @@ -112,18 +113,20 @@ BOOST_AUTO_TEST_CASE(prove_verify_many_coins) std::vector Cout = {{params, 2}, {params, 1}}; LelantusProof proof; + SchnorrProof qkSchnorrProof; - LelantusProver prover(params); - prover.proof(anonymity_sets, Vin, Cin, indexes, Vout, Cout, f, proof); + LelantusProver prover(params, LELANTUS_TX_VERSION_4_5); + prover.proof(anonymity_sets, {}, Vin, Cin, indexes, {}, Vout, Cout, f, proof, qkSchnorrProof); std::vector groupIds; auto Sin = ExtractSerials(anonymity_sets.size(), Cin, groupIds); auto Cout_Public = ExtractPublicCoins(Cout); - lelantus::LelantusVerifier verifier(params); - BOOST_CHECK(verifier.verify(anonymity_sets, Sin, groupIds, Vin, Vout, f, Cout_Public, proof)); - BOOST_CHECK(verifier.verify(anonymity_sets, Sin, groupIds, Vin + 1, Vout + 1, f, Cout_Public, proof)); - BOOST_CHECK(verifier.verify(anonymity_sets, Sin, groupIds, Vin, Vout + f, uint64_t(0), Cout_Public, proof)); + lelantus::LelantusVerifier verifier(params, LELANTUS_TX_VERSION_4_5); + BOOST_CHECK(verifier.verify(anonymity_sets, {}, Sin, {}, groupIds, Vin, Vout, f, Cout_Public, proof, qkSchnorrProof)); + //After Lelantus new update (after version LELANTUS_TX_VERSION_4_5) following 2 verifications will fail, as schnorr proof challenge depends also on Vout, Vin and fee values +// BOOST_CHECK(verifier.verify(anonymity_sets, {}, Sin, {}, groupIds, Vin + 1, Vout + 1, f, Cout_Public, proof)); +// BOOST_CHECK(verifier.verify(anonymity_sets, {}, Sin, {}, groupIds, Vin, Vout + f, uint64_t(0), Cout_Public, proof)); } BOOST_AUTO_TEST_CASE(imbalance_proof_should_fail) @@ -149,28 +152,29 @@ BOOST_AUTO_TEST_CASE(imbalance_proof_should_fail) // Proof LelantusProof proof; + SchnorrProof qkSchnorrProof; // Should be prevent from prover - LelantusProver prover(params); - BOOST_CHECK_THROW(prover.proof(anonymitySets, Vin, Cin, indexs, Vout, Cout, f, proof), ZerocoinException); + LelantusProver prover(params, LELANTUS_TX_VERSION_4_5); + BOOST_CHECK_THROW(prover.proof(anonymitySets, {}, Vin, Cin, indexs, {}, Vout, Cout, f, proof, qkSchnorrProof), ZerocoinException); // Use fake vin - prover.proof(anonymitySets, FakeVin, Cin, indexs, Vout, Cout, f, proof); + prover.proof(anonymitySets, {}, FakeVin, Cin, indexs, {}, Vout, Cout, f, proof, qkSchnorrProof); // Verify std::vector groupIds; auto Sin = ExtractSerials(anonymitySets.size(), Cin, groupIds); auto publicCoins = ExtractPublicCoins(Cout); - LelantusVerifier verifier(params); + LelantusVerifier verifier(params, LELANTUS_TX_VERSION_4_5); // input: 2 + 3(anonymous), output: 3 + 3(anonymous) + 1(fee) - BOOST_CHECK(!verifier.verify(anonymitySets, Sin, groupIds, Vin, Vout, f, publicCoins, proof)); + BOOST_CHECK(!verifier.verify(anonymitySets, {}, Sin, {}, groupIds, Vin, Vout, f, publicCoins, proof, qkSchnorrProof)); // Verify with output which is less than input also should fail // input: 99 + 3(anonymous), output: 3 + 3(anonymous) + 1(fee) Scalar newVin(99); - BOOST_CHECK(!verifier.verify(anonymitySets, Sin, groupIds, newVin, Vout, f, publicCoins, proof)); + BOOST_CHECK(!verifier.verify(anonymitySets, {}, Sin, {}, groupIds, newVin, Vout, f, publicCoins, proof, qkSchnorrProof)); } BOOST_AUTO_TEST_CASE(other_fail_to_validate) @@ -196,33 +200,34 @@ BOOST_AUTO_TEST_CASE(other_fail_to_validate) // Proof LelantusProof proof; + SchnorrProof qkSchnorrProof; // Should be prevent from prover - LelantusProver prover(params); - prover.proof(anonymitySets, Vin, Cin, indexs, Vout, Cout, f, proof); + LelantusProver prover(params, LELANTUS_TX_VERSION_4_5); + prover.proof(anonymitySets, {}, Vin, Cin, indexs, {}, Vout, Cout, f, proof, qkSchnorrProof); // Verify std::vector groupIds; auto Sin = ExtractSerials(anonymitySets.size(), Cin, groupIds); auto publicCoins = ExtractPublicCoins(Cout); - LelantusVerifier verifier(params); + LelantusVerifier verifier(params, LELANTUS_TX_VERSION_4_5); - BOOST_CHECK(verifier.verify(anonymitySets, Sin, groupIds, Vin, Vout, f, publicCoins, proof)); + BOOST_CHECK(verifier.verify(anonymitySets, {}, Sin, {}, groupIds, Vin, Vout, f, publicCoins, proof, qkSchnorrProof)); // Invalid group auto invalidAnonymitySets = anonymitySets; invalidAnonymitySets[0].pop_back(); - BOOST_CHECK(!verifier.verify(invalidAnonymitySets, Sin, groupIds, Vin, Vout, f, publicCoins, proof)); + BOOST_CHECK(!verifier.verify(invalidAnonymitySets, {}, Sin, {}, groupIds, Vin, Vout, f, publicCoins, proof, qkSchnorrProof)); invalidAnonymitySets = anonymitySets; invalidAnonymitySets[0].push_back(PrivateCoin(params, 1).getPublicCoin()); - BOOST_CHECK(!verifier.verify(invalidAnonymitySets, Sin, groupIds, Vin, Vout, f, publicCoins, proof)); + BOOST_CHECK(!verifier.verify(invalidAnonymitySets, {}, Sin, {}, groupIds, Vin, Vout, f, publicCoins, proof, qkSchnorrProof)); // Invalid serial auto invalidSin = Sin; invalidSin[1].randomize(); - BOOST_CHECK(!verifier.verify(anonymitySets, invalidSin, groupIds, Vin, Vout, f, publicCoins, proof)); + BOOST_CHECK(!verifier.verify(anonymitySets, {}, invalidSin, {}, groupIds, Vin, Vout, f, publicCoins, proof, qkSchnorrProof)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/liblelantus/test/range_proof_test.cpp b/src/liblelantus/test/range_proof_test.cpp index 4f3742c71f..e324e5bd6c 100644 --- a/src/liblelantus/test/range_proof_test.cpp +++ b/src/liblelantus/test/range_proof_test.cpp @@ -32,12 +32,12 @@ BOOST_AUTO_TEST_CASE(prove_verify) V.push_back(g_gen * v_s.back() + h_gen1 * randoms[i] + h_gen2 * serials[i]); } - RangeProver rangeProver(g_gen, h_gen1, h_gen2, g_, h_, n); + RangeProver rangeProver(g_gen, h_gen1, h_gen2, g_, h_, n, LELANTUS_TX_VERSION_4_5); RangeProof proof; - rangeProver.batch_proof(v_s, serials, randoms, proof); + rangeProver.batch_proof(v_s, serials, randoms, V, proof); - RangeVerifier rangeVerifier(g_gen, h_gen1, h_gen2, g_, h_, n); - BOOST_CHECK(rangeVerifier.verify_batch(V, proof)); + RangeVerifier rangeVerifier(g_gen, h_gen1, h_gen2, g_, h_, n, LELANTUS_TX_VERSION_4_5); + BOOST_CHECK(rangeVerifier.verify_batch(V, V, proof)); } BOOST_AUTO_TEST_CASE(out_of_range_notVerify) @@ -62,12 +62,12 @@ BOOST_AUTO_TEST_CASE(out_of_range_notVerify) V.push_back(g_gen * v_s[i] + h_gen1 * randoms[i] + h_gen2 * serials[i]); } - lelantus::RangeProver rangeProver(g_gen, h_gen1, h_gen2, g_, h_, n); + lelantus::RangeProver rangeProver(g_gen, h_gen1, h_gen2, g_, h_, n, LELANTUS_TX_VERSION_4_5); lelantus::RangeProof proof; - rangeProver.batch_proof(v_s, serials, randoms, proof); + rangeProver.batch_proof(v_s, serials, randoms, V, proof ); - lelantus::RangeVerifier rangeVerifier(g_gen, h_gen1, h_gen2, g_, h_, n); - BOOST_CHECK(!rangeVerifier.verify_batch(V, proof)); + lelantus::RangeVerifier rangeVerifier(g_gen, h_gen1, h_gen2, g_, h_, n, LELANTUS_TX_VERSION_4_5); + BOOST_CHECK(!rangeVerifier.verify_batch(V, V, proof)); }; // All values are out of range diff --git a/src/liblelantus/test/schnorr_test.cpp b/src/liblelantus/test/schnorr_test.cpp index fb6d64b970..471ddcae78 100644 --- a/src/liblelantus/test/schnorr_test.cpp +++ b/src/liblelantus/test/schnorr_test.cpp @@ -1,6 +1,7 @@ #include "../schnorr_proof.h" #include "../schnorr_prover.h" #include "../schnorr_verifier.h" +#include "../challenge_generator_impl.h" #include "../../streams.h" #include @@ -15,10 +16,12 @@ class SchnorrProofTests { h.randomize(); P.randomize(); T.randomize(); + a.randomize(); + b.randomize(); } public: - GroupElement g, h; + GroupElement g, h, a, b; Scalar P, T; }; @@ -26,9 +29,12 @@ BOOST_FIXTURE_TEST_SUITE(lelantus_schnorr_proof_tests, SchnorrProofTests) BOOST_AUTO_TEST_CASE(serialization) { - SchnorrProver prover(g, h); + unique_ptr challengeGenerator = std::make_unique>(1); + SchnorrProver prover(g, h, true); + GroupElement y; + y.randomize(); SchnorrProof proof; - prover.proof(P, T, proof); + prover.proof(P, T, y, a, b, challengeGenerator, proof); CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); serialized << proof; @@ -44,40 +50,47 @@ BOOST_AUTO_TEST_CASE(serialization) BOOST_AUTO_TEST_CASE(prove_verify) { auto y = LelantusPrimitives::commit(g, P, h, T); + unique_ptr challengeGenerator = std::make_unique>(1); - SchnorrProver prover(g, h); + SchnorrProver prover(g, h, true); SchnorrProof proof; - prover.proof(P, T, proof); + prover.proof(P, T, y, a, b, challengeGenerator, proof); - SchnorrVerifier verifier(g, h); - BOOST_CHECK(verifier.verify(y ,proof)); + SchnorrVerifier verifier(g, h, true); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(verifier.verify(y, a, b, proof, challengeGenerator)); } BOOST_AUTO_TEST_CASE(fake_prove_not_verify) { auto y = LelantusPrimitives::commit(g, P, h, T); + unique_ptr challengeGenerator = std::make_unique>(1); - SchnorrProver prover(g, h); + SchnorrProver prover(g, h, true); SchnorrProof proof; - prover.proof(P, T, proof); + prover.proof(P, T, y, a, b, challengeGenerator, proof); GroupElement fakeY; fakeY.randomize(); - SchnorrVerifier verifier(g, h); - BOOST_CHECK(!verifier.verify(fakeY, proof)); + SchnorrVerifier verifier(g, h, true); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!verifier.verify(fakeY, a, b, proof, challengeGenerator)); auto fakeProof = proof; fakeProof.P1.randomize(); - BOOST_CHECK(!verifier.verify(y, fakeProof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!verifier.verify(y, a, b, fakeProof, challengeGenerator)); fakeProof = proof; fakeProof.T1.randomize(); - BOOST_CHECK(!verifier.verify(y, fakeProof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!verifier.verify(y, a, b, fakeProof, challengeGenerator)); fakeProof = proof; fakeProof.u.randomize(); - BOOST_CHECK(!verifier.verify(y, fakeProof)); + challengeGenerator.reset(new ChallengeGeneratorImpl(1)); + BOOST_CHECK(!verifier.verify(y, a, b, fakeProof, challengeGenerator)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/liblelantus/test/serialize_test.cpp b/src/liblelantus/test/serialize_test.cpp index b38b65d0e3..70147ca65e 100644 --- a/src/liblelantus/test/serialize_test.cpp +++ b/src/liblelantus/test/serialize_test.cpp @@ -1,5 +1,6 @@ #include "../lelantus_prover.h" #include "../lelantus_verifier.h" + #include "streams.h" #include "lelantus_test_fixture.h" @@ -39,9 +40,10 @@ BOOST_AUTO_TEST_CASE(serialize) secp_primitives::Scalar f(uint64_t(1)); lelantus::LelantusProof initial_proof; + lelantus::SchnorrProof qkSchnorrProof; - lelantus::LelantusProver prover(params); - prover.proof(anonymity_sets, Vin, Cin, indexes, Vout, Cout, f, initial_proof); + lelantus::LelantusProver prover(params, LELANTUS_TX_VERSION_4_5); + prover.proof(anonymity_sets, {}, Vin, Cin, indexes, {}, Vout, Cout, f, initial_proof, qkSchnorrProof); CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); serialized << initial_proof; diff --git a/src/liblelantus/test/sigma_extended_test.cpp b/src/liblelantus/test/sigma_extended_test.cpp index 5b8ebdc914..25d8628444 100644 --- a/src/liblelantus/test/sigma_extended_test.cpp +++ b/src/liblelantus/test/sigma_extended_test.cpp @@ -96,83 +96,6 @@ class SigmaExtendedTests : public LelantusTestingSetup { BOOST_FIXTURE_TEST_SUITE(lelantus_sigma_tests, SigmaExtendedTests) -BOOST_AUTO_TEST_CASE(one_out_of_N) -{ - GenerateParams(16, 4); - - Prover prover(g, h_gens, n, m); - - auto commits = RandomizeGroupElements(N); - - // tests indexs - for (auto index : {0, 3, 15}) { - Scalar s, v, r; - s.randomize(); - v.randomize(); - r.randomize(); - - commits[index] = Primitives::double_commit( - g, uint64_t(0), h_gens[1], v, h_gens[0], r); - - Proof proof; - prover.proof(commits, index, v, r, proof); - - Verifier verifier(g, h_gens, n, m); - BOOST_CHECK(verifier.verify(commits, proof)); - - // clear generated commitment - commits[index].randomize(); - } -} - -BOOST_AUTO_TEST_CASE(one_out_of_N_with_other_groups) -{ - GenerateParams(16, 4); - - Prover prover(g, h_gens, n, m); - auto commits = RandomizeGroupElements(N); - - Secret s(0); - commits[0] = Primitives::double_commit(g, uint64_t(0), h_gens[1], s.v, h_gens[0], s.r); - - Proof proof; - prover.proof(commits, 0, s.v, s.r, proof); - - Verifier verifier(g, h_gens, n, m); - BOOST_CHECK(verifier.verify(commits, proof)); - - // test with invalid commits - auto test = [&](std::vector const &cs) -> void { - BOOST_CHECK(!verifier.verify(cs, proof)); - }; - - // extra member - auto anotherCommits = commits; - anotherCommits.emplace_back(); - anotherCommits.back().randomize(); - test(anotherCommits); - - // remove last member - anotherCommits = commits; - anotherCommits.pop_back(); - test(anotherCommits); - - // change itself - anotherCommits = commits; - anotherCommits[0].randomize(); - test(anotherCommits); - - // change other - anotherCommits = commits; - anotherCommits[1].randomize(); - test(anotherCommits); - - // swap some coins - anotherCommits = commits; - std::swap(anotherCommits[1], anotherCommits[2]); - test(anotherCommits); -} - BOOST_AUTO_TEST_CASE(one_out_of_N_batch) { GenerateParams(16, 4); diff --git a/src/libzerocoin/Zerocoin.h b/src/libzerocoin/Zerocoin.h index 50d0abd9f2..30b525c3fc 100644 --- a/src/libzerocoin/Zerocoin.h +++ b/src/libzerocoin/Zerocoin.h @@ -42,6 +42,8 @@ #define ZEROCOIN_TX_VERSION_3_1 31 #define LELANTUS_TX_VERSION_4 40 #define SIGMA_TO_LELANTUS_JOINSPLIT 41 +#define LELANTUS_TX_VERSION_4_5 45 +#define SIGMA_TO_LELANTUS_JOINSPLIT_FIXED 46 // Activate multithreaded mode for proof verification #define ZEROCOIN_THREADING 1 diff --git a/src/secp256k1/src/cpp/Scalar.cpp b/src/secp256k1/src/cpp/Scalar.cpp index 0fc52973c1..55eae220c2 100644 --- a/src/secp256k1/src/cpp/Scalar.cpp +++ b/src/secp256k1/src/cpp/Scalar.cpp @@ -217,7 +217,7 @@ Scalar& Scalar::randomize() { throw "Unable to generate random Scalar"; } generate(temp); - } while (!this->isMember()); + } while (!this->isMember() || this->isZero()); // we need to ensure, generated value is valid and non 0 return *this; } diff --git a/src/test/evospork_tests.cpp b/src/test/evospork_tests.cpp index 084e355e45..31e77e50de 100644 --- a/src/test/evospork_tests.cpp +++ b/src/test/evospork_tests.cpp @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(mempool) int prevHeight; pwalletMain->SetBroadcastTransactions(true); - for (int n=chainActive.Height(); n<1000; n++) + for (int n=chainActive.Height(); n<1001; n++) GenerateBlock({}); auto utxos = BuildSimpleUtxoMap(coinbaseTxns); @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(limit) int prevHeight; pwalletMain->SetBroadcastTransactions(true); - for (int n=chainActive.Height(); n<1000; n++) + for (int n=chainActive.Height(); n<1001; n++) GenerateBlock({}); auto utxos = BuildSimpleUtxoMap(coinbaseTxns); @@ -385,7 +385,7 @@ BOOST_AUTO_TEST_CASE(startstopblock) CreateAndProcessBlock({sporkTx1}, coinbaseKey); BOOST_ASSERT(chainActive.Height() == prevHeight); - for (int n=chainActive.Height(); n<1000; n++) + for (int n=chainActive.Height(); n<1001; n++) GenerateBlock({}); // now we can mine sporkTx1 diff --git a/src/test/lelantus_state_tests.cpp b/src/test/lelantus_state_tests.cpp index 287fd2e39a..a493271952 100644 --- a/src/test/lelantus_state_tests.cpp +++ b/src/test/lelantus_state_tests.cpp @@ -400,15 +400,16 @@ BOOST_AUTO_TEST_CASE(get_coin_group) addMintsToState(indexes[2], blocks[2]); verifyGroup(1, 6, indexes[0], indexes[2]); - uint256 blockHashOut1; std::vector coinOut1; + std::vector setHash; BOOST_CHECK_EQUAL(6, lelantusState->GetCoinSetForSpend( &chainActive, indexes[2]->nHeight, 1, blockHashOut1, - coinOut1)); + coinOut1, + setHash)); verifyMints(0, 6, coinOut1); BOOST_CHECK(indexes[2]->GetBlockHash() == blockHashOut1); @@ -425,7 +426,8 @@ BOOST_AUTO_TEST_CASE(get_coin_group) indexes[3]->nHeight + 1, // specify limit with no mints block 2, blockHashOut2, - coinOut2)); + coinOut2, + setHash)); verifyMints(4, 8, coinOut2); BOOST_CHECK(indexes[3]->GetBlockHash() == blockHashOut2); @@ -443,7 +445,8 @@ BOOST_AUTO_TEST_CASE(get_coin_group) indexes[4]->nHeight, 2, blockHashOut3, - coinOut3)); + coinOut3, + setHash)); verifyMints(4, 10, coinOut3); BOOST_CHECK(indexes[4]->GetBlockHash() == blockHashOut3); @@ -462,7 +465,8 @@ BOOST_AUTO_TEST_CASE(get_coin_group) indexes[5]->nHeight, 3, blockHashOut4, - coinOut4)); + coinOut4, + setHash)); verifyMints(8, 12, coinOut4); @@ -474,7 +478,8 @@ BOOST_AUTO_TEST_CASE(get_coin_group) indexes[5]->nHeight, 1, blockHashOut5, - coinOut5)); + coinOut5, + setHash)); verifyMints(0, 6, coinOut5); BOOST_CHECK(indexes[2]->GetBlockHash() == blockHashOut5); @@ -487,7 +492,8 @@ BOOST_AUTO_TEST_CASE(get_coin_group) indexes[0]->nHeight, 1, blockHashOut6, - coinOut6)); + coinOut6, + setHash)); verifyMints(0, 2, coinOut6); BOOST_CHECK(indexes[0]->GetBlockHash() == blockHashOut6); diff --git a/src/test/lelantus_tests.cpp b/src/test/lelantus_tests.cpp index 43becf8e84..e83228617b 100644 --- a/src/test/lelantus_tests.cpp +++ b/src/test/lelantus_tests.cpp @@ -7,7 +7,7 @@ #include "test_bitcoin.h" #include "fixtures.h" - +#include #include namespace lelantus { @@ -28,8 +28,7 @@ struct JoinSplitScriptGenerator { CScript script; - JoinSplit joinSplit(p, coins, anons, vout, coinsOut, fee, groupBlockHashes, txHash); - joinSplit.setVersion(LELANTUS_TX_VERSION_4); + JoinSplit joinSplit(p, coins, anons, {}, vout, coinsOut, fee, groupBlockHashes, txHash, LELANTUS_TX_VERSION_4); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << joinSplit; @@ -556,7 +555,7 @@ BOOST_AUTO_TEST_CASE(checktransaction) CValidationState state; CLelantusTxInfo info; BOOST_CHECK(CheckLelantusTransaction( - txs[0], state, tx.GetHash(), true, chainActive.Height(), true, true, NULL, &info)); + txs[0], state, tx.GetHash(), false, chainActive.Height(), true, true, NULL, &info)); std::vector>> expectedCoins = {{mints[0].GetPubcoinValue(), {1 * CENT, info.mints[0].second.second}}}; @@ -735,8 +734,8 @@ BOOST_AUTO_TEST_CASE(parse_joinsplit) BOOST_CHECK(gs.second.getVersion() == result->getVersion()); BOOST_CHECK(gs.second.HasValidSerials() == result->HasValidSerials()); - BOOST_CHECK(gs.second.Verify(g.anons, ExtractCoins(g.coinsOut), g.vout, g.txHash)); - BOOST_CHECK(result->Verify(g.anons, ExtractCoins(g.coinsOut), g.vout, g.txHash)); + BOOST_CHECK(gs.second.Verify(g.anons, {}, ExtractCoins(g.coinsOut), g.vout, g.txHash)); + BOOST_CHECK(result->Verify(g.anons, {}, ExtractCoins(g.coinsOut), g.vout, g.txHash)); } BOOST_AUTO_TEST_CASE(coingroup) diff --git a/src/txdb.cpp b/src/txdb.cpp index 3c2b4991fe..7271190fb2 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -394,6 +394,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::functionlelantusMintedPubCoins = diskindex.lelantusMintedPubCoins; pindexNew->lelantusSpentSerials = diskindex.lelantusSpentSerials; + pindexNew->anonymitySetHash = diskindex.anonymitySetHash; pindexNew->activeDisablingSporks = diskindex.activeDisablingSporks; diff --git a/src/validation.cpp b/src/validation.cpp index 0d4be5e07d..1d7aa3c78f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3172,7 +3172,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara continue; } - if (joinsplit->getVersion() == SIGMA_TO_LELANTUS_JOINSPLIT) { + if (joinsplit->isSigmaToLelantus()) { for (size_t i = 0; i < serials.size(); i++) { int coinGroupId = ids[i] % (CENT / 1000); int64_t intDenom = (ids[i] - coinGroupId); diff --git a/src/wallet/lelantusjoinsplitbuilder.cpp b/src/wallet/lelantusjoinsplitbuilder.cpp index 0baacd79dc..ef129de8b1 100644 --- a/src/wallet/lelantusjoinsplitbuilder.cpp +++ b/src/wallet/lelantusjoinsplitbuilder.cpp @@ -405,12 +405,20 @@ void LelantusJoinSplitBuilder::CreateJoinSplit( std::map groupBlockHashes; int version = 0; + // after nLelantusFixesStartBlock set new transaction version, if(!isSigmaToLelantusJoinSplit) { - version = LELANTUS_TX_VERSION_4; + if (chainActive.Height() >= Params().GetConsensus().nLelantusFixesStartBlock) + version = LELANTUS_TX_VERSION_4_5; + else + version = LELANTUS_TX_VERSION_4; } else { - version = SIGMA_TO_LELANTUS_JOINSPLIT; + if (chainActive.Height() >= Params().GetConsensus().nLelantusFixesStartBlock) + version = SIGMA_TO_LELANTUS_JOINSPLIT_FIXED; + else + version = SIGMA_TO_LELANTUS_JOINSPLIT; } + std::vector> anonymity_set_hashes; for (const auto &spend : spendCoins) { // construct public part of the mint lelantus::PublicCoin pub(spend.value); @@ -432,7 +440,7 @@ void LelantusJoinSplitBuilder::CreateJoinSplit( } coins.emplace_back(make_pair(priv, groupId)); - + std::vector setHash; if (anonymity_sets.count(groupId) == 0) { std::vector set; uint256 blockHash; @@ -441,11 +449,14 @@ void LelantusJoinSplitBuilder::CreateJoinSplit( chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1), // required 2 confirmation for mint to spend groupId, blockHash, - set) < 2) + set, + setHash) < 2) throw std::runtime_error( _("Has to have at least two mint coins with at least 2 confirmation in order to spend a coin")); groupBlockHashes[groupId] = blockHash; anonymity_sets[groupId] = set; + if (!setHash.empty()) + anonymity_set_hashes.push_back(setHash); } } @@ -504,15 +515,14 @@ void LelantusJoinSplitBuilder::CreateJoinSplit( std::sort(coins.begin(), coins.end(), CoinCompare()); - lelantus::JoinSplit joinSplit(params, coins, anonymity_sets, Vout, Cout, fee, groupBlockHashes, txHash); - joinSplit.setVersion(version); + lelantus::JoinSplit joinSplit(params, coins, anonymity_sets, anonymity_set_hashes, Vout, Cout, fee, groupBlockHashes, txHash, version); std::vector pCout; pCout.reserve(Cout.size()); for(const auto& coin : Cout) pCout.emplace_back(coin.getPublicCoin()); - if (!joinSplit.Verify(anonymity_sets, pCout, Vout, txHash)) { + if (!joinSplit.Verify(anonymity_sets, anonymity_set_hashes, pCout, Vout, txHash)) { throw std::runtime_error(_("The joinsplit transaction failed to verify")); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1e5824774c..e8032a077f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2920,12 +2920,14 @@ std::list CWallet::GetAvailableLelantusCoins(const CCoinControl // Check group size uint256 hashOut; std::vector coinOuts; + std::vector setHash; state->GetCoinSetForSpend( &chainActive, chainActive.Height() - (ZC_MINT_CONFIRMATIONS - 1), // required 2 confirmation for mint to spend coinId, hashOut, - coinOuts + coinOuts, + setHash ); if (!includeUnsafe && coinOuts.size() < 2) { diff --git a/src/zerocoin_params.h b/src/zerocoin_params.h index ff0f0cef94..c2617d1b87 100644 --- a/src/zerocoin_params.h +++ b/src/zerocoin_params.h @@ -55,7 +55,9 @@ static const int64_t DUST_HARD_LIMIT = 1000; // 0.00001 FIRO mininput // Block after which lelantus mints are activated. #define ZC_LELANTUS_STARTING_BLOCK 336888 +#define ZC_LELANTUS_FIXES_START_BLOCK 365544 //Approx April 22, 20211, 2:00 PM UTC #define ZC_LELANTUS_TESTNET_STARTING_BLOCK 15700 +#define ZC_LELANTUS_TESTNET_FIXES_START_BLOCK 27600 // Number of blocks after ZC_SIGMA_STARTING_BLOCK during which we still accept zerocoin V2 mints into mempool. #define ZC_V2_MINT_GRACEFUL_MEMPOOL_PERIOD 4500