plonky2/plonky2/examples/square_root.rs
Daniel Lubarov 92974aa105 A few more cyclic recursion changes
In preparation for adding the zkEVM aggregation circuit. Mainly,

- Adds a `WitnessWrite` trait, a sub-trait of `Witness`, and move the write methods to it. `GeneratedValues` impls `WitnessWrite`, which lets generators like `DummyProofGenerator` access all our write methods like `set_proof_with_pis_target`. Also removes some duplication.

- Remove `set_cyclic_recursion_data_target` - now that dummy proof data is automatically populated, all that remains is populating `condition` and the cyclic proof + VK. I think it's easy enough for callers to do this; the steps are the same as with `conditionally_verify_proof`. This way there's no cyclic-recursion-specific API to learn about.

- Split `cyclic_recursion` into two variants, one which checks the current circuit or a dummy, and a more general one which checks the current circuit or some other circuit. We can use the latter to build a more efficient aggregation circuit, where we check another aggregation proof or an EVM proof, with no dummy proofs involved.
2022-12-11 22:43:26 -08:00

82 lines
2.5 KiB
Rust

use core::marker::PhantomData;
use anyhow::Result;
use plonky2::field::types::{PrimeField, Sample};
use plonky2::hash::hash_types::RichField;
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
use plonky2::iop::target::Target;
use plonky2::iop::witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite};
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::plonk::circuit_data::CircuitConfig;
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
use plonky2_field::extension::Extendable;
/// A generator used by the prover to calculate the square root (`x`) of a given value
/// (`x_squared`), outside of the circuit, in order to supply it as an additional public input.
#[derive(Debug)]
struct SquareRootGenerator<F: RichField + Extendable<D>, const D: usize> {
x: Target,
x_squared: Target,
_phantom: PhantomData<F>,
}
impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F>
for SquareRootGenerator<F, D>
{
fn dependencies(&self) -> Vec<Target> {
vec![self.x_squared]
}
fn run_once(&self, witness: &PartitionWitness<F>, out_buffer: &mut GeneratedValues<F>) {
let x_squared = witness.get_target(self.x_squared);
let x = x_squared.sqrt().unwrap();
println!("Square root: {x}");
out_buffer.set_target(self.x, x);
}
}
/// An example of using Plonky2 to prove a statement of the form
/// "I know the square root of this field element."
fn main() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_recursion_config();
let mut builder = CircuitBuilder::<F, D>::new(config);
let x = builder.add_virtual_target();
let x_squared = builder.square(x);
builder.register_public_input(x_squared);
builder.add_simple_generator(SquareRootGenerator::<F, D> {
x,
x_squared,
_phantom: PhantomData,
});
// Randomly generate the value of x^2: any quadratic residue in the field works.
let x_squared_value = {
let mut val = F::rand();
while !val.is_quadratic_residue() {
val = F::rand();
}
val
};
let mut pw = PartialWitness::new();
pw.set_target(x_squared, x_squared_value);
let data = builder.build::<C>();
let proof = data.prove(pw.clone())?;
let x_squared_actual = proof.public_inputs[0];
println!("Field element (square): {x_squared_actual}");
data.verify(proof)
}