Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I verify a proof which may have more than 2 steps inside its query_round_proofs #3

Open
AndrewLeeCHCH opened this issue Jan 31, 2023 · 12 comments

Comments

@AndrewLeeCHCH
Copy link

After running the e2e test successfully, I try to verify plonky2-sha256 proof through Circom way. Then, I add the following code to the plonky2-sha256 project. It compiles successfully and faces fatal error since the steps of query round proof is more than 2.
Is there a way to reduce the proof's query round step to pass this assertion?

let proof = data.prove(pw).unwrap(); /// sha256 proof
let conf = generate_verifier_config(&proof)?; /// Generate verifier config for sha256 proof, it failed
let (circom_constants, circom_gates) = generate_circom_verifier(&conf, &data.common, &data.verifier_only)?;

Fatal error position

assert_eq!(proof.opening_proof.query_round_proofs[0].steps.len(), 2);

@AndrewLeeCHCH AndrewLeeCHCH changed the title How can I verify proof with more steps? How can I verify a proof which may have more than 2 steps inside its query_round_proofs Jan 31, 2023
@ghost
Copy link

ghost commented Jan 31, 2023

Did you use standard_recursion_config in Plonky2 circuit? It should use only 2 steps.
You can always recursively prove your proof with this config.

@AndrewLeeCHCH
Copy link
Author

Hi Saideng,

Thank you for the response. Unfortunately, I did use the standard recursion config. To avoid anything being messed up with my code change, I did a quick test with the plonky2-sha256 sample. I added one line for logging. It turns out the length of steps is 4.

Here is code snippet.

let mut hasher = Sha256::new();
    hasher.update(msg);
    let hash = hasher.finalize();
    // println!("Hash: {:#04X}", hash);

    let msg_bits = array_to_bits(msg);
    let len = msg.len() * 8;
    println!("block count: {}", (len + 65 + 511) / 512);
    const D: usize = 2;
    type C = PoseidonGoldilocksConfig;
    type F = <C as GenericConfig<D>>::F;
    let mut builder = CircuitBuilder::<F, D>::new(CircuitConfig::standard_recursion_config());
    let targets = make_circuits(&mut builder, len as u64);
    let mut pw = PartialWitness::new();

    for i in 0..len {
        pw.set_bool_target(targets.message[i], msg_bits[i]);
    }

    let expected_res = array_to_bits(hash.as_slice());
    for i in 0..expected_res.len() {
        if expected_res[i] {
            builder.assert_one(targets.digest[i].target);
        } else {
            builder.assert_zero(targets.digest[i].target);
        }
    }

    println!(
        "Constructing inner proof with {} gates",
        builder.num_gates()
    );
    let data = builder.build::<C>();
    let timing = TimingTree::new("prove", Level::Debug);
    let proof = data.prove(pw).unwrap();
    println!("proof steps length {}", proof.proof.opening_proof.query_round_proofs[0].steps.len()); // Print steps length
    timing.print();

    let timing = TimingTree::new("verify", Level::Debug);
    let res = data.verify(proof);
    timing.print();

    res
}

Here is the console log.

block count: 45
Constructing inner proof with 261980 gates
[INFO  plonky2::plonk::circuit_builder] Degree before blinding & padding: 262019
[INFO  plonky2::plonk::circuit_builder] Degree after blinding & padding: 262144
[DEBUG plonky2::plonk::circuit_builder] Building circuit took 43.592686s
proof steps length 4
[DEBUG plonky2::util::timing] 66.4551s to prove
[DEBUG plonky2::util::timing] 0.0172s to verify

@ghost
Copy link

ghost commented Feb 1, 2023

I suggest you recursively prove it in a new proof. like this one: https://github.com/polymerdao/plonky2-ed25519/blob/main/src/main.rs#L71

@AndrewLeeCHCH
Copy link
Author

It works as expected, thank you

@AndrewLeeCHCH
Copy link
Author

After I replaced e2e testing constants.circom, gates.circom, conf.json and proof.json with my own generation files, plonky2.circom failed to compile. Do I miss any needed modifications for circom compilation?

****COMPILING CIRCUIT****
error[T3001]: Out of bounds exception
    ┌─ "/home/user/zk-benchmark/plonky2-circom/circom/circuits/poseidon.circom":305:5
    │
305 │     cPoseidon[0].capacity[0] <== capacity[0];
    │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found here
    │
    = call trace:
      ->VerifyPlonky2Proof
       ->HashNoPad_GL

previous errors were found

@ghost
Copy link

ghost commented Feb 2, 2023

Do you have any public inputs in your proof?

@AndrewLeeCHCH
Copy link
Author

I don't think so

@AndrewLeeCHCH
Copy link
Author

Here is the full sample code

pub fn prove_sha256(msg: &[u8]) -> Result<()> {
    let mut hasher = Sha256::new();
    hasher.update(msg);
    let hash = hasher.finalize();
    // println!("Hash: {:#04X}", hash);

    let msg_bits = array_to_bits(msg);
    let len = msg.len() * 8;
    println!("block count: {}", (len + 65 + 511) / 512);
    const D: usize = 2;
    type C = PoseidonGoldilocksConfig;
    type F = <C as GenericConfig<D>>::F;
    let config = CircuitConfig::standard_recursion_config();
    // config.fri_config.rate_bits = 3;
    println!("{:?}", config);

    let mut builder = CircuitBuilder::<F, D>::new(config);
    let mut pw = PartialWitness::new();
    let expected_res = array_to_bits(hash.as_slice());
    let mut targets = vec![];


    for _ in 0..2 {
        let curr = targets.len();
        targets.push(make_circuits(&mut builder, len as u64));

        for i in 0..len {
            pw.set_bool_target(targets[curr].message[i], msg_bits[i]);
        }

        for i in 0..expected_res.len() {
            if expected_res[i] {
                builder.assert_one(targets[curr].digest[i].target);
            } else {
                builder.assert_zero(targets[curr].digest[i].target);
            }
        }
    }

    println!(
        "Constructing inner proof with {} gates",
        builder.num_gates()
    );
    let data = builder.build::<C>();
    let timing = TimingTree::new("prove", Level::Debug);
    let sha256proof = data.prove(pw).unwrap();
    timing.print();
    println!("proof steps length {}", sha256proof.proof.opening_proof.query_round_proofs[0].steps.len());

    let config = CircuitConfig::standard_recursion_config();
    let proof = recursive_proof::<F, C, C, D>(&(sha256proof, data.verifier_only, data.common), None, &config, None)?;

    println!("middle proof steps {:?}", proof.0.proof.opening_proof.query_round_proofs[0].steps.len());

    let conf = generate_verifier_config(&proof.0)?;
    let (circom_constants, circom_gates) = generate_circom_verifier(&conf, &proof.2, &proof.1)?;

    let mut circom_file = File::create("./circom/circuits/constants.circom")?;
    circom_file.write_all(circom_constants.as_bytes())?;
    circom_file = File::create("./circom/circuits/gates.circom")?;
    circom_file.write_all(circom_gates.as_bytes())?;

    let proof_json = generate_proof_base64(&proof.0, &conf)?;

    if !Path::new("./circom/test/data").is_dir() {
        std::fs::create_dir("./circom/test/data")?;
    }

    let mut proof_file = File::create("./circom/test/data/proof.json")?;
    proof_file.write_all(proof_json.as_bytes())?;

    let mut conf_file = File::create("./circom/test/data/conf.json")?;
    conf_file.write_all(serde_json::to_string(&conf)?.as_ref())?;

    // let timing = TimingTree::new("verify", Level::Debug);
    // let res = data.verify(proof);
    // timing.print();

    // res
    Ok(())
}

@ghost
Copy link

ghost commented Feb 3, 2023

Currently the circuits require some public inputs. Try to add some public inputs in your code.

builder.register_public_inputs()

@AndrewLeeCHCH
Copy link
Author

Thanks a lot. I missed some information inside the recursive proving logic. Right now, it works fine. One more thing to confirm is whether I can use some lower ptau to generate circuit's corresponding zkey.

@ghost
Copy link

ghost commented Feb 3, 2023

I haven't done this step. I think it needs 2**25 powers.

@AndrewLeeCHCH
Copy link
Author

I haven't done this step. I think it needs 2**25 powers.

Exactly, 2**25 is the minimum requirement for this circuit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant