Skip to content

fix(cketh): recover a signature against the key that made it - #11254

Merged
gregorydemay merged 1 commit into
greg/DEFI-2926-sweeper-send-taskfrom
greg/DEFI-2926-recover-with-signing-key
Aug 25, 2026
Merged

fix(cketh): recover a signature against the key that made it#11254
gregorydemay merged 1 commit into
greg/DEFI-2926-sweeper-send-taskfrom
greg/DEFI-2926-recover-with-signing-key

Conversation

@gregorydemay

@gregorydemay gregorydemay commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Why

compute_recovery_id recovers a signature's parity bit against lazy_call_ecdsa_public_key() — the minter's master key — while sign and Authorization::sign sign under a caller-supplied derivation path. Recovery only ever succeeds against the key that produced the signature, so signing under anything but the empty main path finds no parity at all: try_recovery_from_digest returns an error and the unwrap_or_else traps. The debug_assert! above it fails first in debug builds.

Nothing calls it with a non-empty path yet, so this is latent today. It stops being latent with the first EIP-7702 authorization, which is signed by a deposit address' own key by definition — and a tuple that does not ecrecover to that address is skipped silently by the protocol, leaving the batch's inner call to hit a code-less address and revert the whole sweep.

What

Recovery now derives the master key along the same path before recovering. The derivation is shared with address derivation rather than duplicated: deposit_address::derive_public_key becomes the single place a subkey is computed, and address derivation is that key's address. The key a signature is recovered against is therefore, by construction, the key whose address it belongs to.

The signing functions now take the path as Vec<ByteBuf> — the form MAIN_DERIVATION_PATH, sweeper_derivation_path() and deposit_derivation_path() already produce — and build the management-canister DerivationPath themselves. That is the structural half of the fix: one owner for both uses of the path, so the signing key and the recovery key cannot drift apart again. Call sites lose a wrapper.

An empty path derives to the master key, so the main address and every withdrawal are unaffected.

Tests

Three pure unit tests, no canister involved. The one that pins the bug signs a digest with a key derived along a deposit path and asserts recovery succeeds against the derived key and fails against the master key, so it demonstrates the trap rather than asserting the new code agrees with itself.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes recovery-ID computation to use the same derived ECDSA key that produced each signature.

Changes:

  • Shares public-key derivation with deposit-address derivation.
  • Passes raw derivation paths through transaction and authorization signing.
  • Adds unit coverage for derived-key recovery.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
withdraw.rs Passes the main derivation path directly.
tx/signed.rs Uses one path for signing and recovery.
tx/mod.rs Recovers signatures against the derived key.
tx/eip_7702.rs Applies derived-key recovery to authorizations.
sweep.rs Passes the sweeper path directly.
deposit_address/tests.rs Tests key derivation and signature recovery.
deposit_address/mod.rs Extracts shared public-key derivation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from 2082fa4 to 253fa99 Compare August 21, 2026 14:45
@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from 253fa99 to 1569069 Compare August 25, 2026 07:16
@gregorydemay
gregorydemay marked this pull request as ready for review August 25, 2026 07:33
@gregorydemay
gregorydemay requested a review from a team as a code owner August 25, 2026 07:33
@zeropath-ai

zeropath-ai Bot commented Aug 25, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 8a2235f.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► rs/ethereum/cketh/minter/src/deposit_address/mod.rs
    Implement derive_public_key and adjust derivation path handling
► rs/ethereum/cketh/minter/src/deposit_address/tests.rs
    Add tests for derive_public_key behavior and master key derivation
► rs/ethereum/cketh/minter/src/sweep.rs
    Use sweeper_derivation_path() directly instead of DerivationPath::new(...)
Enhancement ► rs/ethereum/cketh/minter/src/tx/eip_7702.rs
    Adapt sign method to accept Vec for derivation_path and pass to derive logic
► rs/ethereum/cketh/minter/src/tx/mod.rs
    Import derive_public_key and adjust state function to lazy_call_ecdsa_public_key_with_chain_code
► rs/ethereum/cketh/minter/src/tx/mod.rs
    Add ByteBuf import for derivation_path handling
► rs/ethereum/cketh/minter/src/tx/signed.rs
    Update sign function to take Vec for derivation_path and compute recovery with path
► rs/ethereum/cketh/minter/src/tx/mod.rs
    Change compute_recovery_id to accept derivation_path and compute with derived key
Enhancement ► rs/ethereum/cketh/minter/src/withdraw.rs
    Update sign invocation to pass MAIN_DERIVATION_PATH directly instead of wrapping in DerivationPath::new(...)

@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from 1569069 to b9cecd1 Compare August 25, 2026 10:04
@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from b9cecd1 to 3a44ed7 Compare August 25, 2026 11:21
Comment thread rs/ethereum/cketh/minter/src/deposit_address/tests.rs
@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from 3a44ed7 to a0597bd Compare August 25, 2026 13:05
Comment thread rs/ethereum/cketh/minter/src/tx/mod.rs Outdated
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gregorydemay
gregorydemay force-pushed the greg/DEFI-2926-recover-with-signing-key branch from a0597bd to 8a2235f Compare August 25, 2026 13:14
@gregorydemay
gregorydemay added this pull request to the merge queue Aug 25, 2026
Merged via the queue into master with commit b546d76 Aug 25, 2026
40 checks passed
@gregorydemay
gregorydemay deleted the greg/DEFI-2926-recover-with-signing-key branch August 25, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants