Skip to content

NUT-12: domain-tagged raw-byte challenge hash (hash_e v2) #369

@robwoodgate

Description

@robwoodgate

The current challenge hash concatenates the hex-encoded text of each point before hashing:

e = SHA256(hex(R1) || hex(R2) || hex(A) || hex(C'))

Each uncompressed point is 65 bytes -> 130 lowercase hex characters, encoded as UTF-8 bytes before the SHA256. The lengths are fixed so there's no boundary ambiguity, but there's an encoding pipeline that cross-language implementations have to get right in full.

We could use a cleaner form, following BIP-340 conventions:

e = SHA256(b"Cashu_DLEQ_E_v1" || R1 || R2 || A || C')

Notes

  • Simpler implementation: Points are raw uncompressed SEC1 bytes (65 bytes each). The domain tag is 15 UTF-8 bytes. No intermediate encodings required.

  • This doesn't close any known attack: the current encoding is unambiguous. The motivation is implementation correctness: wrong hex case, wrong text encoding, or a missing encode step can all silently produce a different hash.

  • Migration: this is a breaking change. All existing DLEQ proofs would fail under the new hash scheme.

  • Implementations would need to try the new hash first and fall back to the legacy function during a transition window while tokens cycle out of circulation.

  • Suggest this follows feat(nut12): deterministic DLEQ nonce derivation #368 once that settles: the nonce change was free, this one needs a coordinated migration

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions