NUT-XX: Pay-to-Blinded-Key (P2BK) #291
No reviewers
Labels
No labels
breaking change
bug
documentation
enhancement
needs discussion
needs implementation
new nut
ready
wallet-only
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo-admin/nuts!291
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "blinded-p2pk"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #290
This PR lays out rules for blinding locking keys in secrets with p2pk locking conditions.
Implementation only requires client side (wallet) additional logic.
Is this removal intentional? It breaks table rendering
Tags entry must be included to ensure normalization is consistent
@ -0,0 +1,219 @@# NUT-26: Pay-to-Blinded-Key (P2BK)The reference implementation for cashu-ts is currently in the v3-hackday branch of my own repo.
It is built on top of v3-alpha-2, so I'll PR it to v3-alpha-dev branch once we catch it up to my current v3 tip.
Well spotted 👍
I've updated the cashu-ts implementation to handle Schnorr-derived pubkeys as well. This allows Nostr users to sign P2BK tokens locked with their
02-prefixed hexpub or NIP-61 pubkey.We should probably document the Schnorr secret key derivation in this NUT, since it’s not as straightforward.
For compressed SEC1 keys, the public key includes its Y-parity bit, so the blinded secret key is always derived as
(p + r) mod n. Simples.For Schnorr, public keys are x-only with enforced even-Y parity, which means the original secret key
pmay have beennegated to ensure an even-Y public key.
So when deriving the blinded secret key for a blinded pubkey
P', we need to check both candidates,(p + r) mod nand(-p + r) mod n, and select the one whose derived public key matchesP'in the proof.@robwoodgate
Why didn't this problem emerge in the tests?
just speculating: maybe the tests do not include this case? if that's true, we should add a case that triggers the need for this behavior
It did. I added tests for Schnorr derived keys when I found out P2BK wasn't consistently working with Nostr secret keys. Then I fixed it :)
And just to be clear, there was never an issue signing regular Schnorr pubkey locked proofs. It was just for P2BK where we have to derive an sk for a blinded Schnorr derived pubkey.
Couple of minor nits, otherwise ACK @
ea6888e552@ -0,0 +1,219 @@# NUT-26: Pay-to-Blinded-Key (P2BK)We should probably stay consistent with Cashu ecosystem and say '02' prefixed.
Pubkeys appearing in secrets should always be compressed SEC1 (33-byte hex) format.
@robwoodgate
Yes that's clear.
Thanks for merging my nit suggestions - sorry, I spelt ecosystem wrong in L23
Aside from my gaff - ACK @
e38faa0f86I've added Cashu-TS with P2BK support (
v3-hackday to #f3b9a9e) to Cashu NutLock, so we can play with it in the field. Cashu Redeem and Witness are also P2BK aware now.TS files for these tools available here.
Some topics that were discussed off-proposal:
rtop2pk_rp2pk_rin theProofobject, instead of the secret. Keep secret kind as "P2PK" and avoid any post-hoc normalization (do not break rules: secret stays the same).p2pk_rto the original public key, so only the intended receiver can actually see it (for use in public context, where the Mint could be tapping into)Have updated the reference implementation for cashu-ts to the agreed new format.
nut26flag to payment requests.prkey forp2pk_rpris encoded as an array of Uint8Array byte strings for better CBOR compressionCashu NutLock and related Nostrly Cashu tools have also been updated to use this latest version.
Here is a sample P2BK token created with NutLock:
Great work @lollerfirst, you've captured everything really well.
I've added a couple of suggestions for absolute clarity, but this is looking great.
@ -0,0 +1,219 @@# NUT-26: Pay-to-Blinded-Key (P2BK)Tags if empty was only vital when we were mutating the secret. It can be optional now.
i don't really understand this requirement. I think it should probably be something like:
SHOULD -> MUST?
@ -0,0 +1,219 @@# NUT-26: Pay-to-Blinded-Key (P2BK)Ah probably can be removed altogether. Clanker sometimes likes to be verbose for no reason.
@ -0,0 +1,219 @@# NUT-26: Pay-to-Blinded-Key (P2BK)Cashu-TS de-duplicates the derived secret keys, but it's not vital. Just saves some signing attempts.
Happy either way.
The important bit is "Wallets MUST preserve ordering of the p2pk_r array"
ACK
Couple more suggestions
@ -0,0 +185,4 @@- Each $r_i$ MUST satisfy $1 \leq r_i \leq n-1$; randomness MUST be uniform and MUST NOT be reused across blinded keys.- Wallets SHOULD reject proofs that advertise `p2pk_r` but do not contain the corresponding blinded keys. There must be one entry in `p2pk_r` for every blinded key.@ -0,0 +190,4 @@- Mint privacy: mints never learn the blinding scalars or the original pubkeys; spends appear identical to standard P2PK.- Freshness: reusing scalars enables linkage across blinded keys. Always use fresh randomness per key.- Metadata leakage: wallets MUST keep `p2pk_r` private between sender and receiver (do not leak to the Mint).@ -0,0 +185,4 @@- Each $r_i$ MUST satisfy $1 \leq r_i \leq n-1$; randomness MUST be uniform and MUST NOT be reused across blinded keys.- Wallets SHOULD reject proofs that advertise `p2pk_r` but do not contain the corresponding blinded keys. There must be one entry in `p2pk_r` for every blinded key.I think this is redundant, as the secp library already does this.
@ -0,0 +190,4 @@- Mint privacy: mints never learn the blinding scalars or the original pubkeys; spends appear identical to standard P2PK.- Freshness: reusing scalars enables linkage across blinded keys. Always use fresh randomness per key.- Metadata leakage: wallets MUST keep `p2pk_r` private between sender and receiver (do not leak to the Mint).This follows logically from the previous point.
Re: https://github.com/cashubtc/nuts/pull/291/commits/c63aa7feda27502758e09b6321b95d25d8b3ba4a extending NUT10Options.
In Cashu-TS, I did a NUT-26 flag at the top level... as
p2pk_ris now a Proof level concept, not a secret related one.https://github.com/robwoodgate/cashu-ts/blob/v3-hackday/src/model/PaymentRequest.ts
It probably doesn't matter much either way, but as blinding is specifically a P2PK related concept, perhaps it should not be part of the generic NUT-10 options?
Maybe you're right.
NACK - I've been thinking about this, and am uneasy that the
rs in the proof effectively render P2BK useless where they are posted publicly. Also, storing (up to) 11rs per proof dramatically increases the size of the token.So I've proposed an alternative blinding scheme, based on ECDH shared secrets.
PR https://github.com/cashubtc/nuts/pull/300
Closing in favor of ECDH derived blinding factors
Pull request closed