Skip to content

NUT-00: add BLS12-381 (v3) protocol - #371

Open
robwoodgate wants to merge 19 commits into
cashubtc:mainfrom
robwoodgate:bls-protocol
Open

NUT-00: add BLS12-381 (v3) protocol#371
robwoodgate wants to merge 19 commits into
cashubtc:mainfrom
robwoodgate:bls-protocol

Conversation

@robwoodgate

@robwoodgate robwoodgate commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Implementations

NOTE: Length framed keyset ID derivation added in 68840cc

Summary

Adds Pairing-based BDHKE (BLS12-381) as the v3 Cashu blind-signature protocol for keysets with version byte 02, alongside the legacy secp256k1 protocol for 00/01 keysets.

  • NUT-00 defines the BLS12-381 protocol: hash_to_curve_G1 with the Cashu RFC 9380 DST, multiplicative blinding B_ = r·Y, blind signing C_ = a·B_, unblinding C = r^-1·C_, and verification by e(C, G2) == e(Y, K).
  • NUT-00 also defines deterministic weighted batch verification using a Fiat-Shamir transcript, rejection-sampled weights in Fr*, and explicit point-validation requirements to reject non-canonical encodings, identity points, off-curve points, and non-prime-order subgroup points before signing or verification.
  • NUT-01 version-gates key serialization: 00/01 keysets use compressed secp256k1 keys, while 02 keysets use compressed BLS12-381 G2 keys.
  • NUT-02 adds V3 keyset ID derivation with version byte 02, G2 public keys in the preimage, lowercased units, and updated V3 test vectors.
  • NUT-12 scopes DLEQ to secp256k1 keysets only. V3 proofs and blind signatures do not carry dleq; offline verification uses the pairing equality from NUT-00.
  • NUT-13 extends deterministic recovery for V3 keysets: secrets remain HMAC-SHA256-derived as in V2, while blinding factors use rejection sampling against BLS_FR_ORDER instead of modular reduction.
  • tests/00, 02, 13 add vectors for BLS round-trip signing, weighted batch verification, V3 keyset IDs, and V3 deterministic blinding-factor rejection sampling.

The JSON/wire shape of BlindedMessage, BlindSignature, Proof, and TokenV4 remains unchanged; the keyset version selects the curve and byte widths for B_, C_, C, and mint public keys.

@Egge21M

This comment was marked as resolved.

@Egge21M

This comment was marked as resolved.

@robwoodgate

robwoodgate commented May 21, 2026

Copy link
Copy Markdown
Collaborator Author

@Egge21M - Thank you for running the review bot. All issues raised have been addressed and this should be ready to review now.

cc: @callebtc @a1denvalu3 @thesimplekid

Comment thread 02.md
Comment thread 02.md
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread .DS_Store Outdated
Comment thread xx+1.md Outdated
robwoodgate

This comment was marked as resolved.

@robwoodgate

This comment was marked as resolved.

Comment thread 13.md Outdated
Comment thread 13.md Outdated
Comment thread 13.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Co-authored-by: a1denvalu3 <43107113+a1denvalu3@users.noreply.github.com>
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md Outdated
Comment thread 00.md
robwoodgate and others added 5 commits June 25, 2026 13:54
Co-authored-by: a1denvalu3 <43107113+a1denvalu3@users.noreply.github.com>
Co-authored-by: a1denvalu3 <43107113+a1denvalu3@users.noreply.github.com>
@TheMhv

TheMhv commented Jul 12, 2026

Copy link
Copy Markdown

Why change the protocol cryptographic algorithm? What the benefits of this change?

Comment thread 02.md Outdated
The Ys entries in PostCheckStateRequest are computed with the hash-to-curve
function of the proof's keyset: secp256k1 for version bytes 00 and 01
(33 bytes), BLS12-381 G1 for version byte 02 (48 bytes). Same scoping
pattern as NUT-01's key serialization.
The V3 preimage is built over raw bytes with len32 framing, in the style
of NUT-20's message aggregation: framed(keys) || framed(unit) ||
framed(fee), with minimal big-endian integers and an always-present
length prefix. This replaces the delimited ASCII format and its |
separator, which no other message in the protocol uses.

The unit string must match [a-z0-9_-]+ for V2 and V3 keysets, mirroring
the NUT-04/05 method rule. final_expiry is keyset metadata and is no
longer part of the V3 preimage.

V3 keyset IDs change; the V3 vectors and the NUT-13 V3 derivation
vector are regenerated from the reference implementations.
@robwoodgate

Copy link
Copy Markdown
Collaborator Author

BREAKING CHANGE

Length framed keyset ID derivation added in 68840cc

This also removes final_expiry from the derivation as agreed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

6 participants