diff --git a/field/src/types.rs b/field/src/types.rs index ac94bcfa..7130b7f5 100644 --- a/field/src/types.rs +++ b/field/src/types.rs @@ -427,6 +427,59 @@ pub trait Field: pub trait PrimeField: Field { fn to_canonical_biguint(&self) -> BigUint; + + fn is_quadratic_residue(&self) -> bool { + if self.is_zero() { + return true; + } + // This is based on Euler's criterion. + let power = Self::NEG_ONE.to_canonical_biguint() / 2u8; + let exp = self.exp_biguint(&power); + if exp == Self::ONE { + return true; + } + if exp == Self::NEG_ONE { + return false; + } + panic!("Unreachable") + } + + fn sqrt(&self) -> Option { + if self.is_zero() { + Some(*self) + } else if self.is_quadratic_residue() { + let t = (Self::order() - BigUint::from(1u32)) + / (BigUint::from(2u32).pow(Self::TWO_ADICITY as u32)); + let mut z = Self::POWER_OF_TWO_GENERATOR; + let mut w = self.exp_biguint(&((t - BigUint::from(1u32)) / BigUint::from(2u32))); + let mut x = w * *self; + let mut b = x * w; + + let mut v = Self::TWO_ADICITY as usize; + + while !b.is_one() { + let mut k = 0usize; + let mut b2k = b; + while !b2k.is_one() { + b2k = b2k * b2k; + k += 1; + } + let j = v - k - 1; + w = z; + for _ in 0..j { + w = w * w; + } + + z = w * w; + b *= z; + x *= w; + v = k; + } + Some(x) + } else { + None + } + } } /// A finite field of order less than 2^64. diff --git a/plonky2/examples/factorial.rs b/plonky2/examples/factorial.rs new file mode 100644 index 00000000..bcdb35dc --- /dev/null +++ b/plonky2/examples/factorial.rs @@ -0,0 +1,43 @@ +use anyhow::Result; +use plonky2::field::types::Field; +use plonky2::iop::witness::{PartialWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + +/// An example of using Plonky2 to prove a statement of the form +/// "I know n * (n + 1) * ... * (n + 99)". +/// When n == 1, this is proving knowledge of 100!. +fn main() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + // The arithmetic circuit. + let initial = builder.add_virtual_target(); + let mut cur_target = initial; + for i in 2..101 { + let i_target = builder.constant(F::from_canonical_u32(i)); + cur_target = builder.mul(cur_target, i_target); + } + + // Public inputs are the initial value (provided below) and the result (which is generated). + builder.register_public_input(initial); + builder.register_public_input(cur_target); + + let mut pw = PartialWitness::new(); + pw.set_target(initial, F::ONE); + + let data = builder.build::(); + let proof = data.prove(pw)?; + + println!( + "Factorial starting at {} is {}!", + proof.public_inputs[0], proof.public_inputs[1] + ); + + data.verify(proof) +} diff --git a/plonky2/examples/fibonacci.rs b/plonky2/examples/fibonacci.rs new file mode 100644 index 00000000..6609fc1d --- /dev/null +++ b/plonky2/examples/fibonacci.rs @@ -0,0 +1,49 @@ +use anyhow::Result; +use plonky2::field::types::Field; +use plonky2::iop::witness::{PartialWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + +/// An example of using Plonky2 to prove a statement of the form +/// "I know the 100th element of the Fibonacci sequence, starting with constants a and b." +/// When a == 0 and b == 1, this is proving knowledge of the 100th (standard) Fibonacci number. +fn main() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + // The arithmetic circuit. + let initial_a = builder.add_virtual_target(); + let initial_b = builder.add_virtual_target(); + let mut prev_target = initial_a; + let mut cur_target = initial_b; + for _ in 0..99 { + let temp = builder.add(prev_target, cur_target); + prev_target = cur_target; + cur_target = temp; + } + + // Public inputs are the two initial values (provided below) and the result (which is generated). + builder.register_public_input(initial_a); + builder.register_public_input(initial_b); + builder.register_public_input(cur_target); + + // Provide initial values. + let mut pw = PartialWitness::new(); + pw.set_target(initial_a, F::ZERO); + pw.set_target(initial_b, F::ONE); + + let data = builder.build::(); + let proof = data.prove(pw)?; + + println!( + "100th Fibonacci number mod |F| (starting with {}, {}) is: {}", + proof.public_inputs[0], proof.public_inputs[1], proof.public_inputs[2] + ); + + data.verify(proof) +} diff --git a/plonky2/examples/square_root.rs b/plonky2/examples/square_root.rs new file mode 100644 index 00000000..0bc89f47 --- /dev/null +++ b/plonky2/examples/square_root.rs @@ -0,0 +1,81 @@ +use std::marker::PhantomData; + +use anyhow::Result; +use plonky2::field::types::{Field, PrimeField}; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::witness::{PartialWitness, PartitionWitness, Witness}; +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, const D: usize> { + x: Target, + x_squared: Target, + _phantom: PhantomData, +} + +impl, const D: usize> SimpleGenerator + for SquareRootGenerator +{ + fn dependencies(&self) -> Vec { + vec![self.x_squared] + } + + fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { + 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 = >::F; + + let config = CircuitConfig::standard_recursion_config(); + + let mut builder = CircuitBuilder::::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:: { + 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::(); + let proof = data.prove(pw.clone())?; + + let x_squared_actual = proof.public_inputs[0]; + println!("Field element (square): {}", x_squared_actual); + + data.verify(proof) +}