Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Confidential flows

The lifecycle:

Register → Deposit → Merge → ConfidentialTransfer → Withdraw

The validation pipeline

Every operation passes four ordered checks before state changes:

Operation
   → structural validation     (well-formed, amounts positive, ...)
   → authorization validation  (signature valid, signer == actor, permission)
   → state validation          (accounts/tokens exist, registered, active, owned)
   → proof requirement         (present + valid where required)
   → apply transition

Authorization (“is the actor allowed to do this?”) is deliberately separate from cryptographic validity (“is the proof/signature well-formed?”). An operation can be cryptographically valid yet unauthorized — the exact case safeguard-hooks and crucible-scenarios will exercise later.

Operation recording

Every operation produces exactly one structured transaction, whatever its outcome:

Success   -> applied and committed (version bumped, transition recorded)
Rejected  -> failed validation/authorization/state/balance/proof before any
             mutation (nothing changed, operation_rejected event)
Failed    -> started inside the transaction scope and rolled back
             (nothing changed, operation_rejected event)

Rejected and failed operations never bump the version and never move the state root — atomicity is absolute — but they leave a deterministic-ID record with the structured error embedded, so conformance suites can assert on the rejection record, not only on the returned error. The operation_rejected event carries the stable error code in its metadata (never amounts).

Flow semantics

Register

Per (account, token). Duplicates are duplicate_registration. On tokens that require registration, this is the gate for everything else.

Deposit

Public asset → confidential commitment. A fresh blinding nonce is drawn from the seeded RNG, so equal-value deposits stay distinguishable but reproducible. The account’s confidential head points at the new commitment.

Merge

Consolidate several active commitments owned by the merger into one whose value is their sum (overflow-checked). Each input is consumed (nullified). Merging is how an account consolidates before a large withdrawal.

Confidential transfer

The most important flow:

Sender → select all active commitments → validate coverage
      → prove through ProofProvider
      → consume inputs (nullify each)
      → create recipient commitment (amount) + change commitment (if any)
      → update heads → record

The simulator never proves itself: it builds a ProofRequest with public inputs (sender, recipient, token, amount, input IDs) separate from private inputs (values), hands it to the configured provider, and fails with InvalidProof if no provider is present or the provider rejects. The ProofReference recorded on the transaction is opaque to the simulator.

Withdraw

Confidential → public. Spends the account’s active commitments; when withdrawing less than the total, a change commitment keeps the remainder confidential. Requires no proof — this is the public side of the boundary.

Events (observable output)

OperationSuccess eventRejection event
Registeraccount_registeredoperation_rejected
Depositdeposit_completedoperation_rejected
Mergemerge_completedoperation_rejected
Transferconfidential_transfer_completedoperation_rejected
Withdrawwithdrawal_completedoperation_rejected

Events never carry amounts or commitment values. They report the actor, token, ledger, and a stable result — enough to describe what happened without leaking how much. A rejection event adds only the stable error code to its metadata. The privacy boundary is enforced by design and asserted by regression tests.