An End-to-End example

This example builds off the previous example of the simple-example, where the mock-prover is replaced with an example of generating real proofs.

Constructing the circuit using private inputs from the User


    // The number of rows in our circuit cannot exceed 2^k. Since our example
    // circuit is very small, we can pick a very small value here.
    let k = 4;

    // Args from the command line
    let args: Vec<String> = env::args().collect();

    // Prepare the private and public inputs to the circuit!
    let constant = Fp::from(7);
    let a = Fp::from(args[1].parse::<u64>().unwrap());
    let b = Fp::from(args[2].parse::<u64>().unwrap());
    let c = constant * a.square() * b.square();

    // Instantiate the circuit with the private inputs.
    let circuit = MyCircuit {
        constant,
        a: Value::known(a),
        b: Value::known(b),
    };

Creating a proof

To generate a proof, we need to generate a verification key (vk) and a proving key (ok) as inputs for generating the proof using create_proof.


    let params: Params<EqAffine> = halo2_proofs::poly::commitment::Params::new(k);

    // Generate verification key.
    println!("Generating Verification Key");
    let vk = keygen_vk(&params, &circuit).unwrap();

    // Generate proving key.
    println!("Generating Proving Key from Verification Key");
    let pk = keygen_pk(&params, vk, &circuit).unwrap();

    let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);

    println!("Generating Proof!");
    create_proof(
        &params,
        &pk,
        &[circuit],
        &[&[&[c]]],
        &mut OsRng,
        &mut transcript,
    )
    .expect("Failed to create proof!");

Write proof to a file

This is an example of how to write the proof to a file.


    let proof_path = "./proof";
    let proof = transcript.finalize();
    File::create(Path::new(proof_path))
        .expect("Failed to create proof file")
        .write_all(&proof[..])
        .expect("Failed to write proof");
    println!("Proof written to: {}", proof_path);

Verifying the proof


    let mut transcript_proof = Blake2bRead::init(&proof[..]);

    // Verify the proof
    println!("Verifying Proof");
    let verified_proof_result = verify_proof(
        &params,
        pk.get_vk(),
        SingleVerifier::new(&params),
        &[&[&[c]]],
        &mut transcript_proof,
    );

    // Print "OK(())" if the proof is valid or an error message otherwise.
    if verified_proof_result.is_ok() {
        println!("Proof verified!");
    } else {
        println!(
            "Proof verification failed! {}",
            verified_proof_result.err().unwrap()
        );
    }

Running the example

To generate the proof and verify the proof in this example run: cargo run --example e2e-example 2 3 where 2 and 3 are the values of the a and b variables in the proof.

Full Main Function

fn main() {
    use halo2_proofs::pasta::Fp;

    // The number of rows in our circuit cannot exceed 2^k. Since our example
    // circuit is very small, we can pick a very small value here.
    let k = 4;

    // Args from the command line
    let args: Vec<String> = env::args().collect();

    // Prepare the private and public inputs to the circuit!
    let constant = Fp::from(7);
    let a = Fp::from(args[1].parse::<u64>().unwrap());
    let b = Fp::from(args[2].parse::<u64>().unwrap());
    let c = constant * a.square() * b.square();

    // Instantiate the circuit with the private inputs.
    let circuit = MyCircuit {
        constant,
        a: Value::known(a),
        b: Value::known(b),
    };


    let params: Params<EqAffine> = halo2_proofs::poly::commitment::Params::new(k);

    // Generate verification key.
    println!("Generating Verification Key");
    let vk = keygen_vk(&params, &circuit).unwrap();

    // Generate proving key.
    println!("Generating Proving Key from Verification Key");
    let pk = keygen_pk(&params, vk, &circuit).unwrap();

    let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);

    println!("Generating Proof!");
    create_proof(
        &params,
        &pk,
        &[circuit],
        &[&[&[c]]],
        &mut OsRng,
        &mut transcript,
    )
    .expect("Failed to create proof!");


    let proof_path = "./proof";
    let proof = transcript.finalize();
    File::create(Path::new(proof_path))
        .expect("Failed to create proof file")
        .write_all(&proof[..])
        .expect("Failed to write proof");
    println!("Proof written to: {}", proof_path);


    let mut transcript_proof = Blake2bRead::init(&proof[..]);

    // Verify the proof
    println!("Verifying Proof");
    let verified_proof_result = verify_proof(
        &params,
        pk.get_vk(),
        SingleVerifier::new(&params),
        &[&[&[c]]],
        &mut transcript_proof,
    );

    // Print "OK(())" if the proof is valid or an error message otherwise.
    if verified_proof_result.is_ok() {
        println!("Proof verified!");
    } else {
        println!(
            "Proof verification failed! {}",
            verified_proof_result.err().unwrap()
        );
    }

}