Skip to content

Note Commitment and Nullifier Formulas v1

Status: frozen for TKT-P3-36.

Purpose: define one canonical encoding and hash policy for note commitments and nullifiers used by prover/wallet/covenant integrations.

1. Canonical implementations

The canonical implementation surface is:

  • @bch-stealth/zk-notes
  • packages/zk-notes/src/commitment_nullifier_v1.ts
  • packages/zk-notes/src/note_tree_v1.ts (NoteLeafV1 encoding/hash primitives)

Downstream packages (wallet validation, planner, backend adapters) must consume these helpers and must not fork formula logic.

2. Note commitment v1

2.1 Leaf structure and ordering

NoteLeafV1 is encoded in this exact order:

  1. version = "NLeaf1" (6 ASCII bytes)
  2. poolId32
  3. shardId32
  4. ownerCommitment32
  5. valueCommitment32
  6. nonce32

2.2 Note commitment formula

noteCommitment32 = HASH256("NTL1" || encodeNoteLeafV1(noteLeaf))

No field reordering, shortening, or alternative domain tags are valid.

3. Nullifier formula v1

3.1 Domain tag

NULLIFIER_DERIVE_V1_DOMAIN_ASCII = "P3-16:nullifier:v1"

3.2 Preimage ordering

Nullifier preimage order is frozen as:

  1. domain tag ASCII bytes
  2. noteId32
  3. noteHash32
  4. senderPub33
  5. receiverSpendPub33
  6. shardId32

3.3 Nullifier formula

nullifier32 = HASH256(domain || noteId32 || noteHash32 || senderPub33 || receiverSpendPub33 || shardId32)

No domain substitutions and no field-order changes are allowed.

4. Serialization and reject rules

4.1 Byte constraints

  • noteId32, noteHash32, shardId32 MUST be exactly 32 bytes
  • senderPub33, receiverSpendPub33 MUST be exactly 33 bytes
  • all NoteLeafV1 32-byte fields MUST be exactly 32 bytes

Malformed lengths MUST reject deterministically.

4.2 Hex constraints

Hex helper inputs MUST:

  • be lowercase/uppercase hex-compatible ([0-9a-fA-F])
  • have even length
  • have exact byte width for each field

Malformed hex MUST reject deterministically.

4.3 Formula mismatch checks

Validation code may assert expected commitments/nullifiers against recomputed values. Any mismatch (including domain-tag mutation or ordering mutation) MUST reject deterministically.

5. Vectors

Canonical vectors:

  • packages/zk-notes/test-vectors/commitment_nullifier_v1.json

The vector set includes:

  • canonical valid note-commitment/nullifier cases
  • malformed-length rejects
  • malformed-hex rejects
  • domain-tag mismatch reject case
  • ordering mismatch reject case

6. Policy boundaries

  • Derivation paths are wallet policy and not part of formula validity.
  • Receiver identity model remains (A, B) at ownership layer; formulas consume concrete byte inputs only.