Skip to content

NUT-XX: Pay-to-Blinded-Key (P2BK)#291

Closed
a1denvalu3 wants to merge 22 commits intocashubtc:mainfrom
a1denvalu3:blinded-p2pk
Closed

NUT-XX: Pay-to-Blinded-Key (P2BK)#291
a1denvalu3 wants to merge 22 commits intocashubtc:mainfrom
a1denvalu3:blinded-p2pk

Conversation

@a1denvalu3
Copy link
Contributor

@a1denvalu3 a1denvalu3 commented Oct 2, 2025

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.

… NUT-11; add spec and README entry; ensure proper Markdown formatting
@a1denvalu3 a1denvalu3 changed the title NUT-XX:Pay-to-Blinded-Key (P2BK): NUT-XX:Pay-to-Blinded-Key (P2BK) Oct 2, 2025
@a1denvalu3 a1denvalu3 changed the title NUT-XX:Pay-to-Blinded-Key (P2BK) NUT-XX: Pay-to-Blinded-Key (P2BK) Oct 2, 2025
@a1denvalu3 a1denvalu3 marked this pull request as draft October 2, 2025 08:01
Copy link
Contributor

@robwoodgate robwoodgate left a comment

Choose a reason for hiding this comment

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

Tags entry must be included to ensure normalization is consistent

@robwoodgate
Copy link
Contributor

robwoodgate commented Oct 2, 2025

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.

a1denvalu3 and others added 2 commits October 3, 2025 09:40
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
@robwoodgate
Copy link
Contributor

robwoodgate commented Oct 4, 2025

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 p may have been
negated 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 n and (-p + r) mod n, and select the one whose derived public key matches P' in the proof.

@a1denvalu3
Copy link
Contributor Author

a1denvalu3 commented Oct 5, 2025

@robwoodgate

So when deriving the blinded secret key for a blinded pubkey P', we need to check both candidates, (p + >r) mod n and (-p + r) mod n, and select the one whose derived public key matches P' in the proof.

Why didn't this problem emerge in the tests?

@prusnak
Copy link
Collaborator

prusnak commented Oct 5, 2025

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

…k=p+r and k=-p+r); fix normalization to preserve empty tags; clarify key encodings. Resolves -+p issue per PR cashubtc#291 discussion.
@robwoodgate
Copy link
Contributor

@robwoodgate

So when deriving the blinded secret key for a blinded pubkey P', we need to check both candidates, (p + >r) mod n and (-p + r) mod n, and select the one whose derived public key matches P' in the proof.

Why didn't this problem emerge in the tests?

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 :)

@robwoodgate
Copy link
Contributor

@robwoodgate

So when deriving the blinded secret key for a blinded pubkey P', we need to check both candidates, (p + >r) mod n and (-p + r) mod n, and select the one whose derived public key matches P' in the proof.

Why didn't this problem emerge in the tests?

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.

robwoodgate

This comment was marked as outdated.

@a1denvalu3
Copy link
Contributor Author

a1denvalu3 commented Oct 5, 2025

@robwoodgate

And just to be clear, there was never an issue signing regular Schnorr pubkey locked proofs.

Yes that's clear.

a1denvalu3 and others added 2 commits October 6, 2025 07:37
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
robwoodgate

This comment was marked as outdated.

@robwoodgate
Copy link
Contributor

robwoodgate commented Oct 7, 2025

I'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.

@a1denvalu3
Copy link
Contributor Author

a1denvalu3 commented Oct 7, 2025

Some topics that were discussed off-proposal:

  • We should rename r to p2pk_r
  • We should move p2pk_r in the Proof object, instead of the secret. Keep secret kind as "P2PK" and avoid any post-hoc normalization (do not break rules: secret stays the same).
  • There should be a way to signal "support" for blinded keys in a NUT-18 request.
  • (Potentially) We could NIP44-encrypt p2pk_r to 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)

@robwoodgate
Copy link
Contributor

robwoodgate commented Oct 8, 2025

Have updated the reference implementation for cashu-ts to the agreed new format.

  • Renames r to p2pk_r
  • Moves p2pk_r to the Proof object, instead of the secret.
  • No longer mutates secret.
  • Adds nut26 flag to payment requests.
  • v4 token format uses pr key for p2pk_r
  • v4 token pr is encoded as an array of Uint8Array byte strings for better CBOR compression

Cashu NutLock and related Nostrly Cashu tools have also been updated to use this latest version.

Here is a sample P2BK token created with NutLock:

cashuBo2FteCJodHRwczovL21pbnQubWluaWJpdHMuY2FzaC9CaXRjb2luYXVjc2F0YXSBomFpSABQBVDwSUFGYXCBpWFhAWFzeQEUWyJQMlBLIix7Im5vbmNlIjoiNWYxN2U0MzU5YjFjZDAxYzkzNjQ4MGVkZGNjMGEzNzk2ZjJhYzM2MDVjNGIzOTkxZGE3YTQxY2UzNGE4MGY5OSIsImRhdGEiOiIwMzhiNTk0M2ZjMzY4ZjI1OWYzNTM5YTViN2FjMjE3ZjIzNzEwNzRkMzc1MDc3ZDMwNDZlMTk1NTkyYjI0Y2FjYTUiLCJ0YWdzIjpbWyJsb2NrdGltZSIsIjE3NTk5NjQzNDAiXSxbInJlZnVuZCIsIjAzNTJiOWFmNGJhMWRiMDliM2Y2Y2E1NDRhNmExY2M0OTQ1ZGRhZjY4MmZjOTMwMzYwYzVlZGU4NGQzZjNjNTBhYiJdXX1dYWNYIQKStW3NIERz0XR--cXYAkfmmo8iDigAc-2F8TE2MYhALGFko2FlWCDXvqR7-X6gJJiHa1T6eBaWHMnGMseti7OrXgwYGI3432FzWCBC6iVGhNhgqNPhA54qlYReHkNOMPHdRkPd2mlGykeB8GFyWCAsniO_fjxZSrh4lSelhNMkBZmMnDL1sdblE82YjYyjgmJwcoJYIHbeRz2-u06KCI0NMjMl75Vf5jnnmXcuONIg9ZVTefklWCAvZpnxoEhgKLdl9lFoU5bF-hVT8YsSmtrjO88OI0UUUw

Copy link
Contributor

@robwoodgate robwoodgate left a comment

Choose a reason for hiding this comment

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

Great work @lollerfirst, you've captured everything really well.

I've added a couple of suggestions for absolute clarity, but this is looking great.

a1denvalu3 and others added 4 commits October 9, 2025 22:34
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
Co-authored-by: Rob Woodgate <robwoodgate@users.noreply.github.com>
robwoodgate

This comment was marked as outdated.

Copy link
Contributor

@robwoodgate robwoodgate left a comment

Choose a reason for hiding this comment

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

Couple more suggestions

@robwoodgate
Copy link
Contributor

Re: c63aa7f extending NUT10Options.

In Cashu-TS, I did a NUT-26 flag at the top level... as p2pk_r is 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?

@a1denvalu3
Copy link
Contributor Author

as p2pk_r is now a Proof level concept

Maybe you're right.

@a1denvalu3 a1denvalu3 marked this pull request as ready for review October 17, 2025 08:33
@robwoodgate
Copy link
Contributor

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) 11 rs per proof dramatically increases the size of the token.

So I've proposed an alternative blinding scheme, based on ECDH shared secrets.
PR #300

@a1denvalu3
Copy link
Contributor Author

Closing in favor of ECDH derived blinding factors

@a1denvalu3 a1denvalu3 closed this Oct 20, 2025
@a1denvalu3 a1denvalu3 deleted the blinded-p2pk branch October 20, 2025 10:05
@ye0man ye0man added this to nuts Jan 13, 2026
@github-project-automation github-project-automation bot moved this to Backlog in nuts Jan 13, 2026
@github-project-automation github-project-automation bot moved this from Backlog to Done in nuts Jan 13, 2026
@ye0man ye0man removed this from nuts Jan 15, 2026
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.

Blinding the locking keys in NUT-11

4 participants