feat: add p2pk_signing_keys to SendOptions#1835
Conversation
|
see #1750 for the first PR attempt |
lescuer97
left a comment
There was a problem hiding this comment.
some comments around the code and proper flow
060ff2b to
04c584e
Compare
|
thanks y'all. i rebased against main and all comments addressed. ready for another look |
|
@thesimplekid any ETA on this? should i rebase? |
| continue; | ||
| }; | ||
|
|
||
| let Ok(data_key) = crate::nuts::PublicKey::from_str(secret.secret_data().data()) else { |
There was a problem hiding this comment.
This signability filter only checks the P2PK data key, but P2PK conditions can also require additional pubkeys via n_sigs. A proof where the wallet has the data key but not enough additional required keys will pass this filter, then fail later at swap/confirm with a mint rejection instead of being excluded as unsignable. Can this reuse the same requirements logic as verification, or sign and verify before treating the proof as selectable?
| &options.p2pk_signing_keys, | ||
| ) | ||
| .await?; | ||
| if !keys.is_empty() { |
There was a problem hiding this comment.
In passthrough mode this signs only when a matching key is found, but it does not fail if no key is found or if the proof is only partially signed. That can create a token containing locked proofs that the recipient cannot redeem. Before creating the token, this should verify the passthrough proofs satisfy their spending conditions and return an error if they do not.
| p2pk_signing_keys: opts | ||
| .p2pk_signing_keys | ||
| .into_iter() | ||
| .filter_map(|k| k.try_into().ok()) |
There was a problem hiding this comment.
This silently drops invalid FFI secret keys. ReceiveOptions uses a fallible conversion and returns an error for invalid p2pk_signing_keys; send should do the same so callers do not get a later InsufficientFunds or mint rejection caused by a key that was ignored during conversion.
thesimplekid
left a comment
There was a problem hiding this comment.
Noticed a few things and yes could you squash and rebase and we can get it merged thanks.
04c584e to
7daf77c
Compare
|
ready for re-review. my agent also found an ffi bug that i will be opening a different pr to fix |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1835 +/- ##
==========================================
+ Coverage 65.91% 66.23% +0.31%
==========================================
Files 330 330
Lines 58129 58641 +512
==========================================
+ Hits 38317 38841 +524
+ Misses 19812 19800 -12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
related bug fix: #1970 |
5dd6e16 to
d66bab6
Compare
d66bab6 to
2c898e1
Compare
|
oh shit my agent force pushed this branch. woops. i will try to reconcile the two force pushes. |
|
ah ok nm, it looks like codex did the right thing. please let me know if the force push was destructive. i tried to put guardrails in place but it seems like controlling agents is an impossible task. ¯\_(ツ)_/¯ |
9523a00 to
c2d29dc
Compare
|
We can avoid needed the direct secp dep by just changing the error to not use transparent, I did this in this commit bf2757f. I also think it is more explixt and better if we use a enum vs the bool, I added that here c2d29dc. If you're happy with those changes I can merge and do any further rebasing once CI completes. |
c2d29dc to
f0b2baa
Compare
f0b2baa to
0ce89bb
Compare
|
LGTM I have confirmed that hashpool mints ehash with this PR branch as it is. Sorry about the dependency churn, I need to work on my agent harness and put more human in the loop before pushing to a PR branch. Thanks for all the fee and enum improvements! Great stuff! |
0ce89bb to
e10a579
Compare
Replace the send-side `allow_locked_proofs` boolean with an explicit `P2PKLockedProofSendMode` enum. The default remains swapping P2PK-locked proofs, while direct signed passthrough is now represented as `SignAndSend`. Update the wallet re-export, FFI conversions/defaults, and P2PK integration tests to use the new mode.
e10a579 to
25c274c
Compare
PR cashubtc/cdk#1835 (P2PK signing keys) was merged on 2026-05-21. The vnprc/cdk fork is no longer needed. Changes: - roles/Cargo.toml, protocols/Cargo.toml: redirect [patch.crates-io] from vnprc/cdk@9523a003 to cashubtc/cdk@1572941d for all 9 cdk crates - devenv.nix: update cdkRepo/cdkCommit variables and build:cdk:cli task - roles/mint/Cargo.toml: bump cdk-ehash rev b7edd52 -> c1a11ba (add onchain: None to SettingsResponse, new field in upstream CDK) - roles/mint/src/main.rs: update HttpCache construction to async HttpCache::from_config(...).await? (sync From impl removed in CDK) - roles/Cargo.lock: pin MSRV-sensitive transitive deps to pre-1.88 versions for devenv Rust 1.86.0 compatibility
Add
p2pk_signing_keys: Vec<SecretKey>andallow_locked_proofs: booltoSendOptionsso wallets holding P2PK-locked proofs can spend them through the standardprepare_send/confirmflow without a separate manual swap.Behaviour
p2pk_signing_keysis non-empty andallow_locked_proofsis false (the default), all selected proofs are routed through a swap so the resulting token contains fresh, unconditioned proofs.allow_locked_proofs: trueopts in to the less-private passthrough path: proofs are signed and retain their spending conditions in the token. This is useful for multi-hop or offline flows where the next holder intentionally receives signed-but-still-locked proofs.SIG_ALL incompatibility
SigFlag::SigAllis incompatible with passthrough signing: the signature would need to commit to swap outputs that do not exist at signing time.confirm()now callsenforce_sig_flag()on the proofs-to-send set and returnsnut11::Error::SigAllNotSupportedHereearly rather than silently producing an unspendable token.Changes
cdk-common: addp2pk_signing_keysandallow_locked_proofstoSendOptions, with doc comments explaining the SigAll incompatibility.cdk/wallet/util.rs: extractsign_proofs()with four unit tests covering correct key, wrong key, plain proof, and empty-keys cases.cdk/wallet/send/saga/mod.rs: shadowforce_swaptotrueininternal_preparewhen signing keys are provided and passthrough is not opted in; callsign_proofs()inconfirm()for bothproofs_to_swap(default path) andproofs_to_send(passthrough path); add SigAll check with an explanatory block comment before the passthrough signing block.cdk-ffi: addp2pk_signing_keysandallow_locked_proofsto FFISendOptionsand update bothFromconversions.Description
Add
p2pk_signing_keys: Vec<SecretKey>andallow_locked_proofs: booltoSendOptionsso wallets holding P2PK-locked proofs can spend them through the standardprepare_send/confirmflow without a separate manual swap.Default behaviour (
allow_locked_proofs: false): all selected proofs are routed through a swap, producing a clean token with no spending conditions. The caller provides signing keys only to authorize the swap inputs.Passthrough (
allow_locked_proofs: true): proofs are signed in-place and retain their spending conditions. Useful for multi-hop or offline flows where the next holder intentionally receives signed-but-still-locked proofs.SigAll rejection:
SigFlag::SigAllis incompatible with passthrough because the signature would need to commit to swap outputs that don't exist at signing time.confirm()detects this viaenforce_sig_flag()and returnsnut11::Error::SigAllNotSupportedHereearly rather than silently producing an unspendable token.Also fixes a force-swap short-circuit bug where proofs summing exactly to the send amount bypassed the swap entirely, causing locked proofs to escape into the token unsigned.
Test plan
cargo test -p cdk wallet::util— 5 unit tests passtest_p2pk_send_options_signing_keys— normal signing flowtest_p2pk_signing_keys_exact_denomination_short_circuit— force-swap regressiontest_p2pk_allow_locked_proofs_passthrough— passthrough opt-intest_p2pk_allow_locked_proofs_rejects_sig_all— SigAll rejectionNotes to the reviewers
Suggested CHANGELOG Updates
CHANGED
ADDED
REMOVED
FIXED
Checklist
just final-checkbefore committing