Proofra/Docs/Protocol

Compute. Prove.
Verify.

Proofra turns heavy off-chain computation into a single folded proof, verified by an Anchor program on Solana mainnet. This is the protocol, end to end.

v0.1 · MAINNET UPDATED JUN 2026 ~6 MIN READ

#Overview

Applications submit computational workloads to the Proofra network. The network executes the workload off-chain inside the SP1 v3 zkVM, generates a cryptographic proof of correctness, folds the sub-proofs into one SNARK, and returns a verifiable result that any Solana program can check on-chain.

The guarantee is simple: a program never has to trust that a computation ran correctly. It verifies the proof, and only then acts — verified compute, with no trusted gap between checked and acted on.

KEY IDEA

The verifier's cost is constant. Whether you fold ten sub-proofs or ten thousand, the Anchor program checks one folded proof in under 200K compute units.

#Architecture

Five layers move a job from input to a permanent on-chain record. The folding adapter is identical across every circuit, so the same path works whether you prove a median or an ML inference.

  1. 01

    Submission

    Applications POST a circuit id, an input blob and a callback to the FastAPI service. The job is queued to an SP1 host pool.

    INPUT
  2. 02

    Proving

    The SP1 host pool executes the guest program off-chain and emits one succinct proof per sub-computation.

    SP1 zkVM
  3. 03

    Folding

    The Nova / SuperNova adapter folds the sub-proofs recursively into a single Groth16 SNARK — constant final size.

    NOVA IVC
  4. 04

    Verification

    The Anchor program runs verify_proof on Solana mainnet and writes a ProofRecord PDA seeded by hash.

    SOLANA
  5. 05

    Marketplace

    Verified results publish as Pyth-style feeds. External dApps subscribe by hash and read proven facts.

    FEEDS

#Quickstart

Install the CLI and run a circuit end to end. The proofs are identical to what your dApp would generate.

TERMINAL · BASH
$ npm install -g proofra-cli$ proofra prove median --input scores.json$ proofra fold ./proofs$ proofra verify folded.bin --cluster mainnet ✓ verified · 0.0001 SOL · <200K CU

#Circuits

A circuit is a guest program plus a typed input and output. Five ship today; adding one is a directory and a builder entry — the SDK and verifier pick it up automatically.

CIRCUITINPUTOUTPUT
scoringscores[64], weights[64]weighted_avg_fp
aggregationVec<u64> · ≤4096sum, avg, min, max
medianraw[256], sorted[256]u64 median
sortinput[256], perm[256][u64; 256]
ml-inferencefeatures[32], w1/b1…[i32; 4] logits

#CPI

The CLI is the human surface: you stand at a terminal, type proofra verify, and read the result with your eyes. Cross-Program Invocation is the program surface — what a Solana program calls when it, not a human, needs a verified fact before it acts.

A lending market that will not lend against an unverified risk score. A leaderboard that will not record a run it cannot prove was legitimate. A mint that will not issue unless an ML inference actually returned the gating class. Both surfaces wrap the same single instruction.

Add the verifier crate to your program's Cargo.toml with the cpi feature. That pulls in the generated CPI helpers and turns off the on-chain entrypoint, so you link the instruction builders without shipping a second copy of the program:

Cargo.toml
[dependencies]proofra-verifier = { version = "0.1", features = ["cpi"] }anchor-lang = "0.31"

The verifier exposes a single verify_proof instruction. Because verification and the action it gates run in the same transaction, they are atomic — either both land or neither does. That atomicity is the whole reason CPI exists: composable verified compute, with no trusted gap.

#ProofRecord

On success the program writes a ProofRecord PDA seeded by [b"proof", &proof_hash]. Distinct verifications never contend; the proof bytes stay off-chain.

ProofRecord · RUST
#[account]pub struct ProofRecord { pub proof_hash: [u8; 32], pub circuit_id: u16, pub verified_at: i64, pub public_inputs: Vec<u8>, pub submitter: Pubkey,}

#Errors

The verifier returns Anchor error codes. Handle them in your client or program before acting on a result.

CODENAMEMEANING
6000InvalidProofFolded proof failed verification.
6001CircuitMismatchcircuit_id does not match the verifier config.
6002RecordExistsProofRecord for this hash already settled.
6003InputTooLargepublic_inputs exceeds the account size limit.
Was this page helpful? Edit on GitHub ↗