fix: verify derive signature for all derivation paths and update Swift bindings#67
fix: verify derive signature for all derivation paths and update Swift bindings#67r1b2ns wants to merge 3 commits intobitcoindevkit:masterfrom
Conversation
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.
|
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? |
|
This looks like the right way to fix it but I think it still doesn't work with real TAPSIGNER cards. I just tried it with one of mine and it says the signature fails. Do you have a real card to test with? $ just run derive -p 84,0,0
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/cktap-cli derive -p 84,0,0`
Enter cvc:
[cli/src/main.rs:233:21] &ts.derive(path.unwrap_or_default(), &cvc()).await = Err(
Secp256k1(
IncorrectSignature,
),
)
$ just run derive
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Running `target/debug/cktap-cli derive`
Enter cvc:
[cli/src/main.rs:233:21] &ts.derive(path.unwrap_or_default(), &cvc()).await = Ok(
PublicKey {
compressed: true,
inner: PublicKey(
f96ecf9fecd902bf724692ba340dc59200d45717552f94d62f8749f27b0922dd2f72c81368cc3f8c9e258a6a660a89d2f90825acc5ef91ff0938224d28dd6334,
),
},
) |
Unfortunately, I haven’t, but I’m looking for a card to test it better. I’ll keep it as a draft until I can test it properly. I’ve only tested it with a Satscard by compiling the library to Swift and testing it on iOS. |
Description
deriveresponse signature was not verified when a derivation path was providedcard_nonceusage — was using the post-command nonce instead of the pre-command nonce for verificationNotes to the reviewers
Signature verification (security fix)
In
TapSignerShared::derive(), the response signature was only verified whenpubkey == master_pubkey(i.e., no derivation path). When a path was provided,the card returns a derived pubkey different from master, causing the
ifguardto skip verification entirely.
Per the Coinkite Tap Protocol
and the reference Python implementation (
verify_master_pubkeyincktap/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_nonceused in message construction was captured afterset_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
Issues
#23 Fix verifying the sig when a derivation path is used
Checklists
All Submissions:
cargo fmtandcargo clippybefore committingNew Features:
Bugfixes: