Skip to content

fix(keyring-eth-ledger-bridge): normalize signature v value for proper recovery#449

Merged
gantunesr merged 4 commits intomainfrom
fix/normalize-signature-recovery-param
Jan 30, 2026
Merged

fix(keyring-eth-ledger-bridge): normalize signature v value for proper recovery#449
gantunesr merged 4 commits intomainfrom
fix/normalize-signature-recovery-param

Conversation

@cloudonshore
Copy link
Copy Markdown
Contributor

@cloudonshore cloudonshore commented Jan 29, 2026

Summary

Ledger devices may return signature v as 0 or 1 (modern format), but Ethereum's ecrecover expects 27 or 28. This causes "The signature doesnt match the right address" errors in signPersonalMessage and signTypedData.

Fix

if (recoveryParam === 0 || recoveryParam === 1) {
  recoveryParam += 27;
}

Why This Wasn't Fixed Before

Original bug (pre-2022): The code subtracted 27 from v:

let v = payload.v - 27  // WRONG

This converted correct values (27/28) into incorrect ones (0/1).

PR #152 (August 2022): Changed to pass through the raw value:

let v = parseInt(payload.v, 10)  // Just pass through

This fixed the case where Ledger returns 27/28, but assumed Ledger always returns 27/28.

The gap: Ledger devices may return 0/1 depending on firmware, signing method, or device model. PR #152 didn't normalize these values.

Issue #10850 was closed prematurely in January 2024 with "I expect this was resolved in PR #152" — but PR #152 only fixed one direction of the problem.

References

This is a well-known issue with a standard fix across the ecosystem:


Note

Medium Risk
Changes signature formatting in signPersonalMessage and signTypedData, which can affect signature verification and downstream consumers if assumptions about v differ. Scope is small and covered by new unit tests for multiple v cases.

Overview
Fixes Ledger signing to normalize the recovery param (v) so devices returning modern values 0/1 are converted to legacy 27/28 before building the final signature in ledger-keyring.ts.

Adds focused tests covering v normalization for both signPersonalMessage and signTypedData, and updates the CHANGELOG.md entry accordingly (plus minor Jest coverage threshold tweaks).

Written by Cursor Bugbot for commit e756502. This will update automatically on new commits. Configure here.

…r recovery

Ledger devices may return v as 0 or 1 (modern format), but signature
recovery functions like `recoverPersonalSignature` and `recoverTypedSignature`
expect v to be 27 or 28 (legacy format per EIP-191/EIP-712).

This caused "The signature doesnt match the right address" errors when
Ledger returned v=0 or v=1, as the hex conversion produced "00"/"01"
instead of "1b"/"1c".

The fix normalizes v before hex conversion in both `signPersonalMessage`
and `signTypedData` methods.
@cloudonshore cloudonshore requested a review from a team as a code owner January 29, 2026 20:50
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

gantunesr
gantunesr previously approved these changes Jan 30, 2026
Copy link
Copy Markdown
Member

@gantunesr gantunesr left a comment

Choose a reason for hiding this comment

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

Looks good, left a comment about an edge case but feel free to ignore it

Extract duplicate v normalization logic into a private helper method
as suggested in PR review. This improves code maintainability by
consolidating the normalization logic in one place.

Coverage thresholds adjusted slightly due to branch counting changes
from code consolidation (same code paths are tested, just counted
differently by Jest).
@cloudonshore cloudonshore force-pushed the fix/normalize-signature-recovery-param branch from 042f3f2 to e756502 Compare January 30, 2026 18:56
@gantunesr gantunesr added this pull request to the merge queue Jan 30, 2026
Merged via the queue into main with commit f4f52c8 Jan 30, 2026
37 checks passed
@gantunesr gantunesr deleted the fix/normalize-signature-recovery-param branch January 30, 2026 22:00
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.

3 participants