Confidential Transition Statement v1 (Minimum Prover Profile)¶
Status: frozen for TKT-P3-35
Goal: lock one minimum viable confidential transfer statement so prover, wallet, and covenant work can proceed against one deterministic boundary.
1. Boundaries and references¶
This document layers directly on top of the frozen artifacts below:
- spec/protocol-terminology.md (protocol glossary, receiver (A,B) model, wallet note tracking)
- packages/zk-boundary/public_inputs_v1.ts / packages/zk-boundary/proof_blob_v1.ts (PIv1/PBv1 strict codecs + hash policies)
- packages/pool-state/state_cell_v2.ts + packages/pool-state/test-vectors/state_cell_v2.json (SCv2 encodings)
- spec/scv2-transition-linkage-v1.md + packages/pool-state/test-vectors/state_transition_linkage_v1.json (state_in/state_out linkage contract)
- spec/proof-envelope-transcript-v1.md (canonical PBv1 envelope + transcript commitment freeze)
- spec/direct-path-minimum-private-relation-v1.md (normative host/prover split + minimum irreducible private relation freeze for direct-path rescue)
- packages/zk-notes/nullifier_set_v1.ts + packages/zk-notes/test-vectors/nullifier_set_v1.json (nullifier set semantics)
- spec/note-commitment-nullifier-formulas-v1.md + packages/zk-notes/test-vectors/commitment_nullifier_v1.json (canonical commitment/nullifier formulas)
- docs/threat-model.md and docs/audit-pack/adversarial-vectors.md (adversarial controls + budgets)
- spec/budgets-phase3.md + packages/cli/src/zk/budget_tables_v2.ts (budget ceilings for host/kernel/proof blob)
- fixtures/phase3/confidential_transfer_v2_no_receiver_marker.json (committed deterministic transition fixture, canonical v2)
No new protocol rules are introduced here; this file freezes a minimum statement profile from already committed behavior.
2. Confidential transition v1 statement¶
2.0 Fixed cardinality profile (minimum viable v1)¶
The v1 prover statement is frozen to one profile only:
- exactly 1 spent note
- exactly 1 receiver note
- exactly 1 sender change note
- exactly 1 nullifier insertion
- exactly 1 note-root transition (
noteRoot_in -> noteRoot_out) - exactly 1 state-cell transition (
SCv2_in -> SCv2_out) - exactly 1
PIv1transcript - exactly 1
PBv1envelope
This profile is the authoritative boundary for first prover integration. Multi-input/multi-recipient generalizations are out of scope for this version.
2.1 Public input schema (frozen v1)¶
| Name | Source | Notes |
|---|---|---|
shardId32 |
PIv1 / SCv2 |
Identifies the protocol state cell (Phase 2 “shard”). |
stateIn32 / stateOut32 |
SCv2 encoding, hashed via hashStateCellV2 |
Each hash is the commitment to (noteRoot32, nullRoot32, meta) before/after transition. |
outputFingerprint32 |
PIv1 field, computed by OFm2/v2 in this active profile |
Binds the confidential transition to the actual transaction outputs (host verification reference: packages/pool-shards/tests/host_v1_eval.test.js). |
batchDigest32 |
PIv1 optional field |
MUST be absent in this minimum profile (BATCH_PRESENT=0). |
feeDigest32 |
PIv1 optional field |
MAY be absent (FEE_PRESENT=0) or present per PIv1 codec semantics. |
2.2 Public proof envelope schema (frozen v1)¶
PBv1 must satisfy:
- exactly one
PROOFsection (required) - optional
ENCRYPTED_PAYLOADsection - optional
HINTSsection - no unknown stable section IDs
- deterministic section digest commitments validated by codec
- no mock-backend-only envelope fields; PBv1 is backend-neutral at the schema level
Host recomputes hashPBv1 and sectionsRootPBv1, including chunk binding for large payload sections.
2.3 Witness schema (backend-private, frozen v1)¶
Backend witness construction for this profile includes:
- one spent-note witness:
- spent note leaf preimage
- spent note Merkle witness (
noteRoot_in) - one receiver-note construction witness
- one sender-change-note construction witness
- one nullifier witness:
- nullifier preimage inputs
- duplicate-exclusion semantics per nullifier-set policy
- transition linkage witness proving:
noteRoot_outincludes exactly{receiver, change}post-state updates from this profilenullRoot_outreflects exactly one inserted nullifier- transcript binding witness linking statement outputs to:
PIv1bytesPBv1committed sections- output fingerprint digest
None of the private witness values are exposed on-chain; only committed public digests and codec-visible fields are emitted. Private witness values are not part of final verifier inputs: final verifier acceptance is defined only over public inputs plus proof artifact fields.
2.3.1 Provisional backend-1 witness bridge (non-normative)¶
The current backend-1 witness-dependent verification flow is temporary scaffolding for off-chain constraint replay only.
- It MUST NOT define final verifier acceptance semantics.
- It MUST NOT add, rename, or smuggle witness-derived verifier inputs into the final verifier ABI.
- Final verifier acceptance remains public-input-only and proof-artifact-only.
2.3.2 Direct-path irreducible relation freeze (normative)¶
For direct-path confidential transfer feasibility work, the normative minimum private relation is frozen in:
spec/direct-path-minimum-private-relation-v1.md
That document is authoritative for host-side forever checks vs prover-side forever relation facts and must be used as the acceptance boundary for direct-path rescue tickets.
2.4 Transcript binding¶
- The host transcript (
packages/pool-shards/src/cashassembly/host_v1.casm) recomputes: PIv1hash viahashPIv1(strict magic, flags).PBv1hash plus section roots, enforcing order (proof,payload,hints), chunk commitments, and no sorting.outputFingerprint32over actual outputs (ensures binding).- Combined, these define the canonical v1 statement digest boundary that the backend must satisfy.
2.5 Proved vs wallet-checked vs covenant-checked matrix¶
Host/prover responsibility freeze for direct-path rescue is normative in spec/direct-path-minimum-private-relation-v1.md.
The matrix below remains a broader operational view including wallet checks.
| Invariant | Prover statement | Wallet validation | Covenant/host validation |
|---|---|---|---|
stateIn32/stateOut32 commitment coherence |
MUST prove relation to witness roots | MUST recompute and compare to transition context | MUST enforce PI/host equality checks |
| Spent note membership in pre-state root | MUST prove | MAY verify via local witness recomputation when available | Not directly checked (digest-level only) |
| Receiver + change note construction determinism | MUST prove against statement policy | MUST validate recovered note commitment(s) before persistence | Not directly checked |
| Nullifier uniqueness/update rule | MUST prove one insertion for this profile | MUST track nullifier spend status and reject duplicates locally | Host enforces committed root/output binding only |
PIv1 canonical encoding/hash |
Witness links to emitted PI | SHOULD decode and sanity-check | MUST recompute hashPIv1/field relations |
PBv1 canonical encoding/hash |
Witness links to emitted PB | SHOULD decode and sanity-check | MUST recompute hashPBv1 and section commitments |
Output binding (outputFingerprint32) |
Witness links transition to committed fingerprint | MUST verify before accepting inbound note state | MUST recompute from real transaction outputs |
| Candidate feed metadata correctness | Out of scope | MUST treat as advisory only | Out of scope |
2.6 Active output-binding policy (normative)¶
The active fixed confidential-transfer statement in this document is:
- confidential amount mode v1
- tokenized continuation/state-cell invariants (
CARRIERv1) OFm2/v2output binding
OFm2/v1 is not part of active confidential-transfer acceptance semantics in this statement.
Legacy OFm2/v1 compatibility is documented as non-normative in Section 5.
2.7 Confidential amount mode v1 freeze (pre-prover blocker)¶
Confidential amount mode v1 is now frozen as:
- Confidential transition economic amount lives in committed note/state data, not visible BCH output satoshis.
- Continuation state-cell outputs use fixed public carrier sats only.
- Public BCH output satoshis in confidential transitions are carrier/fee transport values, not confidential transfer values.
- Wallet/backend acceptance MUST reject public-value confidential shells that depend on visible BCH output sats to represent transferred confidential amount.
Acceptance boundary:
- Confidential transfer acceptance in this active statement requires tokenized continuation invariants and
OFm2/v2. - Tokenless
OFm2/v1compatibility must not be used to accept confidential transfers.
2.8 Tokenized state-cell carrier invariants v1 (CARRIERv1)¶
For confidential transitions under confidential amount mode, carrier invariants are frozen as:
- Continuation outputs are tokenized protocol state cells.
- Continuation output token category+capability equals the spent state-cell input token category+capability.
- Continuation output token commitment equals
stateOut32. - Continuation output index is deterministic and profile-bound.
Current profile freeze for single-continuation transitions:
- default deterministic index rule: fixed continuation output index
0 - this is a profile rule, not an implicit forever rule; any change requires a versioned successor profile
Reference invariant template (prototype retained):
packages/pool-hash-fold/src/cashassembly/state_cell_template_v1.casm
Carrier invariant vectors:
packages/pool-shards/test-vectors/state_cell_carrier_invariants_v1.json
2.9 Frozen output_fingerprint_m2 successor policy (OFm2/v2)¶
OFm2/v2 is the confidential-transition output-binding policy successor.
Algorithm:
n = tx.outputCount, MUST satisfy1 <= n <= 9.acc0 = HASH256("OFv2" || 0x00 || u8(n)).- For each output in consensus order
i = 0..n-1: valueVm = VM minimal positive encoding of output value.script2 = u16le(len(lockingBytecode)) || lockingBytecode.tokenCategory2 = u16le(len(tokenCategoryRaw)) || tokenCategoryRaw.tokenCommitment2 = u16le(len(tokenCommitmentRaw)) || tokenCommitmentRaw.tokenAmount2 = u16le(len(tokenAmountRaw)) || tokenAmountRaw.h_i = HASH256(valueVm || script2 || tokenCategory2 || tokenCommitment2 || tokenAmount2).acc_{i+1} = HASH256(acc_i || h_i).- Final digest is
acc_n.
Encoding freeze (to prevent TS/CASM drift):
tokenCategoryRawis the raw VM introspection byte string (OP_OUTPUTTOKENCATEGORY) with no re-interpretation.- For NFT state-cell continuations this is expected to be
category32 || capabilityByte. tokenCommitmentRawis the raw VM introspection byte string (OP_OUTPUTTOKENCOMMITMENT).tokenAmountRawis the raw VM introspection byte string (OP_OUTPUTTOKENAMOUNT).- No-token handling: if output has no token data, all token raw fields are empty (
len=0). - Zero-amount handling: token amount field, when present in TS/reference representations, MUST be
>=1; zero amount is invalid.
Scope/versioning:
- Confidential transition acceptance under confidential amount mode MUST use
OFm2/v2(or a later explicit successor), notOFm2/v1. OFm2/v1remains legacy compatibility only and is non-normative for final confidential-transfer acceptance.
Reference implementation: packages/zk-boundary/src/output_fingerprint_m2_v2.ts
Host parity path: packages/pool-shards/src/cashassembly/host_v1.casm
Vectors: packages/zk-boundary/test-vectors/output_fingerprint_m2_v2.json
3. Deterministic canonical fixture (end-to-end)¶
Canonical fixture for this statement profile:
fixtures/phase3/confidential_transfer_v2_no_receiver_marker.json(active canonical tokenized confidential path)fixtures/phase3/confidential_transfer_real_proof_corpus_v1.json(active adversarial corpus for this path)fixtures/phase3/confidential_amount_mode_v1.json(amount-mode policy fixture + reject shells)
Fixture references:
- transition scenario source:
fixtures/phase3/confidential_transfer_v2_no_receiver_marker.json - public transcript bytes:
transport.piHex,transport.pbHex - deterministic state transition values:
state.before/state.after - deterministic nullifier reference:
source.nullifier32Hex
The active canonical fixture for this statement is the tokenized, no-public-receiver-marker confidential transition path (confidential_transfer_v2_no_receiver_marker).
It is normative for minimum v1 confidential-transfer acceptance and shared across backend, wallet, and covenant tracks.
4. Backend bakeoff plan¶
4.1 Objective¶
Demonstrate that a backend can produce PBv1/PIv1 tuples satisfying the frozen boundary while respecting the host/kernel budget ceilings.
The selected backend must preserve final verifier semantics: public inputs + proof artifact only (no verifier-side witness bytes).
4.2 Evaluation criteria¶
| Criterion | Target |
|---|---|
| Proof size (PB bytes) | <= recorded ceilings in spec/budgets-phase3.md (e.g., 1000 bytes for confidential wallet transport fixture rows). |
| Encrypted payload chunks | same chunk binding logic as packages/zk-boundary/src/transcript_policy_v1.ts. |
PIv1 hash recomputation |
host must recompute hashPIv1 and compare to payload; failure = rejection (per packages/pool-shards/tests/host_v1_eval.test.js). |
| Final verifier contract preservation | backend integration MUST preserve public-input-only + proof-artifact-only verifier acceptance; witness-dependent backend-1 replay remains non-normative scaffolding only. |
| Budget instrumentation | backend metrics must feed into packages/cli/src/zk/budget_tables_v2.ts (hash operations, tx bytes, unlock bytes). |
| Transcript adherence | transcript vectors (packages/zk-boundary/test-vectors/tpv1_vectors.json) must remain valid; mismatches get flagged via packages/zk-boundary/src/tests/transcript_policy_v1.test.ts. |
4.3 Bakeoff steps¶
- Reuse
packages/zk-sim/tests/toy_shard_sim_v1.test.js+fixtures/phase3/toy_shard/toy_shard_v1.jsonas the canonical proof-only path. - Extend to the wallet transport scenario using
fixtures/phase3/confidential_transfer_v2_no_receiver_marker.json+packages/e2e-chipnet/tests/phase3_e2e_chipnet.test.js. - Measure host/kernel budgets from
spec/budgets-phase3.mdand verify backend outputs stay within those ceilings when replacing the mock backend with the real prover. - Track the
proofBlobsections matching the frozen tokenized confidential statement boundary to ensure prover outputs only frozen fields and does not depend on legacy tokenless acceptance semantics.
4.4 Risk register¶
| Risk | Mitigation | Status |
|---|---|---|
| Prover tries to expose note/root data | Statement boundary forbids exposing note commitments/nullifier data outside hashed fields; backend must only emit hashPBv1/hashPIv1 via transcript_policy_v1. |
Controlled |
| Payload chunks grow beyond budget | Use spec/budgets-phase3.md ceilings; record chunk counts in manifest. |
Guarded |
| Host/backend drift on transcript | Compare against packages/zk-boundary/test-vectors/tpv1_vectors.json during bakeoff; treat mismatches as show-stoppers. |
Active |
New proofs leak (A,B) semantics |
Glossary clarifies (A,B) is wallet identity; proofs only consume hashed commitments. |
Documented |
| Quantum-proof path not defined | Reserve lattice-ready candidate paths in follow-up ticket (per user request) and treat them as future work. | Planned |
5. Legacy compatibility note (non-normative)¶
OFm2/v1 tokenless policy is retained only for legacy compatibility/profile testing and historical references.
- It is non-normative for active confidential-transfer acceptance in this document.
- It must not override tokenized continuation +
OFm2/v2rules for the fixed confidential-transfer statement. - Reference implementation/vectors remain available at:
packages/zk-boundary/src/output_fingerprint_m2_v1.tspackages/zk-boundary/test-vectors/output_fingerprint_m2_v1.json
6. Follow-ups¶
- Align candidate prover implementations with this boundary (reference
spec/confidential-transition-boundary-v1.md). - Document lattice/quantum-ready strategies in a follow-up ticket once the boundary is locked.
- Ensure any future “public candidate feed” includes the canonical glossary references so wallets adopt the same terminology.