diff --git a/src/main.cpp b/src/main.cpp index 209d5bf47b..14fe69e103 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1175,8 +1175,9 @@ private: secp256k1_surjectionproof proof; std::vector vTags; secp256k1_generator gen; + const bool store; public: - CSurjectionCheck(secp256k1_surjectionproof& proofIn, std::vector& vTags_, secp256k1_generator& genIn) : proof(proofIn), gen(genIn) { + CSurjectionCheck(secp256k1_surjectionproof& proofIn, std::vector& vTags_, secp256k1_generator& genIn, const bool storeIn) : proof(proofIn), gen(genIn), store(storeIn) { vTags.swap(vTags_); } @@ -1216,11 +1217,7 @@ bool CBalanceCheck::operator()() bool CSurjectionCheck::operator()() { - if (secp256k1_surjectionproof_verify(secp256k1_ctx_verify_amounts, &proof, vTags.data(), vTags.size(), &gen) != 1) { - return false; - } - - return true; + return CachingSurjectionProofChecker(store).VerifySurjectionProof(proof, vTags, gen, secp256k1_ctx_verify_amounts); } } // namespace @@ -1409,7 +1406,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, const C if (secp256k1_surjectionproof_parse(secp256k1_ctx_verify_amounts, &proof, &asset.vchSurjectionproof[0], asset.vchSurjectionproof.size()) != 1) return false; - if (!QueueCheck(pvChecks, new CSurjectionCheck(proof, ephemeral_input_tags, gen))) { + if (!QueueCheck(pvChecks, new CSurjectionCheck(proof, ephemeral_input_tags, gen, cacheStore))) { return false; } // Each CSurjectionCheck uses swap to keep pointers valid. diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index f617b6314f..ad564e973a 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -146,3 +146,37 @@ bool CachingRangeProofChecker::VerifyRangeProof(const std::vector return true; } + +bool CachingSurjectionProofChecker::VerifySurjectionProof(secp256k1_surjectionproof& proof, std::vector& vTags, secp256k1_generator& gen, const secp256k1_context* secp256k1_ctx_verify_amounts) const +{ + static CSignatureCache surjectionProofCache; + + std::vector vchproof; + size_t proof_len = 0; + vchproof.resize(secp256k1_surjectionproof_serialized_size(secp256k1_ctx_verify_amounts, &proof)); + secp256k1_surjectionproof_serialize(secp256k1_ctx_verify_amounts, &vchproof[0], &proof_len, &proof); + + std::vector vchGen; + vchGen.resize(CTxOutValue::nCommittedSize); + secp256k1_generator_serialize(secp256k1_ctx_verify_amounts, &vchGen[0], &gen); + + CPubKey pubkey(vchGen); + uint256 entry; + surjectionProofCache.ComputeEntry(entry, uint256(), vchproof, pubkey); + + if (surjectionProofCache.Get(entry)) { + if (!store) { + surjectionProofCache.Erase(entry); + } + return true; + } + + if (secp256k1_surjectionproof_verify(secp256k1_ctx_verify_amounts, &proof, vTags.data(), vTags.size(), &gen) != 1) { + return false; + } + + if (store) { + surjectionProofCache.Set(entry); + } + return true; +} diff --git a/src/script/sigcache.h b/src/script/sigcache.h index f5a2c933ca..1649957c13 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -10,6 +10,7 @@ #include #include +#include #include // DoS prevention: limit cache size to less than 40MB (over 500000 @@ -42,4 +43,17 @@ public: }; +class CachingSurjectionProofChecker +{ +private: + bool store; +public: + CachingSurjectionProofChecker(bool storeIn){ + store = storeIn; + }; + + bool VerifySurjectionProof(secp256k1_surjectionproof& proof, std::vector& vTags, secp256k1_generator& gen, const secp256k1_context* ctx) const; + +}; + #endif // BITCOIN_SCRIPT_SIGCACHE_H