Skip to content

fix: verify derive signature for all derivation paths and update Swift bindings#67

Open
r1b2ns wants to merge 3 commits intobitcoindevkit:masterfrom
r1b2ns:fix/signature-derivation-path
Open

fix: verify derive signature for all derivation paths and update Swift bindings#67
r1b2ns wants to merge 3 commits intobitcoindevkit:masterfrom
r1b2ns:fix/signature-derivation-path

Conversation

@r1b2ns
Copy link
Copy Markdown
Contributor

@r1b2ns r1b2ns commented Apr 13, 2026

Description

  • Fix critical security bug where TapSigner derive response signature was not verified when a derivation path was provided
  • Fix incorrect card_nonce usage — was using the post-command nonce instead of the pre-command nonce for verification
  • Regenerate Swift FFI bindings with latest uniffi-rs

Notes to the reviewers

Signature verification (security fix)

In TapSignerShared::derive(), the response signature was only verified when
pubkey == master_pubkey (i.e., no derivation path). When a path was provided,
the card returns a derived pubkey different from master, causing the if guard
to skip verification entirely.

Per the Coinkite Tap Protocol
and the reference Python implementation (verify_master_pubkey in cktap/utils.py),
the card always signs with the master private key, regardless of whether a
derivation path was used. The verification is now unconditional.

Nonce ordering fix

The card_nonce used in message construction was captured after set_card_nonce()
updated it with the response nonce (intended for the next command). The card signs
with the nonce that existed before the command. This matches the pattern already
used correctly in SatsCard::derive().

Tests report

Screenshot 2026-04-14 at 10 46 22
  • Additionally, I’ve run tests using cktap-swift in SatsBuddy, and it works as expected

Issues

#23 Fix verifying the sig when a derivation path is used

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

r1b2ns added 2 commits April 13, 2026 11:02
The derive response signature was only verified when no derivation path
was used (pubkey == master_pubkey). Per the Coinkite protocol, the card
always signs with the master private key regardless of path, so the
verification must run unconditionally.

Also fixes a bug where card_nonce was captured AFTER transmit instead of
BEFORE — the card signs with the pre-command nonce, but the code was
using the new nonce from the response.
@r1b2ns r1b2ns marked this pull request as ready for review April 14, 2026 11:46
@r1b2ns r1b2ns changed the title [draft] fix: verify derive signature for all derivation paths and update Swift bindings fix: verify derive signature for all derivation paths and update Swift bindings Apr 14, 2026
@notmandatory
Copy link
Copy Markdown
Member

Does this fix #23? If so please reference that in the description. Also can you add a unit test to verify the behavior with and without derivation paths?

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