Documentation

Build with Provera

Provera is software you run yourself. There is no hosted service, account or API key. These docs describe what exists in the repository today and say so where something is not finished.

Quick start

You need x86-64 Linux (WSL2 on Windows), Docker, and a Solana wallet. Download the source (Apache-2.0; checksum in SHA256SUMS.txt), unpack it, and from that folder:

1. set up and build
bash scripts/setup-wsl.sh        # Rust, RISC Zero, Docker, Solana CLI, Anchor, Node
. scripts/wsl-env.sh
cargo build --release -p prover  # add --features cuda to prove on an NVIDIA GPU
bash scripts/check-image-id.sh   # your guest is the one this repository describes
npm install && npm run build:sdk # the provera command-line tool
2. prove on your own machine
prover prove  --manifest airdrop.json --out proof     # STARK
prover verify --receipt proof/receipt.bin             # check it
prover wrap   --receipt proof/receipt.bin --out proof # Groth16, for Solana
3. register on Solana from your own wallet
provera submit --report proof/report-groth16.json \
  --deployment deployment.json --keypair ~/.config/solana/id.json
4. anyone can check it
provera receipt <address> --deployment deployment.json
provera check airdrop.json --receipt <address> --deployment deployment.json

deployment.json names the on-chain programs you are using. There is no public deployment yet, so you create one: deploy the programs to a local validator or devnet with one script. To try everything without spending anything, run bash scripts/localnet-up.sh and then bash scripts/cli-localnet-test.sh, which performs all four steps with a fresh wallet.

Command-line tool

provera talks only to a Solana RPC node. Run it as node packages/cli/bin/provera.mjs, or link it with npm link -w @provera/cli.

CommandWhat it does
provera evaluate <dataset>Recomputes the commitment and totals and says whether the rule holds. No proof, no network.
provera submitSends a Groth16-wrapped proof to the registry from your wallet, then reads the receipt back. A proof that does not verify is rejected in simulation and costs nothing. Mainnet needs --yes-mainnet.
provera receipt <address>Reads a receipt from finalized chain state and refuses it unless the registry in your deployment file owns it. --image also pins the guest image.
provera check <dataset>Confirms that a receipt is about exactly that dataset. Exits non-zero if not.

Add --json for machine-readable output and --rpc <url> to use your own RPC provider.

Deploying the programs

On-chain verification needs three programs on the cluster: RISC Zero’s verifier router and Groth16 verifier, and the Provera registry. Whoever deploys them controls which guest images the registry accepts, so a project that does not want to rely on someone else’s deployment runs its own.

local validator (free, instant)
BUILD_ONLY=1 bash scripts/localnet-e2e.sh   # build the three programs
bash scripts/localnet-up.sh                 # start, initialize, write deployment.json
bash scripts/localnet-e2e.sh                # optional: 12 on-chain tests
devnet (public test network, free SOL)
bash scripts/devnet-keys.sh                 # keys in ~/provera-devnet, outside the repo
# fund the printed deployer address with about 6.5 devnet SOL (faucet.solana.com)
bash scripts/deploy-cluster.sh              # deploy, initialize, write deployment-devnet.json

The same script deploys to mainnet when run with CLUSTER=mainnet-beta PROVERA_MAINNET_APPROVED=yes. That spends real SOL (about 4.5 kept as rent) and publishes programs that have not been audited. No one has deployed Provera to devnet or mainnet yet.

RISC Zero’s source is used unchanged except for the two lines that set each program’s address. If RISC Zero publishes an official router on your cluster, prefer it over deploying your own copy.

SDK

@provera/sdk does the same things from TypeScript, in Node or the browser. It is not published to npm; use it from the workspace.

check a receipt against a dataset, no server
import { computeStatement, fetchReceipt, differencesFromReceipt } from "@provera/sdk";

const receipt = await fetchReceipt(address, {
  cluster: "devnet",
  registryProgramId: REGISTRY, // the registry you trust
  imageId: IMAGE_ID,           // the guest image you built
});
const statement = await computeStatement(dataset);
const differing = differencesFromReceipt(statement, receipt);
console.log(differing.length === 0 ? "match" : differing);
submit from a wallet
import { submitReceipt, buildSubmitReceiptTransaction } from "@provera/sdk/solana";

// Node, with a keypair:
const result = await submitReceipt(connection, payer, report, deployment);

// Or build the transaction and let a wallet adapter sign it:
const tx = await buildSubmitReceiptTransaction(report, deployment, wallet.publicKey);

@provera/sdk/solana needs @solana/web3.js. Everything else in the SDK has no dependencies.

Proof types

token_distribution (provera.td.v1)

A verified proof establishes that there is an allocation list such that:

  1. every wallet appears once and every amount is a non-zero integer in base units;
  2. its RFC 6962 SHA-256 Merkle root is the published datasetRoot;
  3. the amounts sum to totalAmount and the largest is maxAllocation;
  4. no amount exceeds maxWalletAllocationBps / 10,000 of the total.
airdrop.json
{
  "schema": "provera.token_distribution.manifest.v1",
  "mint": "<base58>",
  "category": "genesis | airdrop | balance_snapshot | other",
  "snapshotSlot": 0,
  "context": "<64 hex chars, optional>",
  "rules": { "maxWalletAllocationBps": 200 },
  "allocations": [{ "wallet": "<base58>", "amount": "1000000" }]
}

Rows may be in any order. Duplicate wallets and zero amounts are rejected, never merged or dropped, so the commitment always refers to exactly the data you supplied. Trading leaderboards and reward calculations are planned and not implemented.

Verification guide

There are three independent things to check, and none of them needs to trust Provera or the prover.

  1. The receipt exists and belongs to the right registry. Use the Verify page or provera receipt. Both read finalized state from an RPC node and check the owning program.
  2. The receipt is about your data. If you hold the dataset, provera check or the Verify page recomputes the commitment and compares every public value.
  3. The guest image is the program you think it is. Build the prover from source and run bash scripts/check-image-id.sh. The guest is compiled inside a pinned container, so every checkout of the same source produces the same image ID, recorded in circuits/token-distribution/IMAGE_ID. Compare it with the receipt’s.

Reproducibility was confirmed across two checkouts and a GPU build on one machine. It has not yet been confirmed on an unrelated machine.

What Solana verifies

Solana does not verify the STARK. The STARK is wrapped in a 256-byte Groth16 SNARK and the registry program asks the RISC Zero verifier router to check that wrapper, then writes a receipt account derived from the image ID and journal digest. A receipt exists only if verification succeeded in the same transaction. The full STARK receipt stays with whoever proved it and can be checked off-chain with prover verify.

Reading a receipt from another program

  1. Check the account is owned by the registry program and has the receipt discriminator.
  2. Re-derive its address from ["receipt", image_id, journal_digest].
  3. Compare image_id with an image ID you built yourself. Do not rely on the registry admin’s choice.
  4. Read the public inputs and apply your own rule, for example a required context.

Read the account rather than calling submit_receipt by CPI: verification already uses three of Solana’s four CPI levels.

Security assumptions

  • Not audited. No part of Provera has had an external security review.
  • Dataset completeness is not proven. A proof covers the list that was proved. It cannot show that no other wallets exist.
  • No chain authentication. Mint, category and slot are labels supplied by the prover. Signed manifests are designed and not implemented.
  • STARK soundness. RISC Zero states 96 to 99 bits of conjectured security for its STARK layers.
  • Trusted setup on-chain. The Groth16 wrapper depends on RISC Zero’s setup ceremony and is not post-quantum. The off-chain STARK is unaffected.
  • Privacy. When you run the prover yourself, the dataset never leaves your machine and only the commitment and public outputs are published. RISC Zero does not claim a formal zero-knowledge guarantee for its proofs, so treat this as “the data is not published”, not as a mathematical privacy proof.
  • Registry admin. Whoever deployed a registry chooses which guest images it accepts. They cannot create or alter receipts, but they can register a bad image, which is why consumers should pin the image ID.
  • Router owner. Whoever deployed the RISC Zero router can add verifiers to it and emergency-stop them.

Architecture

ComponentRoleState
td-coreStatement logic shared by the guest, the evaluator and the Solana programTested
proverRuns the guest in the RISC Zero zkVM: prove, verify, wrapWorking, tested
Registry programVerifies the Groth16 wrapper by CPI and stores receiptsTested on a local validator; no public deployment
provera CLISubmit from your wallet, read and check receiptsTested end to end on a local validator
SDKSame operations from TypeScript, plus statement recomputationTested
This websiteStatic files; reads receipts from Solana in the browserNo backend
API serverOptional queue and dashboard for a teamTested; you host it

Optional: your own API

A team that wants a job queue, API keys and a dashboard can run the bundled API next to its prover. Nothing else depends on it. Build this site with NEXT_PUBLIC_PROVERA_API_URL set to your API to enable the explorer and dashboard pages.

terminal
npm run build:eval
npm run create-key -- "team"                 # prints a pvk_… secret once
export PROVERA_PROVER_CMD='["/path/to/provera-target/release/prover"]'
npm run dev:api                              # http://127.0.0.1:8787
EndpointAuthPurpose
POST /v1/proofsKeyValidate, evaluate and queue a job. 422 if the statement is false. Accepts Idempotency-Key.
GET /v1/proofs, /v1/proofs/:id, /statusKey, or public once verifiedRecords, public inputs and status.
GET /v1/proofs/:id/artifactsOwner or publicReceipt and report; the manifest is owner-only.
POST /v1/proofs/:id/verifyOwner or publicRe-runs cryptographic verification of the stored receipt.
POST /v1/proofs/:id/solanaOwnerWraps and submits the proof using the server’s fee-payer wallet.
GET /v1/explorer/proofs, /v1/health, /v1/proof-typesNonePublic listings and status.

Note the trade-off: anyone who submits to an API hands their dataset to whoever runs it. Proving locally with the CLI avoids that.

Costs

The software is free and open source. Running it costs only your own hardware and Solana network fees, and it does not require the Provera token; the token’s contract address, once published, is shown at the bottom of this site. Measured on one machine (8-core CPU, one RTX 4070 SUPER) for a 1,000-wallet dataset:

StepMeasured
STARK proof16 to 26 seconds on the GPU, about 12 minutes on CPU only
Groth16 wrapabout 60 seconds on CPU
Registering a receipt128,555 compute units; 5,000 lamport fee plus about 0.0028 SOL rent
Deploying the three programsabout 4.5 SOL kept as rent, about 6 needed during upload

These are single runs, not benchmarks, and will differ on other hardware.

Troubleshooting

SymptomCause
risc0-zkvm fails to compile with trait errorsA lockfile was regenerated and RISC Zero sub-crates floated to newer releases. Restore the committed Cargo.lock or run bash scripts/pin-risc0.sh.
Solana programs fail to build with edition2024 errorsWrong Solana CLI. Use 2.3.9, as setup-wsl.sh installs.
prover wrap failsDocker is not running, or the machine is not x86-64.
provera submit fails with a custom program errorThe proof does not verify for that image, or the image is not registered in that deployment.
provera receipt says “wrong owner”The account belongs to a different registry than the one in your deployment file.
Verify page cannot reach mainnetThe public endpoint refuses browser requests. Use Custom RPC URL with your provider.
WSL will not install (0xc03a0014)Windows virtualization devices are disabled. See the repository README.