# Onchain Verification: Setup

The best way to get started with verifying SP1 proofs on-chain is to refer to the SP1 Project Template.

- The template program shows how to write outputs that can be decoded in Solidity.
- The template script shows how to generate the proof using the SDK and save it to a file.
- The template contract shows how to verify the proof onchain using Solidity.

Refer to the section on Contract Addresses for the addresses of the deployed verifiers.

## Generating SP1 Proofs for Onchain Verification

By default, the proofs generated by SP1 are not verifiable onchain, as they are non-constant size and STARK verification on Ethereum is very expensive. To generate a proof that can be verified onchain, we use performant STARK recursion to combine SP1 shard proofs into a single STARK proof and then wrap that in a SNARK proof. Our `ProverClient`

has a prover option for this called `plonk`

. Behind the scenes, this function will first generate a normal SP1 proof, then recursively combine all of them into a single proof using the STARK recursion protocol. Finally, the proof is wrapped in a SNARK proof using PLONK.

WARNING: The Groth16 and PLONK provers are only guaranteed to work on official releases of SP1. To use Groth16 or PLONK proving & verification locally, ensure that you have Docker installed and have at least 128GB of RAM.

### Example

```
use sp1_sdk::{utils, HashableKey, ProverClient, SP1Stdin};
/// The ELF we want to execute inside the zkVM.
const ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf");
fn main() {
// Setup logging.
utils::setup_logger();
// Create an input stream and write '500' to it.
let n = 500u32;
let mut stdin = SP1Stdin::new();
stdin.write(&n);
// Set up the pk and vk.
let client = ProverClient::new();
let (pk, vk) = client.setup(ELF);
println!("vk: {:?}", vk.bytes32());
// Generate the Groth16 proof.
let proof = client.prove(&pk, stdin).groth16().run().unwrap();
println!("generated proof");
// Get the public values as bytes.
let public_values = proof.public_values.as_slice();
println!("public values: 0x{}", hex::encode(public_values));
// Get the proof as bytes.
let solidity_proof = proof.bytes();
println!("proof: 0x{}", hex::encode(solidity_proof));
// Verify proof and public values
client.verify(&proof, &vk).expect("verification failed");
// Save the proof.
proof.save("fibonacci-groth16.bin").expect("saving proof failed");
println!("successfully generated and verified proof for the program!")
}
```

You can run the above script with `RUST_LOG=info cargo run --bin groth16_bn254 --release`

in `examples/fibonacci/script`

.

#### Using Groth16 and PLONK without Docker (Advanced)

If you would like to run the Groth16 or PLONK prover directly without Docker, you must have Go 1.22 installed and enable the `native-gnark`

feature in `sp1-sdk`

. This path is not recommended and may require additional native dependencies.

```
sp1-sdk = { version = "2.0.0", features = ["native-gnark"] }
```