Skip to content

blind: verify rangeproofs for confidential issuance amounts - #298

Open
delta1 wants to merge 2 commits into
ElementsProject:masterfrom
delta1:fix/issuance-rangeproof-verification
Open

delta1 wants to merge 2 commits into
ElementsProject:masterfrom
delta1:fix/issuance-rangeproof-verification

Conversation

@delta1

@delta1 delta1 commented Sep 14, 2026

Copy link
Copy Markdown
Member

verify_tx_amt_proofs pushed confidential issuance amount and inflation
keys commitments into the balance sum without verifying any rangeproof.
The commitment entered the aggregate sum as an unconstrained curve point,
making the value-conservation check satisfiable for an arbitrary
transaction carrying an issuance: a relying verifier could be induced to
accept a transaction that mints value out of nothing.

This PR verifies the accompanying rangeproof against the unblinded
issuance generator, mirroring Elements Core's VerifyIssuanceAmount:
the proof message is empty for issuances, and the generator is the
unblinded generator of the issued asset (resp. reissuance token). A
confidential issuance amount without a rangeproof is now rejected with
VerificationError::RangeProofMissing.

verify_tx_amt_proofs pushes confidential issuance amount commitments into
the balance sum without verifying any rangeproof, making the aggregate
value-conservation check vacuous for any transaction carrying an issuance.

Adds a PoC: 1 L-BTC in, 100 L-BTC out, gap supplied by a raw 99*G_LBTC
point in asset_issuance.amount, and a control asserting that removing the
forged issuance makes the balance check fail.
verify_tx_amt_proofs pushed confidential issuance amount and inflation
keys commitments into the balance sum without verifying any rangeproof.
The commitment therefore entered the aggregate sum as an unconstrained
curve point, making the value-conservation check satisfiable for an
arbitrary transaction carrying an issuance: a relying verifier could be
induced to accept a transaction that mints value out of nothing.

Verify the accompanying rangeproof against the unblinded issuance
generator, mirroring Elements Core's VerifyIssuanceAmount: the proof
message is empty for issuances, and the generator is the unblinded
generator of the issued asset (resp. reissuance token). A confidential
issuance amount without a rangeproof is rejected with
VerificationError::RangeProofMissing.

Tests: a forged issuance commitment is now rejected, and a legitimately
blinded issuance produced by blind_issuances still verifies.
@apoelstra

Copy link
Copy Markdown
Member

Since this looks alarming -- note that the invalid issuance here is rejected by all nodes on the network, even by testproposedblock, and the bad data is covered by signature hashes (so if a wallet is fooled into signing this the signature will be harmlessly invalid).

So it's ultimately no more harmless than any other form of invalid transaction that you can construct and get through this library, which does not claim to be (and never will claim to be) a complete consensus implementation.

Comment thread src/blind.rs
// Issuance pseudo-inputs are never asset-blinded: the
// generator is the unblinded generator of the issued
// (or reissuance token) asset.
let gen = Generator::new_unblinded(secp, asset.into_tag());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 173321e:

Nit: moving this line was not necessary (and it causes an unnecessary generator computation in the Value::Null case).

@apoelstra

Copy link
Copy Markdown
Member

Because the doccomment for verify_tx_amt_proofs claims that it does this check, and it didn't, we should backport to 0.25.x onward.

@apoelstra apoelstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 173321e; successfully ran local tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants