From 3a1c39625e7f9c05234df71c35bee3dae5b785e6 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 19 Jun 2024 15:27:06 +0000 Subject: [PATCH] rangeproof: add unit test for malleating single-value proofs I was a bit confused reading `secp256k1_rangeproof_getheader_impl` because in the case of single-value proofs (`has_nz_range == 0`) some bits of the header are unconstrained. At first I thought this was a malleability vector. And I think I've had this same confusion in the past. But in fact it is not a malleability vector because the whole header gets hashed into the proof. Add a unit test to confirm this to reduce future confusion. --- src/modules/rangeproof/tests_impl.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index d1abe204..49cc16cf 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -422,6 +422,7 @@ static void test_single_value_proof(uint64_t val) { uint64_t val_out = 0; size_t m_len_out = 0; + size_t i; secp256k1_testrand256(blind); secp256k1_testrand256(nonce); @@ -463,6 +464,30 @@ static void test_single_value_proof(uint64_t val) { CHECK(plen == 73); } + /* Test if trailing bytes are rejected. */ + proof[plen] = 0; + CHECK(secp256k1_rangeproof_verify( + CTX, + &min_val_out, &max_val_out, + &commit, + proof, plen + 1, + NULL, 0, + secp256k1_generator_h + ) == 0); + /* Test if single-bit malleation is caught */ + for (i = 0; i < plen*8; i++) { + proof[i >> 3] ^= 1 << (i & 7); + CHECK(secp256k1_rangeproof_verify( + CTX, + &min_val_out, &max_val_out, + &commit, + proof, plen, + NULL, 0, + secp256k1_generator_h + ) == 0); + proof[i >> 3] ^= 1 << (i & 7); + } + /* Test if unchanged proof is accepted. */ CHECK(secp256k1_rangeproof_verify( CTX, &min_val_out, &max_val_out,