Prover

The zkm_sdk crate provides all the necessary tools for proof generation. Key features include the ProverClient, enabling you to:

  • Initialize proving/verifying keys via setup().
  • Execute your program via execute().
  • Generate proofs with prove().
  • Verify proofs through verify().

When generating Groth16 or PLONK proofs, the ProverClient automatically downloads the pre-generated proving key (pk) from a trusted setup by calling try_install_circuit_artifacts().

Example: Fibonacci

The following code is an example of using zkm_sdk in host.

use zkm_sdk::{include_elf, utils, ProverClient, ZKMProofWithPublicValues, ZKMStdin}; /// The ELF we want to execute inside the zkVM. const ELF: &[u8] = include_elf!("fibonacci"); fn main() { // Create an input stream and write '1000' to it. let n = 1000u32; // The input stream that the guest will read from using `zkm_zkvm::io::read`. Note that the // types of the elements in the input stream must match the types being read in the program. let mut stdin = ZKMStdin::new(); stdin.write(&n); // Create a `ProverClient` method. let client = ProverClient::new(); // Execute the guest using the `ProverClient.execute` method, without generating a proof. let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap(); println!("executed program with {} cycles", report.total_instruction_count()); // Generate the proof for the given program and input. let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); // Read and verify the output. // // Note that this output is read from values committed to in the program using // `zkm_zkvm::io::commit`. let n = proof.public_values.read::<u32>(); let a = proof.public_values.read::<u32>(); let b = proof.public_values.read::<u32>(); println!("n: {}", n); println!("a: {}", a); println!("b: {}", b); // Verify proof and public values client.verify(&proof, &vk).expect("verification failed"); }

Proof Types

zkMIPS provides customizable proof generation options:

#![allow(unused)] fn main() { /// A proof generated with zkMIPS of a particular proof mode. #[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, EnumTryAs)] #[strum_discriminants(derive(Default, Hash, PartialOrd, Ord))] #[strum_discriminants(name(ZKMProofKind))] pub enum ZKMProof { /// A proof generated by the core proof mode. /// /// The proof size scales linearly with the number of cycles. #[strum_discriminants(default)] Core(Vec<ShardProof<CoreSC>>), /// A proof generated by the compress proof mode. /// /// The proof size is constant, regardless of the number of cycles. Compressed(Box<ZKMReduceProof<InnerSC>>), /// A proof generated by the Plonk proof mode. Plonk(PlonkBn254Proof), /// A proof generated by the Groth16 proof mode. Groth16(Groth16Bn254Proof), } }

Core Proof (Default)

The default prover mode generates a sequence of STARK proofs whose cumulative proof size scales linearly with the execution trace length.

#![allow(unused)] fn main() { let client = ProverClient::new(); client.prove(&pk, stdin).run().unwrap(); }

Compressed Proof

The compressed proving mode generates constant-sized STARK proofs, but not suitable for on-chain verification.

#![allow(unused)] fn main() { let client = ProverClient::new(); client.prove(&pk, stdin).compressed().run().unwrap(); }

The Groth16 proving mode ​generates succinct SNARK proofs with a compact size of approximately 260 bytes, ​and features on-chain verification.

#![allow(unused)] fn main() { let client = ProverClient::new(); client.prove(&pk, stdin).groth16().run().unwrap(); }

PLONK Proof

The PLONK proving mode generates succinct SNARK proofs with a compact size of approximately 868 bytes, while maintaining on-chain verifiability. In contrast to Groth16, PLONK removes the dependency on trusted setup ceremonies.

#![allow(unused)] fn main() { let client = ProverClient::new(); client.prove(&pk, stdin).plonk().run().unwrap(); }

Hardware Acceleration

zkMIPS provides hardware acceleration support for AVX256/AVX512 on x86 CPUs due to support in Plonky3.

You can check your CPU's AVX compatibility by running:

grep avx /proc/cpuinfo

Check if you can see avx2 or avx512 in the results.

To activate AVX256 optimization, add these flags to your RUSTFLAGS environment variable:

RUSTFLAGS="-C target-cpu=native" cargo run --release

To activate AVX512 optimization, add these flags to your RUSTFLAGS environment variable:

RUSTFLAGS="-C target-cpu=native -C target-feature=+avx512f" cargo run --release

Network Prover

We support a network prover via the ZKM Proof Network, accessible through our RESTful API.The network prover currently supports only the Groth16 proving mode. >The proving process consists of several stages: queuing, splitting, proving, and finalizing. Each stage may take a different amount of time.

Requirements

  • CA certificate: ca.pem, ca.key. These keys are stored here
  • Register your address to gain access.
  • SDK dependency: add zkm_sdk from the zkMIPS SDK to your Cargo.toml:
zkm-sdk = { git = "https://github.com/zkMIPS/zkMIPS", branch = "main" }

Environment Variable Setup

Before running your application, export the following environment variables to enable the network prover:

export ZKM_PRIVATE_KEY=<your_private_key> # Private key corresponding to your registered public key export CERT_PATH=<path_to_client_certificate> # Path to client certificate export KEY_PATH=<path_to_client_key> # Path to client key

You can generate the client certificate and key by running the certgen.sh script.

To host your own network prover, export the following variables to configure your endpoint:

export ENDPOINT=<proof_network_endpoint> # Proof network endpoint (default: https://152.32.186.45:20002) export CA_CERT_PATH=<path_to_ca_certificate> # Path to CA certificate (default: ca.pem) export DOMAIN_NAME=<domain_name> # Domain name (default: "stage")

Example

The following example shows how to use the network prover on the host:

use std::env; use zkm_sdk::{include_elf, ProverClient, ZKMStdin}; const FIBONACCI_ELF: &[u8] = include_elf!("fibonacci"); fn main() { utils::setup_logger(); let mut stdin = ZKMStdin::new(); stdin.write(&10usize); let elf = test_artifacts::FIBONACCI_ELF; // create network client let client = ProverClient::network(); let (pk, vk) = client.setup(elf); let proof = client.prove(&pk, stdin).run().unwrap(); client.verify(&proof, &vk).unwrap(); }