Skip to content

Accept ECDSA signatures shorter than 71 bytes#69

Open
johnzilla wants to merge 3 commits into
rust-bitcoin:masterfrom
johnzilla:fix-ecdsa-signature-length
Open

Accept ECDSA signatures shorter than 71 bytes#69
johnzilla wants to merge 3 commits into
rust-bitcoin:masterfrom
johnzilla:fix-ecdsa-signature-length

Conversation

@johnzilla

Copy link
Copy Markdown

verify_full_p2wpkh gated the encoded ECDSA signature length on 71 | 72 and rejected everything else with Error::SignatureLength. ECDSA signatures aren't fixed length — a low-S DER signature is shorter than 71 bytes when r or s serialize to fewer than 32 bytes (~1% of signatures) — so valid signatures that sign_simple itself produces were rejected by verify_simple.

This peels the trailing sighash flag off and lets from_der validate the remainder instead of gating on length, with an empty-input guard so the slice index can't panic. The taproot path is unchanged.

Adds a P2WPKH regression vector (a 70-byte signature); it fails on master and passes with this change. cargo fmt --check, cargo clippy --all --all-targets -- --deny warnings, and cargo test --all are green.

Fixes #68.

Comment thread src/verify.rs Outdated
Comment on lines +157 to +158
let sighash_type =
EcdsaSighashType::from_consensus(encoded_signature[signature_length - 1] as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
let sighash_type =
EcdsaSighashType::from_consensus(encoded_signature[signature_length - 1] as u32);
let sighash_type =
EcdsaSighashType::from_standard(encoded_signature[signature_length - 1] as u32);

Thank you for your work on this.
I think from_standard is a better fit here. from_standard matches the byte strictly and errors on anything non-standard, whereas from_consensus forces unknown bytes to All​. Open to your thought.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good call. from_standard is the right strictness for a verifier; from_consensus would fold non-standard bytes to All and accept them. It also lines up with how the taproot path parses its flag.

One detail: from_standard returns Result<_, NonStandardSighashTypeError>, which doesn't match the existing SigHashTypeInvalid variant (typed to InvalidSighashTypeError), so I added a SigHashTypeNonStandard variant and .context()'d onto it, mirroring the taproot handling. Pushed. Thanks for the review!

@aagbotemi aagbotemi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ACK 742487f

@johnzilla could you also sign your commits, to match the convention used by the rest of the codebase?

Comment thread src/error.rs Outdated
johnzilla and others added 2 commits June 30, 2026 09:56
ECDSA signatures are not fixed length: a low-S DER signature is shorter
than the usual 71 or 72 bytes when r or s serialize to fewer than 32
bytes (roughly 1% of signatures). verify_full_p2wpkh matched the encoded
signature length against `71 | 72` and rejected everything else with
Error::SignatureLength, so a valid signature that sign_simple itself can
produce was rejected by verify_simple.

Split the trailing sighash flag off and let from_der validate the
remainder rather than gating on length. The empty case is guarded so the
slice index cannot panic.
from_consensus folds unrecognized sighash bytes to All, so a signature
with a non-standard flag would pass the == All check. Parse with
from_standard instead, which errors on anything that isn't a standard
sighash type, matching the strictness of the taproot path. Adds a
SigHashTypeNonStandard error variant for the parse failure.

Co-authored-by: aagbotemi <63763418+aagbotemi@users.noreply.github.com>
@johnzilla johnzilla force-pushed the fix-ecdsa-signature-length branch from 742487f to d33307e Compare June 30, 2026 13:56
@johnzilla

Copy link
Copy Markdown
Author

Heads up: I force-pushed to sign both commits with my SSH key (they show as Verified now). No content change from what you reviewed, just the signatures added.

Co-authored-by: Abiodun Awoyemi <63763418+aagbotemi@users.noreply.github.com>
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.

verify_simple rejects valid ECDSA signatures shorter than 71 bytes

2 participants