Prove and verify with Plonky3 STARKs
Create Plonky3 STARK proofs for the settlement and identity circuits, verify them on the network, and check the attested commitment from an EVM contract.
Tenzro Network uses Plonky3 STARKs, which need no trusted setup and rest on hash functions rather than elliptic curves, so they are quantum-safe. The network uses them in three places: to compress the finality certificates of Tenzro DAG Consensus, and in two application circuits you can call yourself:
- settlement: proves a statement about a payment's private service result, bound to the request it answers, without revealing the result.
- identity: proves a claim about an identity's private value, bound to a relying party's challenge, without revealing the value.
In this tutorial you create a proof for each circuit, have the network verify it, and read the resulting commitment from a contract.
Prerequisites
- The
tenzroCLI (see CLI reference). - Proofs are created on your own machine. The witness is read from standard input and never leaves the
tenzroprocess: it is not an argument, not a file and not sent to any node. Only the proof bundle goes to the network.
export RPC=https://rpc.tenzro.com1. List the circuits
tenzro zk circuits --rpc $RPC --format jsonEach entry names the circuit, the proof system (plonky3), the field (koala-bear) and the hash (poseidon2). This tutorial uses settlement and identity.
2. Prove a settlement
A proof is bound to a 32-byte binding: the verifier's challenge or the hash of the request it answers, so it cannot be replayed against another one. The 32-byte witness, the private value the statement is about, is read as hex from standard input:
BINDING=0x<32-byte challenge from the verifier>
printf '%s' "<32-byte witness hex>" | tenzro zk prove --circuit-id settlement --binding "$BINDING" \
> settlement-proof.json
jq '{circuit_id, public_inputs}' settlement-proof.jsonThe bundle carries the circuit id, the public inputs (the statement's digest and the binding, 32-byte hex each) and one proof leg per proof system. The witness itself stays private.
3. Verify on the network
tenzro zk verify --bundle settlement-proof.json --rpc $RPC --format jsonThe same check is the open JSON-RPC method tenzro_verifyZkProof, with circuit_id, public_inputs and proofs.
A verified proof yields a commitment: a hash of the circuit id, the proof and the public inputs. Change any public input and you get a different commitment.
4. Check the attestation
A commitment is admitted to the on-chain ZK_VERIFY registry when an AttestZkProof transaction verifies its proof in an executed block. Read whether it is:
tenzro zk attestation --commitment <commitment_hex> --rpc $RPCThe JSON-RPC method is tenzro_getZkAttestation.
5. Use the commitment from a contract
Plonky3 STARKs are too large to verify inside every EVM transaction, so contracts read the attested result instead. The ZK_VERIFY precompile takes a 32-byte commitment and returns 1 if it is in the attested registry and 0 otherwise. Tenzro precompiles run inside ordinary EVM transactions, so a settlement contract can gate a payout on a proof:
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;
contract ProofGatedPayout {
address public immutable zkVerify; // the ZK_VERIFY precompile address, see /docs/zk
constructor(address precompile) { zkVerify = precompile; }
function attested(bytes32 commitment) public view returns (bool) {
(bool ok, bytes memory out) = zkVerify.staticcall(abi.encodePacked(commitment));
return ok && out.length == 32 && uint256(bytes32(out)) == 1;
}
function release(bytes32 commitment, address payable to, uint256 amount) external {
require(attested(commitment), "proof not attested");
to.transfer(amount);
}
}6. Prove an identity claim
The identity circuit works the same way: the witness is the private value the claim is about, and the binding is the relying party's challenge.
printf '%s' "<32-byte witness hex>" | tenzro zk prove --circuit-id identity --binding "$BINDING" \
> identity-proof.json
tenzro zk verify --bundle identity-proof.json --rpc $RPCThe relying party learns that the statement holds for a witness it never sees, bound to the challenge it issued.
What these proofs are not for
Inference results on Tenzro are verified with TEE attestation, not with zero-knowledge proofs. To check that a model ran where and how a provider claims, use attested inference; see TEE.
Next steps
- ZK reference: ZK.
- How finality certificates are compressed: Finality certificates.
- Where settlement proofs fit: Settlement.