Pravelle — Operations & Proof System
Architecture, infrastructure and proof-system reference for operators, builders and reviewers. If you are here to use the app, start with the tutorial instead — it does not require any of this.
1. Architecture at a glance
Browser host (Mac or SSH-only VFS) Private compute BSC Testnet (97)
┌─────────────────────────────────┐ ┌──────────────────────┐ ┌────────────────────────┐
│ Vercel app + WASM │ │ dual-RTX-4090 Venus │ │ DarkPool.sol │
│ - master key stays in browser │ │ raw proof on 2 GPUs │ │ deposit/placeOrder/ │
│ - builds operation authorization│ │ CPU PLONK wrapper │ │ withdraw/settleMatch2 │
│ │ └──────────▲───────────┘ │ │
│ 127.0.0.1:8799 ─ private SSH ───┼────────────────┘ │ VenusDarkPoolVerifier │
│ browser indexer rebuilds trees │──────────────────────────────────▶│ 16 finalized VKs │
└─────────────────────────────────┘ └────────────────────────┘
│
└── matcher on 127.0.0.1:8798 (terms and public linkage; no spending keys)
- Master spending keys never leave the browser. Deposit needs no spending key. For active spend/order statements, WASM uses the key locally and emits an exact-operation signature, the spending public key, and a one-way nullifying key. The prover service rejects master-key fields.
- Loopback is still a security boundary. The nullifying key can link a user's spends if it is
exposed, so the prover stays on
127.0.0.1and is reached through a private SSH forward. A Vercel page cannot reach the VFS loopback from a different laptop browser. - The matcher holds no keys. It only pairs order terms and relays public linkage; both sides
prove their own half, and
settleMatch2fuses the two proofs atomically on-chain. - The verifier registry has 16 statement slots; a guest change requires a fresh VK/calibration
set and verifier deployment before that build is live
(
vksFinalized() == true), so no statement can be silently swapped.
Live deployment (BNB Smart Chain Testnet, chain 97; depth-20 pool, deployed 2026-08-25)
| Contract | Address |
|---|---|
| DarkPool | 0xBE945fADB5917FdD20f7cA46A76163b17B526E0f |
| VenusDarkPoolVerifier | 0xE518b138b5AC298993c470102F06b21d5419238d |
| Venus recursion verifier (ZiskVerifier) | 0xDC01F8DDd42aF2fD9581d127a9874C563c30279F |
| PoseidonT6Hasher | 0xD051CEDa4Aa2CE5340894976fC43f10493E28Fb6 |
| pTST fixture token | 0x6f8807E70c7DE2d218388Fb2D9418190A48481C9 |
| pUSD fixture token | 0x42003a22247B271caeA327944a62aA5Ce46989D7 |
Web app: pravelle.vercel.app — Guided mode (hold / trade / withdraw) and Proof workspace (raw order book + on-chain settlement).
The controlled BSC testnet split-proof settleMatch2 used 9,642,056 gas, below the
chain's 2²⁴ (16,777,216) transaction gas cap. DarkPool is Safe-controlled and remains paused
outside scheduled test windows.
2. Running the infrastructure
Guided browser builders keep the master spending key in the page and send only derived authority material plus a signature bound to the exact proof intent. The derived nullifying key remains sensitive metadata, so the configured prover is privacy-trusted. Hosted production uses a pinned, authenticated HTTPS prover; local development can use a loopback SSH forward.
Where 127.0.0.1 lives
Loopback always means the machine running the browser, not Vercel and not automatically the GPU server. The supported topologies are:
- Hosted production. The reviewed deployment pins the Matcher and Prover HTTPS origins. CORS is exact-origin, each tester has an independent prover token, and the raw backend ports remain bound to loopback behind TLS and the FRP transport.
- Local browser. Run the verified
Pravelle Tester
Tunnel v1.0.1 on your Mac/PC. It binds the matcher to
127.0.0.1:8798and the prover to127.0.0.1:8799. That computer and tunnel must remain online while a proof runs. - Durable VFS browser (legacy fallback). The VFS runs Chrome/noVNC and a restartable
SSH tunnel as system services. Its own
127.0.0.1:8799forwards privately to the GPU box. Access noVNC only through SSH, then open the Vercel app inside that remote Chrome. The Mac may disconnect after starting the proof; the VFS and GPU host must remain online. - Do not publish a raw backend port. Public access must terminate TLS at the reviewed reverse proxy and enforce the production CORS and per-tester token controls.
For a local browser, generate a new passphrase-protected tester key, send only its
.pub file to the operator, and keep the private key on your machine:
ssh-keygen -t ed25519 -a 64 -f ~/.ssh/pravelle-tester -C "pravelle-bsc-testnet"
chmod 600 ~/.ssh/pravelle-tester
# send ~/.ssh/pravelle-tester.pub only; never send ~/.ssh/pravelle-tester
The operator must privately return the restricted alias and the expected SHA256 host fingerprint. Collect the advertised key and compare the fingerprint through that independent channel before installing it. A mismatch is a stop condition:
RESTRICTED_HOSTNAME="operator-provided-real-hostname"
ssh-keyscan -t ed25519 "$RESTRICTED_HOSTNAME" > /tmp/pravelle-host-key
ssh-keygen -lf /tmp/pravelle-host-key
# only after an exact fingerprint match:
ssh-keygen -H -f /tmp/pravelle-host-key
grep -v '^#' /tmp/pravelle-host-key >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
Then download both v1.0.1 release assets and verify the archive before extraction:
curl -fLO https://github.com/cysic-labs/pravelle-tester-tunnel/releases/download/v1.0.1/pravelle-tester-tunnel-v1.0.1.tar.gz
curl -fLO https://github.com/cysic-labs/pravelle-tester-tunnel/releases/download/v1.0.1/SHA256SUMS
shasum -a 256 -c SHA256SUMS # Linux: sha256sum -c SHA256SUMS
tar -xzf pravelle-tester-tunnel-v1.0.1.tar.gz
cd pravelle-tester-tunnel-v1.0.1
shasum -a 256 -c SHA256SUMS && ./tests/test.sh
./bin/pravelle-tester-tunnel <restricted-ssh-host> ~/.ssh/pravelle-tester
The verified archive SHA-256 is
4346c66d82f156a7d366e7f8edee5593a823db2695d922ca1763817f7bbcdc86.
The client refuses unknown or changed SSH host keys. Stop immediately if the restricted account
opens a remote shell.
Before starting the tunnel, confirm that local ports 8798 and 8799 are
free with lsof -nP -iTCP:8798 -sTCP:LISTEN and the equivalent :8799
command on macOS, or ss -ltn '( sport = :8798 or sport = :8799 )' on Linux.
Do not kill an unfamiliar process.
Example operator access (replace <vfs-host> with the private host):
ssh -N -L 6080:127.0.0.1:6080 <vfs-host>
# then open http://127.0.0.1:6080/vnc.html
Service and browser checks
On the current VFS, both durable units should report active, and loopback health should
report ok plus proverReady:
systemctl is-active pravelle-prover-tunnel.service pravelle-vnc-browser.service
curl -fsS http://127.0.0.1:8799/health
If prover authentication is enabled, pair the browser once with the individual token assigned by
the operator. For hosted testing, the operator can send a private URL whose fragment is
#proverToken=<token>; the fragment is not sent in the HTTP request and the page removes it
after storing the token for that origin. Never put the token in source control or a screenshot.
Local operators may set the same value manually:
localStorage.setItem("pravelle:proverToken", prompt("Paste the test-window prover token"))
location.reload()
- Matcher.
cargo run -p cysic-matcher(binarymatcher) listens on127.0.0.1:8798. Endpoints:POST /orders,POST /settle/contribute,GET /settle/joint/<id>,POST /settle/proof,GET /settle/proofs/<id>,GET /book. It holds no spending keys. It does see order terms and public linkage. On-chain order verification turns on withCYSIC_MATCHER_RPC+CYSIC_DARKPOOL. - Indexer. The browser rebuilds the pool/book trees from
eth_getLogsand cross-checks the rebuilt roots against the on-chainpoolRoot/bookRoot. This needs an RPC that serves wideeth_getLogs; the release usesbsc-prebsc-dataseed.bnbchain.orgfor log replay, independent BSC testnet view-RPC fallbacks for root checks, and alocalStorage['pravelle:indexerRpc']override for self-hosting.
3. The proof system
- Venus zkVM produces the raw VADCOP proof on both RTX 4090 GPUs, then the deliberately
MPI-free CPU build wraps and verifies it as a 768-byte
uint256[24]PLONK proof against the Polygon-Hermez_26trusted-setup ceremony. - The
VenusDarkPoolVerifierstores a program VK per statement (setVK), is calibrated once with a real proof per statement (the calibrate self-check rejects a wrong VK/framing or an accept-all verifier), then finalized (vksFinalized) to lock the set. - VK reproducibility caveat: guests statically link all of
railgun-core, so any source change shifts every program VK. The deployed verifier is therefore pinned to a specific build; proofs must come from a matching prover build (or the verifier is re-calibrated to it).
The July 14 dual-4090 validation passed 16/16 statements, two complete repeatability runs (32/32 raw proofs), and 16/16 offline SDK wrapper replays/self-verifications. Independent deployed-verifier validation remains a promotion gate. These are proof-stage wall-clock measurements; queue, file, network, and browser time can add latency:
| Statement | Raw GPU average | CPU wrapper | Approx. live proof path |
|---|---|---|---|
deposit | 22.7s | 49.9s | 72.6s |
place | 35.7s | 47.5s | 83.2s |
half-match | 49.4s | 51.6s | 101.0s per side |
transfer | 67.7s | 53.6s | 121.3s |
batch | 164.6s | 53.1s | 217.7s |
Both cards cooperate on one raw proof. This validation establishes correctness and observed two-card latency; it does not isolate the speedup over one 4090. See the full 16-statement timing matrix.