# ZKas — technical capability reference

Reference material for generating protocol and product ideas. Claims checked against source
(`rusty-kaspa` fork, `shielded-core`, `zkas-walletd`, Kaspa KIP-16/17/20/21), September 2026.
Items that are estimated or unverified are marked.

---

## 1. System summary

- Fork of rusty-kaspa. GHOSTDAG BlockDAG, **1 block/second**, ~1s confirmation, **kHeavyHash** PoW.
- **Merged-mined with Kaspa** (aux-PoW). A Kaspa miner produces ZKas blocks at ~0 marginal cost.
- **Mandatory privacy.** No transparent output type on mainnet. Every value-carrying output is an
  Orchard (Halo2) shielded note, including the coinbase.
- **Single asset.** A note holds one `NoteValue: u64`. No asset id field.
- **No virtual machine.** No contracts, no shared mutable state, no scripts on notes.
- Emission: 1-BPS schedule from block 0, smooth halving, 3-month half-life,
  `deflationary_phase_daa_score = 0`. Per-second emission is invariant to BPS (subsidy scales ÷BPS).
- Dev fee: **5%** of subsidy (`ZKAS_DEV_FEE_PERMILLE = 50`), minted as a shielded note, accrued and
  paid every **1000 blocks**.

## 2. Consensus rules that constrain design

**Value integrity, per bundle.** Each action carries a value commitment `cv_net`. The binding
signature verifies under `bvk = Σ cv_net − commit(value_balance, 0)`, valid only if the bundle's true
net equals its declared **public** `value_balance`. Only the coinbase may mint.

**Turnstile ledger.** `pool = cumulative_coinbase − cumulative_fees − burns`, may never go negative
(`PoolUnderflow`), checked every block, snapshotted per chain block. It bounds what can *leave* the
pool; it does not measure what is inside.

**State root in the coinbase.** Each block's coinbase commits the **parent's** shielded state root =
tree anchor + nullifier accumulator + turnstile totals + burn root. PoW-anchored; divergence becomes
block rejection, not silent drift. There is no circularity (a block commits its parent, never itself).

**Append order is consensus order.** The note-commitment tree is append-only and position-dependent.
Order: coinbase mint first, then accepted actions in consensus applied order. Any other order yields
a different root from identical data. Consequence: replaying every `cmx` from genesis must reproduce
the exact frontier a node holds, so history backfill is cryptographically checkable rather than
trusted.

**Anchors.** A spend proves a Merkle path to a past tree root. Accepted only if that root is known,
its producing block is a selected-chain ancestor, and it lies in the window
`shielded_anchor_depth = 600 × BPS` (~10 min, minimum) to `max_shielded_anchor_age = pruning_depth/4`
(~7.5 h, maximum). Several blocks can produce the same root; all producers are retained and any
matured canonical one suffices.

**Drop, do not disqualify.** A tx whose anchor is stale or whose nullifier is claimed is dropped from
the state transition rather than invalidating the block. The coinbase must be built from *applied*
fees only; re-minting a dropped spend's fee creates unbacked supply.

**Nullifier set is a MuHash accumulator.** Double-spends are prevented by set lookup. There is **no
non-membership proof**.

## 3. Transaction and wire budget

| Quantity | Value |
|---|---|
| Max actions per bundle | 512 |
| Per-action wire size | 884 B (nullifier 32, rk 32, cmx 32, cv_net 32, epk 32, enc_ciphertext 580, out_ciphertext 80, spend_auth_sig 64) |
| Bundle header | 117 B (flags 1, value_balance 8, anchor 32, binding_sig 4+64, action count 4, proof len prefix 4) |
| Proof size | `2720 + 2272·n` bytes |
| Total bundle | `117 + 884·n + proof(n)` |
| `enc_ciphertext` (580 B) | version, diversifier 11, value 8, rseed 32, **memo 512**, tag 16 — readable by the recipient's IVK |
| `out_ciphertext` (80 B) | recoverable **only** if an OVK was attached at send |
| Practical spend cap | **38 spends/tx**. Kaspa mempool standardness caps per-dimension mass at 100 000 and transient mass = tx bytes × 4, so a standard shielded tx must stay under **~25 000 bytes** |
| Shielded tx storage mass | zero |
| Fee model | dynamic, byte-proportional. A flat fee below the node minimum is rejected by relay |

Design implication: a shielded tx is a fixed ~25 KB budget. Anything needing many inputs must either
batch across transactions or consolidate notes first (note-heavy wallets require auto-consolidation).

## 4. Keys, addresses, disclosure

- Address: bech32, HRP `zkas:` (mainnet) / `zkastest:` (testnet), version byte
  `ShieldedOrchard = 9`, payload = diversifier(11) ‖ pk_d(32) = **43 raw bytes**.
- **One seed → one FVK → one IVK.** There are **no ZIP-32 sub-accounts**.
- **Diversified addresses:** one FVK yields unlimited mutually unlinkable addresses (`address_at(j)`),
  all funding the same wallet. This is the per-payer / per-invoice mechanism.
- **IVK** decrypts all *incoming* notes of that seed. Disclosing it reveals every inbound flow of that
  seed, permanently. Scoping = a separate seed per counterparty.
- **Outgoing proof** requires capture at send time: with `recoverable = true` the wallet keeps an
  `ActionDisclosure` (spend_value, out_value, out_recipient[43], out_rseed[32], rcv[32]) which lets a
  third party recompute `cmx` and `cv_net` and match them against the on-chain action — a keyless
  payment proof. **Default sends are unprovable even to the sender**: `rseed` is one-time, memory-only,
  never persisted, and the out_ciphertext is sealed under a random key.
- **Watch-only** wallets work from the FVK alone (mobile keeps the seed on device).
- **Message signing** proves address control without spending, and reveals the FVK.

## 5. Shipped primitives

Shielded send/receive · 512-byte encrypted memo per action · unlimited diversified addresses ·
viewing-key disclosure · send-time `ActionDisclosure` (keyless payment proof) · message signing ·
NUMS burn address (hash-derived, recomputable, unspendable; **freezes** value, does not reduce supply)
· atomic multi-output bundles (≤512 actions, all-or-nothing) · absolute tx-level `lock_time` bound
into the sighash · sign-then-prove split (sighash excludes the proof and the spend-auth signature, so
pre-signed conditional payouts are architecturally possible) · shielded coinbase.

## 6. Node, sync and wallet capabilities

- `GetShieldedBlocks` — canonical chain-ordered shielded block stream (clients must not order it
  themselves; DAG-order ingestion corrupts wallet trees).
- `GetShieldedTreeState` — frontier at a point; supports `below_daa_score`, a **DAA locator** that
  places an arbitrary wallet birthday anywhere in history **in one call**.
- **Pruned nodes can serve shielded history** (`RequestShieldedHistoryFlow` v10); there is no
  `--archival` gate on serving. `--archival` retains but does not itself fetch; the
  `history_complete` flag is set by a p2p backfill → verify pass, not by an offline import.
- **Compact scan-effects archive:** ~148 bytes per action, used for below-pruning-point history.
- **Twin-checkpoint adoption:** a second device with the same seed clones an existing scan in ~32 ms.
- Wallet fast-sync from a frontier + persisted witnesses; shared chain tree across wallets.
- No public mempool (nothing to front-run; also nothing to observe pre-confirmation).

## 7. Live infrastructure

Mainnet (launched July 2026) · block explorer · hosted walletd (multi-wallet, token-scoped) ·
mobile + desktop + web wallets · 1-click Tor endpoint · merchant payment gateway (per-invoice
diversified addresses) · custodial OTC desk (ZKAS/KAS; USDT/USDC on Arbitrum and Base deployed with
the USD send path **gated**) · 1% referral programme · an AI service accepting ZKAS · custodial mining
pool + solo/merged-mining kit · **testnet-10**, solo-mineable and feature-matched to mainnet, with an
easy-PoW genesis and **no public seeder** (standalone only) · L2 rollup testbed (public repo
`firecash/vprogs-zkas`).

Ports: mainnet RPC 16810, p2p dial 16111 / listen 16811. Testnet-10 RPC 16820, p2p 16821.
DNS seeder `seed.zkas.info` (mainnet only).

## 8. Consensus parameters

| Parameter | Value |
|---|---|
| `shielded_anchor_depth` | `600 × BPS` (~10 min) |
| `max_shielded_anchor_age` | `pruning_depth / 4` (~7.5 h) |
| `finality_depth` | `BPS × FINALITY_DURATION` |
| `pruning_depth` | derived (finality + 2×merge depth + mergeset/ghostdag terms) |
| `MAX_ACTIONS_PER_BUNDLE` | 512 |
| Block mass limits | prior shared 500 000; new transient 1 000 000 |
| `merged_mining_activation` | always (from genesis) |
| `toccata_activation` (our fork) | always |
| `shielded_anchor_multi_activation` | DAA 757 000 |
| `dev_fee_accrual_activation` | DAA 757 000 |
| `shielded_coinbase_seed_activation` | never (Upgrade-2, not deployed) |
| `dev_fee_permille` / payout interval | 50 (5%) / 1000 blocks |
| Low-difficulty bootstrap | disabled (0/0) — pure DAA from genesis |

## 9. Not built (exact names)

- **Adaptor signatures** — 0 code. Re-randomizable Schnorr on RedPallas exists, so buildable. Gates
  atomic swaps, DLCs, delivery-vs-payment, trustless escrow.
- **Bonded oracle** — 0 code. Scheme is sound (one nonce per event; a second attestation leaks the key
  and forfeits a bond). Gates every conditional product.
- **FROST / threshold signing** — FROST + DKG for RedPallas ship in the `zakura-reddsa` dependency but
  are **unwired**; the shielded spend path is single-signer. Gates multisig, org custody, trustless
  group funds.
- **Per-note relative timelock** — absent. Requires a new note field, changed note commitment, a new
  Halo2 public input and regenerated proving/verifying keys: major circuit + consensus fork. (Absolute
  tx-level `lock_time` exists and covers coarse timeouts.)
- **Cross-curve DLEQ** (Pallas↔secp256k1, Pallas↔ed25519) — 0 code. Gates trustless BTC/XMR swaps.
- **Supply-reducing burn** — machinery built, gated. Small consensus change.
- **KAS↔ZKAS peg** — built and gated (`BRIDGE_ENABLED=false`); blocked externally because Kaspa
  cannot mint or track a pegged token at the settlement layer.
- **2-of-2 co-signed notes** — not wired; would be the minimum ZKas-side escrow primitive (key
  aggregation over existing re-randomizable Schnorr).
- **VDF** — not in tree; required for a bias-resistant randomness beacon.

## 10. Not possible on the base chain

- AMM, order book, continuous perpetuals, pooled lending — require shared mutable state / a VM.
- Native stablecoin or any second asset — single `u64` value, no asset id; multi-asset (ZSA) is a
  circuit + consensus fork.
- On-chain recurring pull payments — no VM; recurrence must be client-side re-payment of push invoices.
- Uniqueness / anti-double-pledge registries — MuHash accumulator gives no non-membership proof;
  would require replacing it with an SMT.
- Markets settled on hashrate or difficulty — only the shielded **state root** is committed in the
  coinbase, not difficulty or hashrate.
- A Kaspa covenant controlling a ZKas note — see §11.

## 11. Kaspa: merged mining and covenants

**Merged mining gives shared hashrate, not a shared VM.** ZKas inherits its participating share of
Kaspa PoW security; it gains no execution environment.

**The commitment link.** Every merged ZKas block hash is written into a Kaspa block's coinbase (tag
`ZKMM<hash>`, or the `/zkas/…` format used by RK-Stratum). Kaspa's **KIP-21** commits every mergeset
block's raw coinbase payload, plus that block's hash and blue_work, under `SeqCommit(B)`:
`leaf = H(block_hash ‖ blue_work ‖ H(coinbase_payload))`. A covenant reads `SeqCommit(B)` via
`OpChainblockSeqCommit` and opens the Merkle path to the tag.

**Kaspa mainnet capabilities (Toccata, active since DAA 474 165 565):**

| Feature | Detail |
|---|---|
| `OpZkPrecompile` (0xa6) | Groth16/BN254 (tag 0x20) and risc0 succinct STARK, Poseidon2 only (0x21) |
| Proof cost | Groth16 **140 000 grams**; risc0 **250 000 grams**. Block compute limit **500 000 grams** ⇒ **~3 Groth16 verifies per Kaspa block** |
| `OpChainblockSeqCommit` (0xd4) | returns a chain block's sequencing commitment. **Selected chain only**, and within `finality_depth` ≈ **12 hours** |
| KIP-20 (0xcb–0xd6) | covenant IDs / lineage — a covenant UTXO cannot be forged, only continued |
| KIP-17 (0xb2–0xc9) | tx introspection: input/output amounts, spk, lock_time, payload substr, DAA score, is_coinbase |
| Hashing | `OpBlake3` (0xd9), `OpBlake3WithKey` (0xda) — KIP-21 hashers are BLAKE3 keyed with zero-padded domain tags, so the opening is computable in script |
| Script limits | element 1 000 000 B, ops 1 000 000, **stack 244**, signature script 250 000 B |
| Pins | risc0 3.0.4 / recursion 4.0.4 / ark 0.6.0 — proofs from other versions will not verify |
| Not available | **no opcode reads a coinbase directly**; **no Halo2 verification** (Orchard proofs must be wrapped into Groth16 or risc0) |

**Three limits that invalidate naive designs:**

1. **Asymmetry.** A Kaspa covenant can *verify* ZKas state but can **never gate a ZKas note** — a note
   has no script and its only spend authority is a single key. Only the KAS leg can be conditional.
   A conditional ZKas-side release requires ZKas-side crypto (2-of-2 co-signing minimum, adaptor
   signatures beyond) or a bonded/custodial operator.
2. **Coverage.** Only ZKas blocks whose merged share *also* cleared Kaspa's own difficulty appear in a
   Kaspa block (a July sample: ~8% of Kaspa blocks carried a tag). Aux-PoW accepts Kaspa headers at
   ZKas difficulty, so "every ZKas block is committed into Kaspa" is false. Also, a chain block's own
   coinbase and its selected parent are **not** in its own leaves — anchor on non-selected-parent
   mergeset members.
3. **What the tag proves.** Publication with PoW weight behind it — **not** that the referenced ZKas
   block is valid or canonical. Any Kaspa miner can write arbitrary bytes there. Validity must come
   from the zk proof; Kaspa cannot decide ZKas fork choice.

**Kaspa L1 covenants are UTXO covenants plus a zk precompile, not a shared-state VM.** Shared-state
DeFi on the Kaspa side means a based rollup (kaspanet vprogs, or Igra EVM) and therefore a wrapped
ZKas representation, with privacy only at entry and exit.

Two trust classes worth naming in any cross-chain proposal:
- **Class S** — anchored to Kaspa consensus through the merged-mining commitment (trust-minimised, up
  to ZKas's own PoW and the 12-hour window).
- **Class P** — proof verified against an anchor supplied by a bonded attester (trust-reduced,
  slashable on equivocation). Required wherever Class S cannot reach (e.g. a USDC leg on Arbitrum).

## 12. L2 / rollup status

`vprogs-ref` (public: `firecash/vprogs-zkas`) — L1 = the Kaspa fork, L2 = a shielded rollup, with a
covenant, proofs and settlement. Simulation suite green including reorg scenarios. Real GPU proofs
verified in-script through `OpZkPrecompile`. Guest ELFs must **all** be rebuilt on any ABI journal
change. Current public test UI runs in `RISC0_DEV_MODE=1` (no real proving) and requires the `r0vm`
executor binary to run guests.

## 13. Measured performance

| Measurement | Value |
|---|---|
| Shielded spend proving (Halo2) | **~0.79 core-seconds per note spent** (≈ 0.8 s × notes). One proof already uses 3.13 of 4 cores — no idle CPU to parallelise into |
| Wallet scan split | ~80% public tree work, ~20% per-viewing-key trial decryption |
| Historic send bottleneck | ~93% of send time was the chain-length witness climb, not the proof |
| L2 real GPU run | `settlement_e2e` 4/4 in **256.94 s** (RTX 5070), incl. a real BN254 Groth16 batch proof at **24.8 s** producing a **222 668-byte** seal, verified in-script |
| L2 guest cost | ~26.2M cycles for 3 deposits + 3 transactions |
| Anchor windows | spendable after ~10 min; anchor unusable after ~7.5 h |
| Spend capacity | ~38 spends per transaction |

## 14. Failure modes already encountered

Useful as negative examples; these are fixed, and re-proposing the broken pattern is a waste.

- **F-01 dropped-spend fee inflation** — a dropped spend's fee was re-minted in the coinbase, creating
  unbacked supply. The coinbase must use *applied* fees only.
- **F-02 sibling coinbase collision** — parallel sibling blocks share parent, mergeset and miner, and
  the coinbase commits the parent's root, so the original seed (`txid ‖ index`) made siblings mint
  byte-identical notes and identical tree roots. Fixed by mixing the block hash into the seed
  (fork-gated).
- **F-04 fail-open anchor source** — when a source block's GHOSTDAG data was pruned the check failed
  open, an inflation vector. Now fail-closed, with peer-attested blue scores for in-window sources
  below the pruning point.
- **DAG-order wallet ingestion** — clients ordering blocks themselves corrupted wallet trees; fixed by
  serving a canonical chain-ordered stream.
- **Reorg nullifier visibility** — RocksDB staged deletes are invisible to reads until written, so the
  down-walk reverts must be committed before the up-walk re-applies.
- **Stale anchor drops** — a spend anchored deeper than `max_shielded_anchor_age` is correctly dropped;
  funds are not lost (nullifiers are not recorded, fee not collected).

## 15. Known weaknesses

- **Counterfeiting inside the pool would be invisible.** The turnstile bounds what can leave (never
  more than was issued) but never measures what is inside. With no live peg there is effectively no
  exit seam, so a circuit soundness bug could dilute holders indefinitely with no public number
  looking wrong. Detection would come from finding the bug, not from accounting.
- **The circuit delta is unaudited.** Upstream zcash-orchard is audited; the fork (zakura-orchard plus
  performance ports) is not independently audited, and the shielded GHOSTDAG core has had no external
  audit.
- **Anonymity is statistical, not per-transaction.** Membership is maximal (a spend proves inclusion in
  the whole tree, and privacy is mandatory so no one is flagged for using it). But coinbase note
  recipients and values are **public** — the recipient's address is in the coinbase script and
  `(rho, rseed)` are deterministic, so anyone can recompute those commitments. Those leaves add tree
  size without adding confusion, and at low concurrent volume timing correlation can still link
  activity. Custodial edges (desk, gateway) see both sides of a hop.
- **Disclosure is neither scoped nor revocable** (no ZIP-32; one seed → one IVK).
- **A default send is unprovable even to the sender** unless disclosure was captured at send time.
- **Block production is not private** — the merged-mining tag identifies which miner produced each
  ZKas block.
- **Not post-quantum.** Orchard/Halo2 is not PQ; encrypted notes are subject to
  harvest-now-decrypt-later.
- **Acquisition constraint.** Mining is currently the only ungated way to obtain ZKAS: no exchange
  listing, and the trustless peg is blocked. Most consumer and merchant designs are downstream of this.

## 16. Format for proposals

For each idea state:

1. Which §5 primitives it uses.
2. Which §9 items it requires (if any), and whether a bonded/custodial operator substitutes.
3. Whether it is trustless, trust-reduced (name the trusted party), or custodial.
4. What it assumes about Kaspa from §11, and whether it is Class S or Class P.
5. The transaction-size and proving cost under §3 and §13.
6. Whether it requires a consensus fork.
