Tenzro Testnet is live —request testnet TNZO

Zero-Knowledge Proofs

Tenzro uses Plonky3 STARKs over the KoalaBear field for verifiable computation. There is no trusted setup, no per-circuit ceremony, and no toxic waste — proofs verify in milliseconds with post-quantum-conjectured soundness.

Why STARKs, Why Plonky3

  • Transparent setup: No CRS, no Powers of Tau ceremony, no per-circuit proving keys. Anyone can prove or verify with the public parameters.
  • KoalaBear field: 31-bit prime 2^31 − 2^24 + 1 with two-adicity 24 — fast SIMD arithmetic on commodity CPUs.
  • Poseidon2 + FRI: Hash-based commitments. No pairings, no elliptic curves.
  • Post-quantum-conjectured: Soundness rests on collision-resistance of the hash, which is conjectured to hold against quantum adversaries.
  • Compact proofs: ~64–128 KB; verification ~5–20 ms on commodity hardware.
  • Hybrid ZK-in-TEE: Pair proofs with hardware attestation for dual verification.

Pre-Built AIRs

Three concrete Algebraic Intermediate Representations (AIRs) ship with the node. Each is keyed by a stable circuit_id string used by the on-chain commitment registry and the JSON-RPC verifier:

circuit_id: "inference" — InferenceAir

Proves an AI inference was computed correctly without revealing model weights or input data.

Public inputs: model_hash, input_hash, output_hash (each as 4-byte LE KoalaBear chunks)
Private inputs: model_weights, input_data, computation_trace

circuit_id: "settlement" — SettlementAir

Proves payment settlement occurred correctly with the right fee calculation.

Public inputs: settlement_id, amount, fee
Private inputs: payer_signature, payee_address, timestamp

circuit_id: "identity" — IdentityAir

Proves identity ownership without revealing private keys or the full DID document.

Public inputs: did_hash, credential_hash
Private inputs: private_key, credential_proof

Pinned Testnet Configuration

The whole network agrees on one Plonky3 config so proofs verify identically across nodes. The dev-tree config is pinned at git rev 32079474b1d31d9221656ae774afb322d2597db0:

use tenzro_zk::build_testnet_config;

let config = build_testnet_config();
// log_blowup   = 1
// num_queries  = 64
// query_pow    = 16
// commit_pow   = 8
// hash         = Poseidon2 over KoalaBear
// commitment   = FRI

Generating a Proof

use tenzro_zk::{Plonky3Prover, Proof, ProofType, build_testnet_config};

let config  = build_testnet_config();
let prover  = Plonky3Prover::new(config.clone(), "inference")?;

// Public inputs are field-element chunks (4 bytes LE per element).
let public_inputs: Vec<Vec<u8>> = vec![
    model_hash_chunks,   // Vec<u8> — 4-byte little-endian KoalaBear elements
    input_hash_chunks,
    output_hash_chunks,
];

let witness = /* private trace cells */;

// Produce a Proof envelope:
//   { proof_bytes, public_inputs, proof_type=Plonky3, circuit_id, ... }
let proof: Proof = prover.prove(&public_inputs, &witness).await?;
assert_eq!(proof.proof_type, ProofType::Plonky3);
assert_eq!(proof.circuit_id, "inference");

Verifying a Proof

A single generic dispatcher matches on the envelope's circuit_idand runs the right AIR's verifier against the pinned config. This is the same entry point used by web, MCP, and JSON-RPC handlers, plus the settlement engine:

use tenzro_zk::verify_proof_envelope;

let valid = verify_proof_envelope(&proof)?;

if valid {
    println!("✓ Proof verified");
    // Release escrow, accept inference result, mark settlement final.
} else {
    println!("✗ Proof invalid");
    // Reject result, slash provider, refund payer.
}

Commitment-Attestation Model (On-Chain Verification)

STARK proofs are too large to verify inside an EVM precompile economically. Tenzro splits the work: validators run the full Plonky3 verifier off-EVM, then record a 32-byte commitment in the on-chain ZkCommitmentRegistry. The EVM ZK_VERIFY precompile becomes an O(1) HashSet lookup against that registry.

use tenzro_zk::compute_zk_commitment;

// Commitment hash, computed identically off-EVM and on-EVM:
//   SHA-256( circuit_id ‖ proof_bytes ‖ Σ( len_le(pi) ‖ pi ) )
//
// where len_le(pi) is a 4-byte little-endian length prefix per public-input chunk.
let commitment: [u8; 32] = compute_zk_commitment(&proof);

// Validators publish the commitment after they accept the proof.
// EVM contracts can then call ZK_VERIFY (precompile address, see /docs/evm)
// with the commitment bytes and get true / false in O(1).

JSON-RPC API

# Generate a proof
curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_createZkProof",
    "params": [{
      "circuit_id": "inference",
      "proof_type": "plonky3",
      "public_inputs": ["0x12345678", "0x9abcdef0", "0x..."],
      "witness": { "...": "..." }
    }],
    "id": 1
  }'

# Verify a proof
curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_verifyZkProof",
    "params": [{ "proof": { "proof_bytes": "0x...", "public_inputs": [...], "proof_type": "plonky3", "circuit_id": "inference" } }],
    "id": 2
  }'

# List supported circuits
curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "method": "tenzro_listCircuits", "id": 3 }'

CLI

# List supported circuits
tenzro zk circuits

# Generate a proof
tenzro zk prove \
  --circuit-id inference \
  --proof-type plonky3 \
  --public-inputs ./public_inputs.json \
  --witness ./witness.json \
  --output proof.bin

# Verify a proof
tenzro zk verify --proof proof.bin

# Generate keys (no-op for STARKs  no per-circuit setup; provided for parity)
tenzro zk keygen --circuit-id inference

Hybrid ZK-in-TEE

A TEE-resident prover runs the Plonky3 prover inside an enclave, then signs the resulting envelope with the enclave's hardware-rooted Ed25519 key. Verifiers check both the cryptographic proof and the hardware attestation:

use tenzro_zk::tee_integration::{
    generate_tee_zk_proof,
    verify_tee_zk_proof,
    sign_tee_zk_proof,
    verify_tee_zk_signature,
};

// Inside the enclave: generate proof and sign it with the TEE key.
let (proof, attestation) = generate_tee_zk_proof(
    "inference",
    &public_inputs,
    &witness,
    tee_provider,
).await?;
let signature = sign_tee_zk_proof(&proof, &attestation, tee_provider)?;

// Outside the enclave: verify both layers.
let proof_ok = verify_tee_zk_proof(&proof, &attestation)?;
let sig_ok   = verify_tee_zk_signature(&proof, &attestation, &signature)?;
assert!(proof_ok && sig_ok);

Use Cases

1. Verifiable AI Inference

// Provider returns inference output + Plonky3 proof.
let (result, proof) = model_provider.infer_with_proof(model_id, input).await?;

// User verifies before accepting.
let valid = tenzro_zk::verify_proof_envelope(&proof)?;
if valid {
    // Release escrow, accept output.
} else {
    // Reject and slash provider.
}

2. Settlement Receipts

// Settlement engine emits a Plonky3 proof committing to (settlement_id, amount, fee).
let proof = settlement_engine.prove_settlement(&settlement)?;

// Counterparties (and any auditor) verify with one RPC call.
let valid = tenzro_zk::verify_proof_envelope(&proof)?;

3. Credential / KYC Proofs

// Prove a credential is issued by a trusted issuer
// without revealing the full DID document.
let proof = identity_prover.prove(&PublicInputs {
    did_hash:        sha256(b"did:tenzro:human:..."),
    credential_hash: sha256(&credential_bytes),
}, &witness).await?;

Web Verification API

# Verify a Plonky3 proof via the public web API.
# Note: api.tenzro.network serves /verify/* directly — no /api/ prefix.
curl -X POST https://api.tenzro.network/verify/zk-proof \
  -H "Content-Type: application/json" \
  -d '{
    "proof": {
      "proof_bytes": "0x...",
      "public_inputs": ["0x12345678", "0x9abcdef0"],
      "proof_type": "plonky3",
      "circuit_id": "inference"
    }
  }'

# Response
{
  "valid": true,
  "circuit_id": "inference",
  "verification_time_ms": 12
}

Performance

Circuit: InferenceAir (medium witness)

CPU proving (commodity x86_64):
  - Single proof: low-seconds range (witness-dependent)

CPU verification:
  - Per proof: 5–20 ms

Proof size:
  - 64–128 KB envelope (proof_bytes + public_inputs)

On-chain check:
  - ZK_VERIFY EVM precompile: O(1) HashSet lookup, ~3k gas
    (the heavy verification ran off-EVM and was committed to the registry)