All RISC Zero verifier contracts implement IRiscZeroVerifier:
interface IRiscZeroVerifier { /// @notice Verifies a RISC Zero proof /// @param seal The encoded cryptographic proof (Groth16) /// @param imageId The unique identifier for the guest program /// @param journalDigest SHA-256 hash of the journal function verify( bytes calldata seal, bytes32 imageId, bytes32 journalDigest ) external view;}
The verify() function reverts if verification fails. It does not return a boolean.
Here’s a complete example showing the standard verification pattern:
// SPDX-License-Identifier: MITpragma solidity ^0.8.20;import {IRiscZeroVerifier} from "risc0-ethereum/contracts/src/IRiscZeroVerifier.sol";contract EvenNumber { /// @notice The RISC Zero verifier contract IRiscZeroVerifier public immutable verifier; /// @notice Image ID of the only function we accept proofs from bytes32 public constant IS_EVEN_ID = /* your image ID here */; /// @notice The verified even number uint256 public number; constructor(IRiscZeroVerifier _verifier) { verifier = _verifier; } /// @notice Set the even number with proof verification /// @param x The number to set (must be even) /// @param seal The Groth16 proof function set(uint256 x, bytes calldata seal) public { // Step 1: Construct the expected journal bytes memory journal = abi.encode(x); // Step 2: Verify the proof // This will revert if the proof is invalid verifier.verify( seal, IS_EVEN_ID, sha256(journal) ); // Step 3: Update state (only reached if proof is valid) number = x; }}
Proofs generated in DEV_MODE will fail on-chain verification. Always use real proofs for testing contract integration.
# Don't use DEV_MODE for contract testing# RISC0_DEV_MODE=1 cargo run # ❌ Proofs won't verify# Generate real proofscargo run --release # ✅ Valid proofs
// test/EvenNumber.t.solimport {Test, console} from "forge-std/Test.sol";import {EvenNumber} from "../src/EvenNumber.sol";contract EvenNumberTest is Test { EvenNumber public evenNumber; address verifierRouter = /* deployed verifier */; function setUp() public { evenNumber = new EvenNumber( IRiscZeroVerifier(verifierRouter) ); } function testValidProof() public { // Load proof from file (generated by Rust) bytes memory seal = vm.parseBytes( vm.readFile("proofs/even_42.bin") ); evenNumber.set(42, seal); assertEq(evenNumber.number(), 42); } function testInvalidProof() public { bytes memory fakeSeal = hex"deadbeef"; vm.expectRevert(); evenNumber.set(42, fakeSeal); }}