Merge pull request #1439 from tomt1664/fix/check-missing-proofs

Add missing proof checks and tests
This commit is contained in:
Pablo Greco 2025-03-26 05:11:02 -07:00 committed by GitHub
commit 811d835960
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 1 deletions

View file

@ -68,11 +68,13 @@ bool CreateAssetSurjectionProof(std::vector<unsigned char>& output_proof, const
bool VerifyBlindAssetProof(const uint256& asset, const std::vector<unsigned char>& proof, const CConfidentialAsset& conf_asset)
{
if (conf_asset.vchCommitment.size() != CConfidentialAsset::nCommittedSize || proof.empty()) {
return false;
}
secp256k1_surjectionproof surj_proof;
if (secp256k1_surjectionproof_parse(secp256k1_blind_context, &surj_proof, proof.data(), proof.size()) == 0) {
return false;
}
secp256k1_generator blinded_asset_gen;
if (secp256k1_generator_parse(secp256k1_blind_context, &blinded_asset_gen, conf_asset.vchCommitment.data()) == 0) {
return false;

View file

@ -390,6 +390,9 @@ bool VerifyAmounts(const std::vector<CTxOut>& inputs, const CTransaction& tx, st
}
if (!ptxoutwit)
return false;
if (asset.vchCommitment.size() != CConfidentialAsset::nCommittedSize || ptxoutwit->vchSurjectionproof.empty()) {
return false;
}
if (secp256k1_generator_parse(secp256k1_ctx_verify_amounts, &gen, &asset.vchCommitment[0]) != 1)
return false;

View file

@ -106,6 +106,44 @@ class CTTest (BitcoinTestFramework):
# clean up blind_details
os.remove(file_path)
def test_no_surj(self):
self.generate(self.nodes[0], 1)
tx_hex = self.nodes[0].createrawtransaction([], [{self.nodes[1].getnewaddress(): 1000}])
tx_hex = self.nodes[0].fundrawtransaction(tx_hex)['hex']
tx_hex = self.nodes[0].blindrawtransaction(tx_hex)
# coming from initial free coins: no need to sign
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True) # tx is ok
# remove a surjection proof from the tx
tx = CTransaction()
tx.deserialize(io.BytesIO(bytes.fromhex(tx_hex)))
tx.wit.vtxoutwit[0].vchSurjectionproof = b''
tx_hex = tx.serialize().hex()
# Both of these make the node crash
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], False)
assert_raises_rpc_error(-26, "bad-txns-in-ne-out", self.nodes[0].sendrawtransaction, tx_hex)
def test_no_range(self):
self.generate(self.nodes[0], 1)
tx_hex = self.nodes[0].createrawtransaction([], [{self.nodes[1].getnewaddress(): 1000}])
tx_hex = self.nodes[0].fundrawtransaction(tx_hex)['hex']
tx_hex = self.nodes[0].blindrawtransaction(tx_hex)
# coming from initial free coins: no need to sign
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True) # tx is ok
# remove a surjection proof from the tx
tx = CTransaction()
tx.deserialize(io.BytesIO(bytes.fromhex(tx_hex)))
tx.wit.vtxoutwit[0].vchRangeproof = b''
tx_hex = tx.serialize().hex()
# Both of these make the node crash
assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], False)
assert_raises_rpc_error(-26, "bad-txns-in-ne-out", self.nodes[0].sendrawtransaction, tx_hex)
def test_null_rangeproof_enforcement(self):
self.generate(self.nodes[0], 1)
@ -160,6 +198,12 @@ class CTTest (BitcoinTestFramework):
def run_test(self):
print("Testing a transaction with a missing surjection proof")
self.test_no_surj()
print("Testing a transaction with a missing range proof")
self.test_no_range()
print("Testing that null issuances must have null rangeproofs")
self.test_null_rangeproof_enforcement()