Skip to content

Proof Envelope + Transcript Commitments v1

Status: frozen for TKT-P3-38
Goal: lock one canonical PBv1 envelope and transcript commitment policy so backend, wallet, and covenant paths commit the same bytes.

1. Scope

This freeze covers:

  • PBv1 envelope byte layout and section rules
  • transcript commitment rules that consume PBv1
  • transport chunk and hints commitment rules used by the rich wallet path
  • malformed/reject behavior expectations

This freeze does not define prover internals. It only defines what bytes are committed and how they are validated.

2. Canonical PBv1 envelope

Normative implementation:

  • packages/zk-boundary/src/proof_blob_v1.ts

Normative vectors/tests:

  • packages/zk-boundary/test-vectors/pbv1_vectors.json
  • packages/zk-boundary/test-vectors/pbv1_reject.json
  • packages/zk-boundary/src/tests/proof_blob_v1.test.ts

2.1 Header and section table

  • magic: ASCII PBV1
  • version: 0x01
  • flags: 0x00 (reserved)
  • backend id: u32le
  • section count: u8 (bounded by MAX_SECTIONS)
  • reserved bytes: zero

Section entries are fixed-width and include:

  • section_id (u16le)
  • reserved fields (must be zero)
  • length (u32le)
  • sha256(section_bytes)

2.2 Section policy

Stable section IDs:

  • 0x0001 PROOF (required, exactly once, must be first)
  • 0x0002 ENCRYPTED_PAYLOAD (optional)
  • 0x0003 HINTS (optional)

Unknown stable IDs are rejected. Experimental IDs (>= 0x8000) are allowed with size caps.

2.3 Canonical PB commitments

  • hashPBv1(bytes) = HASH256(bytes)
  • sectionsRootPBv1(bytes) is an ordered fold over section entries in table order

No sorting or canonicalization-by-reordering is allowed.

2.4 Mock-backend neutrality

PBv1 carries only generic envelope fields (backendId, section IDs/bytes/digests).
There are no mock-backend-only fields in the envelope schema.

3. Transcript policy v1 commitments

Normative implementation:

  • packages/zk-boundary/src/transcript_policy_v1.ts

Normative vectors/tests:

  • packages/zk-boundary/test-vectors/tpv1_vectors.json
  • packages/zk-boundary/src/tests/transcript_policy_v1.test.ts

3.1 PB transcript binds

  • tpv1_proofBlobBind32(pbv1Bytes) binds hashPBv1
  • tpv1_proofBlobSectionsBind32(pbv1Bytes) binds sectionsRootPBv1

These functions must reject malformed PBv1 inputs.

3.2 Transport chunk commitments

For rich wallet transport:

  • encrypted payload is split into exactly two ordered chunks
  • each chunk gets a chunk bind (index, length, HASH256(chunk))
  • payload root is an ordered fold over chunk binds
  • hints bind is tagHash(HINTS_HASH, HASH256(hints_bytes))
  • transport bind is tagHash(TRANSPORT_BIND, payloadRoot32 || hintsBind32)

4. Reject policy (frozen)

At minimum, malformed PB inputs must be rejected for:

  • bad magic/version/flags/reserved bytes
  • too-large section count
  • section table out of bounds
  • duplicate section IDs
  • unknown stable section ID
  • missing PROOF or wrong section order
  • section too large
  • digest mismatch
  • length mismatch / trailing bytes

These reject conditions are pinned in pbv1_reject.json and consumed by both PB parser tests and TPv1 PB-bind tests.

5. On-chain/off-chain parity notes

  • Off-chain strict parsing/commitments are implemented in @bch-stealth/zk-boundary.
  • Host-side parity checks are exercised in packages/pool-shards/tests/host_v1_eval.test.js.
  • Any mutation that changes PB bytes must either reject or alter PB commitments.