Skip to main content

System Overview

The architectural design enforces that the value lives in encrypted notes, spending is authorized by deriving nullifiers, and balance is enforced by value commitments and a binding signature. Platus adapts that model to the EVM, to the BabyJubJub curve and Poseidon2 hash, and to an account-abstraction execution layer that lets shielded value drive arbitrary on-chain calls.


The core invariant: the chain learns almost nothing

A Platus transaction (Orchestrator.transact) exposes only:

  • a set of nullifiers being marked spent (opaque field elements),
  • a set of note commitments being inserted into the tree (opaque field elements),
  • per user, a net public value and a single asset — how many tokens cross the pool boundary, if any,
  • two ciphertext blobs per Action that only the recipient (or the sender) can open.

Nothing on-chain links a spent note to a created note, reveals a note's value, or reveals a recipient. A deposit, an internal transfer, and a withdrawal all present the same structural shape. The unlinkability rests on a ZK proof that the prover knows secret inputs satisfying the circuit — without revealing them.


The unit of work: the 2-in / 2-out Action

Every private transaction decomposes into one or more Actions. A single Action:

  • spends up to two input notes (in1, in2) under one owner key triple (ak, nk, rivk),
  • creates up to two output notes (out1, out2),
  • carries one net value commitment cv_net,
  • emits exactly one Poseidon2 digest as its public output.

Per-side enable_spend_* / enable_output_* flags let any side be a dummy, so the same fixed circuit shape serves the modal case ("1 input → payment + change") and consolidation ("2 inputs → 1 output + dummy") alike.

The only on-chain artifacts of an Action are the two nullifiers and the two commitments. Their relationship to the private (value, address, asset, randomness) is provably correct but perfectly hiding.


End-to-end flow

A private payment crosses every layer exactly once:

Three properties make this safe and cheap:

  • The user proves; the bundler aggregates. Private witnesses never leave the device. The bundler only ever sees opaque public inputs and finished proofs.
  • On-chain verification is constant-cost. The recursive aggregation collapses up to 18 Actions into a single finalize proof, verified in roughly constant gas regardless of batch size.
  • Spend authority is proved, not relayed. Spend-authorization is verified inside the circuit against the bundle's context, so the contract never runs a per-Action signature check.

For the full step-by-step, see Transaction Lifecycle.


Trust boundaries

PropertyEnforced byAn attacker who controls… cannot…
Value conservationbinding signature + on-chain reconstructionthe bundler · mint or burn value
Spend authorityin-circuit Schnorr over rkthe bundler · spend your notes
No double-spendpersistent + transient nullifier setanyone · replay a note
Recipient privacystealth addresses + hybrid encryptionthe indexer · learn who received
Correct executionthe immutable Orchestratoranyone · re-route settled funds

The bundler is a liveness dependency, not a safety dependency. If it is offline or hostile, a user can self-aggregate and submit transact themselves; the worst a bundler can do is refuse service or grief (e.g. tamper with a hint the proof does not bind — see the security model).