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

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions