Proof Types
Prerequisite Reading: Request a Proof, Proof Lifecycle
Default: Merkle Inclusion Proofs
By default, Boundless delivers proofs on-chain as merkle inclusion proofs:
- Proofs are batched together are aggregated into a single Groth16 proof.
 - The aggregated proof is verified once on-chain
 - Individual proofs are verified through cheap merkle inclusion proofs into this root
 
This design is what makes Boundless cost-effective for on-chain verification.
Requesting a specific proof type
While merkle inclusion proofs are efficient for on-chain verification, there may be cases where you need to access the underlying proof instead of a merkle inclusion proof. For example:
- Cross-chain verification where you need to verify the proof on a different chain
 - Integration with other systems that expect a specific proof type
 - Custom verification logic that requires the full proof
 
Boundless supports requesting a raw Groth16 proof instead of a merkle inclusion proof. You can specify this in your proof request by setting the proof_type to ProofType::Groth16:
let request = client.new_request()
    .with_program(program)
    .with_stdin(input)
    .with_groth16_proof()  // Request raw Groth16 proof
    .with_offer(
        OfferParams::builder()
            .min_price(parse_ether("0.001")?)
            .max_price(parse_ether("0.002")?)
            .timeout(1000)
            .lock_timeout(1000)
    );
Considerations
When choosing between proof types, consider:
- 
Gas Costs
- Merkle inclusion proofs are much cheaper to verify on-chain
 - Raw Groth16 proofs require full SNARK verification each time. This will increase the price of the proof
 
 - 
Use Case Requirements
- If you only need on-chain verification, use the default merkle inclusion proof
 - If you need cross-chain verification or raw proof data, use Groth16
 - If you need to compose the proof by verifying it within another zkVM guest program, use Groth16
 
 
Example: Proof Composition using Proof Types
In the Proof Composition example, we demonstrate how to compose a proof from multiple proofs.
Composing a proof requires us to verify a previously generated Groth16 proof within the zkVM guest program. This requires us to request a raw Groth16 proof from the Boundless Market.
In the composition example, we first request a raw Groth16 proof from the Boundless Market using the ECHO guest program.
let request = client.new_request()
    .with_program(program)
    .with_stdin(input)
    .with_groth16_proof()  // Request raw Groth16 proof
    .with_offer(
        OfferParams::builder()
            .min_price(parse_ether("0.001")?)
            .max_price(parse_ether("0.002")?)
            .timeout(1000)
            .lock_timeout(1000)
    );
We then provide the Groth16 proof as input to the IDENTITY zkVM guest program, and verify the proof.
use risc0_zkvm::guest::env;
use risc0_zkvm::{Digest, Receipt};
 
fn main() {
    let (image_id, receipt): (Digest, Receipt) = env::read();
    let claim = receipt.claim().unwrap();
    receipt.verify(image_id).unwrap();
    ....
}