diff --git a/Cargo.toml b/Cargo.toml index 00a4b28f..28fcd834 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman", "ecdsa"] +members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman", "ecdsa", "plonky2_u32"] [profile.release] opt-level = 3 diff --git a/ecdsa/Cargo.toml b/ecdsa/Cargo.toml index a7e1024b..9a7e3c9a 100644 --- a/ecdsa/Cargo.toml +++ b/ecdsa/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" plonky2 = { path = "../plonky2" } plonky2_util = { path = "../util" } plonky2_field = { path = "../field" } +plonky2_u32 = { path = "../plonky2_u32" } num = "0.4.0" itertools = "0.10.0" rayon = "1.5.1" diff --git a/ecdsa/src/gadgets/biguint.rs b/ecdsa/src/gadgets/biguint.rs index 25dab656..b98fcdc1 100644 --- a/ecdsa/src/gadgets/biguint.rs +++ b/ecdsa/src/gadgets/biguint.rs @@ -1,7 +1,6 @@ use std::marker::PhantomData; use num::{BigUint, Integer, Zero}; -use plonky2::gadgets::arithmetic_u32::U32Target; use plonky2::hash::hash_types::RichField; use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::{BoolTarget, Target}; @@ -9,6 +8,9 @@ use plonky2::iop::witness::{PartitionWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::PrimeField; +use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; +use plonky2_u32::gadgets::multiple_comparison::list_le_u32_circuit; +use plonky2_u32::witness::{generated_values_set_u32_target, witness_set_u32_target}; #[derive(Clone, Debug)] pub struct BigUintTarget { @@ -124,7 +126,7 @@ impl, const D: usize> CircuitBuilderBiguint fn cmp_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BoolTarget { let (a, b) = self.pad_biguints(a, b); - self.list_le_u32(a.limbs, b.limbs) + list_le_u32_circuit(self, a.limbs, b.limbs) } fn add_virtual_biguint_target(&mut self, num_limbs: usize) -> BigUintTarget { @@ -289,7 +291,7 @@ pub fn witness_set_biguint_target, F: PrimeField>( assert!(target.num_limbs() >= limbs.len()); limbs.resize(target.num_limbs(), 0); for i in 0..target.num_limbs() { - witness.set_u32_target(target.limbs[i], limbs[i]); + witness_set_u32_target(witness, target.limbs[i], limbs[i]); } } @@ -302,7 +304,7 @@ pub fn buffer_set_biguint_target( assert!(target.num_limbs() >= limbs.len()); limbs.resize(target.num_limbs(), 0); for i in 0..target.num_limbs() { - buffer.set_u32_target(target.get_limb(i), limbs[i]); + generated_values_set_u32_target(buffer, target.get_limb(i), limbs[i]); } } diff --git a/ecdsa/src/gadgets/curve_windowed_mul.rs b/ecdsa/src/gadgets/curve_windowed_mul.rs index 05c2c58a..62437f67 100644 --- a/ecdsa/src/gadgets/curve_windowed_mul.rs +++ b/ecdsa/src/gadgets/curve_windowed_mul.rs @@ -1,7 +1,6 @@ use std::marker::PhantomData; use num::BigUint; -use plonky2::gadgets::arithmetic_u32::U32Target; use plonky2::hash::hash_types::RichField; use plonky2::hash::keccak::KeccakHash; use plonky2::iop::target::{BoolTarget, Target}; @@ -9,6 +8,7 @@ use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{GenericHashOut, Hasher}; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::Field; +use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; use crate::curve::curve_types::{Curve, CurveScalar}; use crate::gadgets::biguint::BigUintTarget; diff --git a/ecdsa/src/gadgets/nonnative.rs b/ecdsa/src/gadgets/nonnative.rs index 76f23f3f..0ff3e1fa 100644 --- a/ecdsa/src/gadgets/nonnative.rs +++ b/ecdsa/src/gadgets/nonnative.rs @@ -1,7 +1,6 @@ use std::marker::PhantomData; use num::{BigUint, Integer, One, Zero}; -use plonky2::gadgets::arithmetic_u32::U32Target; use plonky2::hash::hash_types::RichField; use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::{BoolTarget, Target}; @@ -9,6 +8,9 @@ use plonky2::iop::witness::PartitionWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::field_types::PrimeField; use plonky2_field::{extension_field::Extendable, field_types::Field}; +use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; +use plonky2_u32::gadgets::range_check::range_check_u32_circuit; +use plonky2_u32::witness::generated_values_set_u32_target; use plonky2_util::ceil_div_usize; use crate::gadgets::biguint::{ @@ -249,8 +251,8 @@ impl, const D: usize> CircuitBuilderNonNative _phantom: PhantomData, }); - self.range_check_u32(sum.value.limbs.clone()); - self.range_check_u32(vec![overflow]); + range_check_u32_circuit(self, sum.value.limbs.clone()); + range_check_u32_circuit(self, vec![overflow]); let sum_expected = summands .iter() @@ -290,7 +292,7 @@ impl, const D: usize> CircuitBuilderNonNative _phantom: PhantomData, }); - self.range_check_u32(diff.value.limbs.clone()); + range_check_u32_circuit(self, diff.value.limbs.clone()); self.assert_bool(overflow); let diff_plus_b = self.add_biguint(&diff.value, &b.value); @@ -321,8 +323,8 @@ impl, const D: usize> CircuitBuilderNonNative _phantom: PhantomData, }); - self.range_check_u32(prod.value.limbs.clone()); - self.range_check_u32(overflow.limbs.clone()); + range_check_u32_circuit(self, prod.value.limbs.clone()); + range_check_u32_circuit(self, overflow.limbs.clone()); let prod_expected = self.mul_biguint(&a.value, &b.value); @@ -523,7 +525,7 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat let overflow = overflow_biguint.to_u64_digits()[0] as u32; buffer_set_biguint_target(out_buffer, &self.sum.value, &sum_reduced); - out_buffer.set_u32_target(self.overflow, overflow); + generated_values_set_u32_target(out_buffer, self.overflow, overflow); } } diff --git a/ecdsa/src/gadgets/split_nonnative.rs b/ecdsa/src/gadgets/split_nonnative.rs index e79438f8..60e765c1 100644 --- a/ecdsa/src/gadgets/split_nonnative.rs +++ b/ecdsa/src/gadgets/split_nonnative.rs @@ -1,12 +1,12 @@ use std::marker::PhantomData; use itertools::Itertools; -use plonky2::gadgets::arithmetic_u32::U32Target; use plonky2::hash::hash_types::RichField; use plonky2::iop::target::Target; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::Field; +use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; use crate::gadgets::biguint::BigUintTarget; use crate::gadgets::nonnative::NonNativeTarget; diff --git a/plonky2/Cargo.toml b/plonky2/Cargo.toml index af82a622..b7c95034 100644 --- a/plonky2/Cargo.toml +++ b/plonky2/Cargo.toml @@ -13,7 +13,6 @@ default-run = "generate_constants" [dependencies] plonky2_field = { path = "../field" } plonky2_util = { path = "../util" } -array_tool = "1.0.3" env_logger = "0.9.0" log = "0.4.14" itertools = "0.10.0" diff --git a/plonky2/src/gadgets/mod.rs b/plonky2/src/gadgets/mod.rs index d8613337..6309eb3d 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -1,9 +1,7 @@ pub mod arithmetic; pub mod arithmetic_extension; -pub mod arithmetic_u32; pub mod hash; pub mod interpolation; -pub mod multiple_comparison; pub mod polynomial; pub mod random_access; pub mod range_check; diff --git a/plonky2/src/gadgets/multiple_comparison.rs b/plonky2/src/gadgets/multiple_comparison.rs deleted file mode 100644 index 434fb6c1..00000000 --- a/plonky2/src/gadgets/multiple_comparison.rs +++ /dev/null @@ -1,142 +0,0 @@ -use plonky2_field::extension_field::Extendable; -use plonky2_util::ceil_div_usize; - -use super::arithmetic_u32::U32Target; -use crate::gates::comparison::ComparisonGate; -use crate::hash::hash_types::RichField; -use crate::iop::target::{BoolTarget, Target}; -use crate::plonk::circuit_builder::CircuitBuilder; - -impl, const D: usize> CircuitBuilder { - /// Returns true if a is less than or equal to b, considered as base-`2^num_bits` limbs of a large value. - /// This range-checks its inputs. - pub fn list_le(&mut self, a: Vec, b: Vec, num_bits: usize) -> BoolTarget { - assert_eq!( - a.len(), - b.len(), - "Comparison must be between same number of inputs and outputs" - ); - let n = a.len(); - - let chunk_bits = 2; - let num_chunks = ceil_div_usize(num_bits, chunk_bits); - - let one = self.one(); - let mut result = one; - for i in 0..n { - let a_le_b_gate = ComparisonGate::new(num_bits, num_chunks); - let a_le_b_gate_index = self.add_gate(a_le_b_gate.clone(), vec![]); - self.connect( - Target::wire(a_le_b_gate_index, a_le_b_gate.wire_first_input()), - a[i], - ); - self.connect( - Target::wire(a_le_b_gate_index, a_le_b_gate.wire_second_input()), - b[i], - ); - let a_le_b_result = Target::wire(a_le_b_gate_index, a_le_b_gate.wire_result_bool()); - - let b_le_a_gate = ComparisonGate::new(num_bits, num_chunks); - let b_le_a_gate_index = self.add_gate(b_le_a_gate.clone(), vec![]); - self.connect( - Target::wire(b_le_a_gate_index, b_le_a_gate.wire_first_input()), - b[i], - ); - self.connect( - Target::wire(b_le_a_gate_index, b_le_a_gate.wire_second_input()), - a[i], - ); - let b_le_a_result = Target::wire(b_le_a_gate_index, b_le_a_gate.wire_result_bool()); - - let these_limbs_equal = self.mul(a_le_b_result, b_le_a_result); - let these_limbs_less_than = self.sub(one, b_le_a_result); - result = self.mul_add(these_limbs_equal, result, these_limbs_less_than); - } - - // `result` being boolean is an invariant, maintained because its new value is always - // `x * result + y`, where `x` and `y` are booleans that are not simultaneously true. - BoolTarget::new_unsafe(result) - } - - /// Helper function for comparing, specifically, lists of `U32Target`s. - pub fn list_le_u32(&mut self, a: Vec, b: Vec) -> BoolTarget { - let a_targets: Vec = a.iter().map(|&t| t.0).collect(); - let b_targets: Vec = b.iter().map(|&t| t.0).collect(); - - self.list_le(a_targets, b_targets, 32) - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use num::BigUint; - use plonky2_field::field_types::Field; - use rand::Rng; - - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - fn test_list_le(size: usize, num_bits: usize) -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let config = CircuitConfig::standard_recursion_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let mut rng = rand::thread_rng(); - - let lst1: Vec = (0..size) - .map(|_| rng.gen_range(0..(1 << num_bits))) - .collect(); - let lst2: Vec = (0..size) - .map(|_| rng.gen_range(0..(1 << num_bits))) - .collect(); - - let a_biguint = BigUint::from_slice( - &lst1 - .iter() - .flat_map(|&x| [x as u32, (x >> 32) as u32]) - .collect::>(), - ); - let b_biguint = BigUint::from_slice( - &lst2 - .iter() - .flat_map(|&x| [x as u32, (x >> 32) as u32]) - .collect::>(), - ); - - let a = lst1 - .iter() - .map(|&x| builder.constant(F::from_canonical_u64(x))) - .collect(); - let b = lst2 - .iter() - .map(|&x| builder.constant(F::from_canonical_u64(x))) - .collect(); - - let result = builder.list_le(a, b, num_bits); - - let expected_result = builder.constant_bool(a_biguint <= b_biguint); - builder.connect(result.target, expected_result.target); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_multiple_comparison() -> Result<()> { - for size in [1, 3, 6] { - for num_bits in [20, 32, 40, 44] { - test_list_le(size, num_bits).unwrap(); - } - } - - Ok(()) - } -} diff --git a/plonky2/src/gadgets/range_check.rs b/plonky2/src/gadgets/range_check.rs index 0776fc68..f00578e8 100644 --- a/plonky2/src/gadgets/range_check.rs +++ b/plonky2/src/gadgets/range_check.rs @@ -1,7 +1,5 @@ use plonky2_field::extension_field::Extendable; -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gates::range_check_u32::U32RangeCheckGate; use crate::hash::hash_types::RichField; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::{BoolTarget, Target}; @@ -44,19 +42,6 @@ impl, const D: usize> CircuitBuilder { (low, high) } - pub fn range_check_u32(&mut self, vals: Vec) { - let num_input_limbs = vals.len(); - let gate = U32RangeCheckGate::::new(num_input_limbs); - let gate_index = self.add_gate(gate, vec![]); - - for i in 0..num_input_limbs { - self.connect( - Target::wire(gate_index, gate.wire_ith_input_limb(i)), - vals[i].0, - ); - } - } - pub fn assert_bool(&mut self, b: BoolTarget) { let z = self.mul_sub(b.target, b.target, b.target); let zero = self.zero(); diff --git a/plonky2/src/gates/mod.rs b/plonky2/src/gates/mod.rs index 7a08e709..d02f2978 100644 --- a/plonky2/src/gates/mod.rs +++ b/plonky2/src/gates/mod.rs @@ -1,13 +1,10 @@ // Gates have `new` methods that return `GateRef`s. #![allow(clippy::new_ret_no_self)] -pub mod add_many_u32; pub mod arithmetic_base; pub mod arithmetic_extension; -pub mod arithmetic_u32; pub mod assert_le; pub mod base_sum; -pub mod comparison; pub mod constant; pub mod exponentiation; pub mod gate; @@ -15,17 +12,14 @@ pub mod interpolation; pub mod low_degree_interpolation; pub mod multiplication_extension; pub mod noop; -mod packed_util; +pub mod packed_util; pub mod poseidon; pub(crate) mod poseidon_mds; pub(crate) mod public_input; pub mod random_access; -pub mod range_check_u32; pub mod reducing; pub mod reducing_extension; pub(crate) mod selectors; -pub mod subtraction_u32; -pub mod switch; pub mod util; // Can't use #[cfg(test)] here because it needs to be visible to other crates. diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 5fed3c8f..5dcd7ffc 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -4,7 +4,6 @@ use std::marker::PhantomData; use plonky2_field::extension_field::{Extendable, FieldExtension}; use plonky2_field::field_types::Field; -use crate::gadgets::arithmetic_u32::U32Target; use crate::hash::hash_types::{HashOut, HashOutTarget, RichField}; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; @@ -162,10 +161,6 @@ impl GeneratedValues { self.set_target(target.target, F::from_bool(value)) } - pub fn set_u32_target(&mut self, target: U32Target, value: u32) { - self.set_target(target.0, F::from_canonical_u32(value)) - } - pub fn set_hash_target(&mut self, ht: HashOutTarget, value: HashOut) { ht.elements .iter() diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 4a565d02..6b6a98d5 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -6,7 +6,6 @@ use plonky2_field::field_types::Field; use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::witness_util::set_fri_proof_target; -use crate::gadgets::arithmetic_u32::U32Target; use crate::hash::hash_types::HashOutTarget; use crate::hash::hash_types::RichField; use crate::hash::hash_types::{HashOut, MerkleCapTarget}; @@ -128,10 +127,6 @@ pub trait Witness { self.set_target(target.target, F::from_bool(value)) } - fn set_u32_target(&mut self, target: U32Target, value: u32) { - self.set_target(target.0, F::from_canonical_u32(value)) - } - /// Set the targets in a `ProofWithPublicInputsTarget` to their corresponding values in a /// `ProofWithPublicInputs`. fn set_proof_with_pis_target, const D: usize>( diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 2c9b740b..1c2282d9 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -14,7 +14,6 @@ use crate::fri::oracle::PolynomialBatch; use crate::fri::{FriConfig, FriParams}; use crate::gadgets::arithmetic::BaseArithmeticOperation; use crate::gadgets::arithmetic_extension::ExtensionArithmeticOperation; -use crate::gadgets::arithmetic_u32::U32Target; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::arithmetic_extension::ArithmeticExtensionGate; @@ -362,11 +361,6 @@ impl, const D: usize> CircuitBuilder { } } - /// Returns a U32Target for the value `c`, which is assumed to be at most 32 bits. - pub fn constant_u32(&mut self, c: u32) -> U32Target { - U32Target(self.constant(F::from_canonical_u32(c))) - } - /// If the given target is a constant (i.e. it was created by the `constant(F)` method), returns /// its constant value. Otherwise, returns `None`. pub fn target_as_constant(&self, target: Target) -> Option { diff --git a/plonky2_u32/Cargo.toml b/plonky2_u32/Cargo.toml new file mode 100644 index 00000000..f0a1d349 --- /dev/null +++ b/plonky2_u32/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "plonky2_u32" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.40" +rand = "0.8.4" +num = { version = "0.4", features = [ "rand" ] } +itertools = "0.10.0" +plonky2 = { path = "../plonky2" } +plonky2_util = { path = "../util" } +plonky2_field = { path = "../field" } diff --git a/plonky2/src/gadgets/arithmetic_u32.rs b/plonky2_u32/src/gadgets/arithmetic_u32.rs similarity index 69% rename from plonky2/src/gadgets/arithmetic_u32.rs rename to plonky2_u32/src/gadgets/arithmetic_u32.rs index 8a6d7296..2b494a52 100644 --- a/plonky2/src/gadgets/arithmetic_u32.rs +++ b/plonky2_u32/src/gadgets/arithmetic_u32.rs @@ -1,51 +1,104 @@ use std::marker::PhantomData; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; use crate::gates::add_many_u32::U32AddManyGate; use crate::gates::arithmetic_u32::U32ArithmeticGate; use crate::gates::subtraction_u32::U32SubtractionGate; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::Target; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; +use crate::witness::generated_values_set_u32_target; #[derive(Clone, Copy, Debug)] pub struct U32Target(pub Target); -impl, const D: usize> CircuitBuilder { - pub fn add_virtual_u32_target(&mut self) -> U32Target { +pub trait CircuitBuilderU32, const D: usize> { + fn add_virtual_u32_target(&mut self) -> U32Target; + + fn add_virtual_u32_targets(&mut self, n: usize) -> Vec; + + /// Returns a U32Target for the value `c`, which is assumed to be at most 32 bits. + fn constant_u32(&mut self, c: u32) -> U32Target; + + fn zero_u32(&mut self) -> U32Target; + + fn one_u32(&mut self) -> U32Target; + + fn connect_u32(&mut self, x: U32Target, y: U32Target); + + fn assert_zero_u32(&mut self, x: U32Target); + + /// Checks for special cases where the value of + /// `x * y + z` + /// can be determined without adding a `U32ArithmeticGate`. + fn arithmetic_u32_special_cases( + &mut self, + x: U32Target, + y: U32Target, + z: U32Target, + ) -> Option<(U32Target, U32Target)>; + + // Returns x * y + z. + fn mul_add_u32(&mut self, x: U32Target, y: U32Target, z: U32Target) -> (U32Target, U32Target); + + fn add_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target); + + fn add_many_u32(&mut self, to_add: &[U32Target]) -> (U32Target, U32Target); + + fn add_u32s_with_carry( + &mut self, + to_add: &[U32Target], + carry: U32Target, + ) -> (U32Target, U32Target); + + fn mul_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target); + + // Returns x - y - borrow, as a pair (result, borrow), where borrow is 0 or 1 depending on whether borrowing from the next digit is required (iff y + borrow > x). + fn sub_u32(&mut self, x: U32Target, y: U32Target, borrow: U32Target) -> (U32Target, U32Target); +} + +impl, const D: usize> CircuitBuilderU32 + for CircuitBuilder +{ + fn add_virtual_u32_target(&mut self) -> U32Target { U32Target(self.add_virtual_target()) } - pub fn add_virtual_u32_targets(&mut self, n: usize) -> Vec { + fn add_virtual_u32_targets(&mut self, n: usize) -> Vec { self.add_virtual_targets(n) .into_iter() .map(U32Target) .collect() } - pub fn zero_u32(&mut self) -> U32Target { + /// Returns a U32Target for the value `c`, which is assumed to be at most 32 bits. + fn constant_u32(&mut self, c: u32) -> U32Target { + U32Target(self.constant(F::from_canonical_u32(c))) + } + + fn zero_u32(&mut self) -> U32Target { U32Target(self.zero()) } - pub fn one_u32(&mut self) -> U32Target { + fn one_u32(&mut self) -> U32Target { U32Target(self.one()) } - pub fn connect_u32(&mut self, x: U32Target, y: U32Target) { + fn connect_u32(&mut self, x: U32Target, y: U32Target) { self.connect(x.0, y.0) } - pub fn assert_zero_u32(&mut self, x: U32Target) { + fn assert_zero_u32(&mut self, x: U32Target) { self.assert_zero(x.0) } /// Checks for special cases where the value of /// `x * y + z` /// can be determined without adding a `U32ArithmeticGate`. - pub fn arithmetic_u32_special_cases( + fn arithmetic_u32_special_cases( &mut self, x: U32Target, y: U32Target, @@ -72,12 +125,7 @@ impl, const D: usize> CircuitBuilder { } // Returns x * y + z. - pub fn mul_add_u32( - &mut self, - x: U32Target, - y: U32Target, - z: U32Target, - ) -> (U32Target, U32Target) { + fn mul_add_u32(&mut self, x: U32Target, y: U32Target, z: U32Target) -> (U32Target, U32Target) { if let Some(result) = self.arithmetic_u32_special_cases(x, y, z) { return result; } @@ -107,12 +155,12 @@ impl, const D: usize> CircuitBuilder { (output_low, output_high) } - pub fn add_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target) { + fn add_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target) { let one = self.one_u32(); self.mul_add_u32(a, one, b) } - pub fn add_many_u32(&mut self, to_add: &[U32Target]) -> (U32Target, U32Target) { + fn add_many_u32(&mut self, to_add: &[U32Target]) -> (U32Target, U32Target) { match to_add.len() { 0 => (self.zero_u32(), self.zero_u32()), 1 => (to_add[0], self.zero_u32()), @@ -142,7 +190,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn add_u32s_with_carry( + fn add_u32s_with_carry( &mut self, to_add: &[U32Target], carry: U32Target, @@ -170,18 +218,13 @@ impl, const D: usize> CircuitBuilder { (output, output_carry) } - pub fn mul_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target) { + fn mul_u32(&mut self, a: U32Target, b: U32Target) -> (U32Target, U32Target) { let zero = self.zero_u32(); self.mul_add_u32(a, b, zero) } // Returns x - y - borrow, as a pair (result, borrow), where borrow is 0 or 1 depending on whether borrowing from the next digit is required (iff y + borrow > x). - pub fn sub_u32( - &mut self, - x: U32Target, - y: U32Target, - borrow: U32Target, - ) -> (U32Target, U32Target) { + fn sub_u32(&mut self, x: U32Target, y: U32Target, borrow: U32Target) -> (U32Target, U32Target) { let gate = U32SubtractionGate::::new_from_config(&self.config); let (gate_index, copy) = self.find_slot(gate, &[], &[]); @@ -220,21 +263,21 @@ impl, const D: usize> SimpleGenerator let low = x_u64 as u32; let high = (x_u64 >> 32) as u32; - out_buffer.set_u32_target(self.low, low); - out_buffer.set_u32_target(self.high, high); + generated_values_set_u32_target(out_buffer, self.low, low); + generated_values_set_u32_target(out_buffer, self.high, high); } } #[cfg(test)] mod tests { use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use rand::{thread_rng, Rng}; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; + use crate::gadgets::arithmetic_u32::CircuitBuilderU32; #[test] pub fn test_add_many_u32s() -> Result<()> { @@ -267,6 +310,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/plonky2_u32/src/gadgets/mod.rs b/plonky2_u32/src/gadgets/mod.rs new file mode 100644 index 00000000..622242ea --- /dev/null +++ b/plonky2_u32/src/gadgets/mod.rs @@ -0,0 +1,3 @@ +pub mod arithmetic_u32; +pub mod multiple_comparison; +pub mod range_check; diff --git a/plonky2_u32/src/gadgets/multiple_comparison.rs b/plonky2_u32/src/gadgets/multiple_comparison.rs new file mode 100644 index 00000000..b2f9709a --- /dev/null +++ b/plonky2_u32/src/gadgets/multiple_comparison.rs @@ -0,0 +1,149 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2_field::extension_field::Extendable; +use plonky2_util::ceil_div_usize; + +use super::arithmetic_u32::U32Target; +use crate::gates::comparison::ComparisonGate; + +/// Returns true if a is less than or equal to b, considered as base-`2^num_bits` limbs of a large value. +/// This range-checks its inputs. +pub fn list_le_circuit, const D: usize>( + builder: &mut CircuitBuilder, + a: Vec, + b: Vec, + num_bits: usize, +) -> BoolTarget { + assert_eq!( + a.len(), + b.len(), + "Comparison must be between same number of inputs and outputs" + ); + let n = a.len(); + + let chunk_bits = 2; + let num_chunks = ceil_div_usize(num_bits, chunk_bits); + + let one = builder.one(); + let mut result = one; + for i in 0..n { + let a_le_b_gate = ComparisonGate::new(num_bits, num_chunks); + let a_le_b_gate_index = builder.add_gate(a_le_b_gate.clone(), vec![]); + builder.connect( + Target::wire(a_le_b_gate_index, a_le_b_gate.wire_first_input()), + a[i], + ); + builder.connect( + Target::wire(a_le_b_gate_index, a_le_b_gate.wire_second_input()), + b[i], + ); + let a_le_b_result = Target::wire(a_le_b_gate_index, a_le_b_gate.wire_result_bool()); + + let b_le_a_gate = ComparisonGate::new(num_bits, num_chunks); + let b_le_a_gate_index = builder.add_gate(b_le_a_gate.clone(), vec![]); + builder.connect( + Target::wire(b_le_a_gate_index, b_le_a_gate.wire_first_input()), + b[i], + ); + builder.connect( + Target::wire(b_le_a_gate_index, b_le_a_gate.wire_second_input()), + a[i], + ); + let b_le_a_result = Target::wire(b_le_a_gate_index, b_le_a_gate.wire_result_bool()); + + let these_limbs_equal = builder.mul(a_le_b_result, b_le_a_result); + let these_limbs_less_than = builder.sub(one, b_le_a_result); + result = builder.mul_add(these_limbs_equal, result, these_limbs_less_than); + } + + // `result` being boolean is an invariant, maintained because its new value is always + // `x * result + y`, where `x` and `y` are booleans that are not simultaneously true. + BoolTarget::new_unsafe(result) +} + +/// Helper function for comparing, specifically, lists of `U32Target`s. +pub fn list_le_u32_circuit, const D: usize>( + builder: &mut CircuitBuilder, + a: Vec, + b: Vec, +) -> BoolTarget { + let a_targets: Vec = a.iter().map(|&t| t.0).collect(); + let b_targets: Vec = b.iter().map(|&t| t.0).collect(); + + list_le_circuit(builder, a_targets, b_targets, 32) +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use num::BigUint; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2_field::field_types::Field; + use rand::Rng; + + use crate::gadgets::multiple_comparison::list_le_circuit; + + fn test_list_le(size: usize, num_bits: usize) -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let config = CircuitConfig::standard_recursion_config(); + let pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let mut rng = rand::thread_rng(); + + let lst1: Vec = (0..size) + .map(|_| rng.gen_range(0..(1 << num_bits))) + .collect(); + let lst2: Vec = (0..size) + .map(|_| rng.gen_range(0..(1 << num_bits))) + .collect(); + + let a_biguint = BigUint::from_slice( + &lst1 + .iter() + .flat_map(|&x| [x as u32, (x >> 32) as u32]) + .collect::>(), + ); + let b_biguint = BigUint::from_slice( + &lst2 + .iter() + .flat_map(|&x| [x as u32, (x >> 32) as u32]) + .collect::>(), + ); + + let a = lst1 + .iter() + .map(|&x| builder.constant(F::from_canonical_u64(x))) + .collect(); + let b = lst2 + .iter() + .map(|&x| builder.constant(F::from_canonical_u64(x))) + .collect(); + + let result = list_le_circuit(&mut builder, a, b, num_bits); + + let expected_result = builder.constant_bool(a_biguint <= b_biguint); + builder.connect(result.target, expected_result.target); + + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + data.verify(proof) + } + + #[test] + fn test_multiple_comparison() -> Result<()> { + for size in [1, 3, 6] { + for num_bits in [20, 32, 40, 44] { + test_list_le(size, num_bits).unwrap(); + } + } + + Ok(()) + } +} diff --git a/plonky2_u32/src/gadgets/range_check.rs b/plonky2_u32/src/gadgets/range_check.rs new file mode 100644 index 00000000..a6c4a50c --- /dev/null +++ b/plonky2_u32/src/gadgets/range_check.rs @@ -0,0 +1,23 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::iop::target::Target; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2_field::extension_field::Extendable; + +use crate::gadgets::arithmetic_u32::U32Target; +use crate::gates::range_check_u32::U32RangeCheckGate; + +pub fn range_check_u32_circuit, const D: usize>( + builder: &mut CircuitBuilder, + vals: Vec, +) { + let num_input_limbs = vals.len(); + let gate = U32RangeCheckGate::::new(num_input_limbs); + let gate_index = builder.add_gate(gate, vec![]); + + for i in 0..num_input_limbs { + builder.connect( + Target::wire(gate_index, gate.wire_ith_input_limb(i)), + vals[i].0, + ); + } +} diff --git a/plonky2/src/gates/add_many_u32.rs b/plonky2_u32/src/gates/add_many_u32.rs similarity index 93% rename from plonky2/src/gates/add_many_u32.rs rename to plonky2_u32/src/gates/add_many_u32.rs index 4f9c4293..8bfbdfb7 100644 --- a/plonky2/src/gates/add_many_u32.rs +++ b/plonky2_u32/src/gates/add_many_u32.rs @@ -1,22 +1,21 @@ use std::marker::PhantomData; use itertools::unfold; +use plonky2::gates::gate::Gate; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::wire::Wire; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; use plonky2_util::ceil_div_usize; -use crate::field::extension_field::Extendable; -use crate::field::field_types::Field; -use crate::gates::gate::Gate; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::wire::Wire; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::circuit_data::CircuitConfig; -use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; - const LOG2_MAX_NUM_ADDENDS: usize = 4; const MAX_NUM_ADDENDS: usize = 16; @@ -349,17 +348,17 @@ mod tests { use anyhow::Result; use itertools::unfold; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; + use plonky2_field::extension_field::quartic::QuarticExtension; + use plonky2_field::field_types::Field; + use plonky2_field::goldilocks_field::GoldilocksField; use rand::Rng; - use crate::field::extension_field::quartic::QuarticExtension; - use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::gates::add_many_u32::U32AddManyGate; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn low_degree() { diff --git a/plonky2/src/gates/arithmetic_u32.rs b/plonky2_u32/src/gates/arithmetic_u32.rs similarity index 95% rename from plonky2/src/gates/arithmetic_u32.rs rename to plonky2_u32/src/gates/arithmetic_u32.rs index dc03e296..977f86a2 100644 --- a/plonky2/src/gates/arithmetic_u32.rs +++ b/plonky2_u32/src/gates/arithmetic_u32.rs @@ -1,25 +1,24 @@ use std::marker::PhantomData; use itertools::unfold; -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; -use plonky2_field::packed_field::PackedField; - -use crate::gates::gate::Gate; -use crate::gates::packed_util::PackedEvaluableBase; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::wire::Wire; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::circuit_data::CircuitConfig; -use crate::plonk::vars::{ +use plonky2::gates::gate::Gate; +use plonky2::gates::packed_util::PackedEvaluableBase; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::wire::Wire; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; +use plonky2_field::packed_field::PackedField; /// A gate to perform a basic mul-add on 32-bit values (we assume they are range-checked beforehand). #[derive(Copy, Clone, Debug)] @@ -349,16 +348,16 @@ mod tests { use std::marker::PhantomData; use anyhow::Result; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; use plonky2_field::field_types::Field; use plonky2_field::goldilocks_field::GoldilocksField; use rand::Rng; use crate::gates::arithmetic_u32::U32ArithmeticGate; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn low_degree() { diff --git a/plonky2/src/gates/comparison.rs b/plonky2_u32/src/gates/comparison.rs similarity index 96% rename from plonky2/src/gates/comparison.rs rename to plonky2_u32/src/gates/comparison.rs index b1cf7b98..3ddfcf24 100644 --- a/plonky2/src/gates/comparison.rs +++ b/plonky2_u32/src/gates/comparison.rs @@ -1,26 +1,25 @@ use std::marker::PhantomData; +use plonky2::gates::gate::Gate; +use plonky2::gates::packed_util::PackedEvaluableBase; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::wire::Wire; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive}; +use plonky2::plonk::vars::{ + EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, + EvaluationVarsBasePacked, +}; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::{Field, Field64}; use plonky2_field::packed_field::PackedField; use plonky2_util::{bits_u64, ceil_div_usize}; -use crate::gates::gate::Gate; -use crate::gates::packed_util::PackedEvaluableBase; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::wire::Wire; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive}; -use crate::plonk::vars::{ - EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, - EvaluationVarsBasePacked, -}; - /// A gate for checking that one value is less than or equal to another. #[derive(Clone, Debug)] pub struct ComparisonGate, const D: usize> { @@ -520,17 +519,17 @@ mod tests { use std::marker::PhantomData; use anyhow::Result; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; use plonky2_field::field_types::Field; use plonky2_field::field_types::PrimeField64; use plonky2_field::goldilocks_field::GoldilocksField; use rand::Rng; use crate::gates::comparison::ComparisonGate; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn wire_indices() { diff --git a/plonky2_u32/src/gates/mod.rs b/plonky2_u32/src/gates/mod.rs new file mode 100644 index 00000000..1880b163 --- /dev/null +++ b/plonky2_u32/src/gates/mod.rs @@ -0,0 +1,5 @@ +pub mod add_many_u32; +pub mod arithmetic_u32; +pub mod comparison; +pub mod range_check_u32; +pub mod subtraction_u32; diff --git a/plonky2/src/gates/range_check_u32.rs b/plonky2_u32/src/gates/range_check_u32.rs similarity index 90% rename from plonky2/src/gates/range_check_u32.rs rename to plonky2_u32/src/gates/range_check_u32.rs index 79e91de8..fe7fb43b 100644 --- a/plonky2/src/gates/range_check_u32.rs +++ b/plonky2_u32/src/gates/range_check_u32.rs @@ -1,20 +1,19 @@ use std::marker::PhantomData; +use plonky2::gates::gate::Gate; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive}; +use plonky2::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; use plonky2_util::ceil_div_usize; -use crate::field::extension_field::Extendable; -use crate::field::field_types::Field; -use crate::gates::gate::Gate; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recursive}; -use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; - /// A gate which can decompose a number into base B little-endian limbs. #[derive(Copy, Clone, Debug)] pub struct U32RangeCheckGate, const D: usize> { @@ -220,18 +219,18 @@ mod tests { use anyhow::Result; use itertools::unfold; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; + use plonky2_field::extension_field::quartic::QuarticExtension; + use plonky2_field::field_types::Field; + use plonky2_field::goldilocks_field::GoldilocksField; use plonky2_util::ceil_div_usize; use rand::Rng; - use crate::field::extension_field::quartic::QuarticExtension; - use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::range_check_u32::U32RangeCheckGate; - use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn low_degree() { diff --git a/plonky2/src/gates/subtraction_u32.rs b/plonky2_u32/src/gates/subtraction_u32.rs similarity index 95% rename from plonky2/src/gates/subtraction_u32.rs rename to plonky2_u32/src/gates/subtraction_u32.rs index b1e4d84f..b362be60 100644 --- a/plonky2/src/gates/subtraction_u32.rs +++ b/plonky2_u32/src/gates/subtraction_u32.rs @@ -1,24 +1,23 @@ use std::marker::PhantomData; -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; -use plonky2_field::packed_field::PackedField; - -use crate::gates::gate::Gate; -use crate::gates::packed_util::PackedEvaluableBase; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::wire::Wire; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::circuit_data::CircuitConfig; -use crate::plonk::vars::{ +use plonky2::gates::gate::Gate; +use plonky2::gates::packed_util::PackedEvaluableBase; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::wire::Wire; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; +use plonky2_field::packed_field::PackedField; /// A gate to perform a subtraction on 32-bit limbs: given `x`, `y`, and `borrow`, it returns /// the result `x - y - borrow` and, if this underflows, a new `borrow`. Inputs are not range-checked. @@ -337,18 +336,18 @@ mod tests { use std::marker::PhantomData; use anyhow::Result; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; use plonky2_field::extension_field::quartic::QuarticExtension; use plonky2_field::field_types::Field; use plonky2_field::field_types::PrimeField64; use plonky2_field::goldilocks_field::GoldilocksField; use rand::Rng; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::subtraction_u32::U32SubtractionGate; - use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn low_degree() { diff --git a/plonky2_u32/src/lib.rs b/plonky2_u32/src/lib.rs new file mode 100644 index 00000000..0957c7bc --- /dev/null +++ b/plonky2_u32/src/lib.rs @@ -0,0 +1,5 @@ +#![allow(clippy::needless_range_loop)] + +pub mod gadgets; +pub mod gates; +pub mod witness; diff --git a/plonky2_u32/src/witness.rs b/plonky2_u32/src/witness.rs new file mode 100644 index 00000000..44b13a81 --- /dev/null +++ b/plonky2_u32/src/witness.rs @@ -0,0 +1,21 @@ +use plonky2::iop::generator::GeneratedValues; +use plonky2::iop::witness::Witness; +use plonky2_field::field_types::Field; + +use crate::gadgets::arithmetic_u32::U32Target; + +pub fn generated_values_set_u32_target( + buffer: &mut GeneratedValues, + target: U32Target, + value: u32, +) { + buffer.set_target(target.0, F::from_canonical_u32(value)) +} + +pub fn witness_set_u32_target, F: Field>( + witness: &mut W, + target: U32Target, + value: u32, +) { + witness.set_target(target.0, F::from_canonical_u32(value)) +} diff --git a/waksman/Cargo.toml b/waksman/Cargo.toml index 2fe030a9..5aa25dc9 100644 --- a/waksman/Cargo.toml +++ b/waksman/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" [dependencies] "plonky2" = { path = "../plonky2" } +"plonky2_field" = { path = "../field" } "plonky2_util" = { path = "../util" } anyhow = "1.0.40" bimap = "0.6.1" itertools = "0.10.0" rand = "0.8.4" +array_tool = "1.0.3" diff --git a/waksman/src/gates/mod.rs b/waksman/src/gates/mod.rs new file mode 100644 index 00000000..5a2a8f48 --- /dev/null +++ b/waksman/src/gates/mod.rs @@ -0,0 +1 @@ +pub mod switch; diff --git a/plonky2/src/gates/switch.rs b/waksman/src/gates/switch.rs similarity index 95% rename from plonky2/src/gates/switch.rs rename to waksman/src/gates/switch.rs index bd298762..12410c59 100644 --- a/plonky2/src/gates/switch.rs +++ b/waksman/src/gates/switch.rs @@ -1,25 +1,24 @@ use std::marker::PhantomData; use array_tool::vec::Union; -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; -use plonky2_field::packed_field::PackedField; - -use crate::gates::gate::Gate; -use crate::gates::packed_util::PackedEvaluableBase; -use crate::gates::util::StridedConstraintConsumer; -use crate::hash::hash_types::RichField; -use crate::iop::ext_target::ExtensionTarget; -use crate::iop::generator::{GeneratedValues, WitnessGenerator}; -use crate::iop::target::Target; -use crate::iop::wire::Wire; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::circuit_data::CircuitConfig; -use crate::plonk::vars::{ +use plonky2::gates::gate::Gate; +use plonky2::gates::packed_util::PackedEvaluableBase; +use plonky2::gates::util::StridedConstraintConsumer; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::generator::{GeneratedValues, WitnessGenerator}; +use plonky2::iop::target::Target; +use plonky2::iop::wire::Wire; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::vars::{ EvaluationTargets, EvaluationVars, EvaluationVarsBase, EvaluationVarsBaseBatch, EvaluationVarsBasePacked, }; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; +use plonky2_field::packed_field::PackedField; /// A gate for conditionally swapping input values based on a boolean. #[derive(Copy, Clone, Debug)] @@ -332,16 +331,16 @@ mod tests { use std::marker::PhantomData; use anyhow::Result; + use plonky2::gates::gate::Gate; + use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; + use plonky2::hash::hash_types::HashOut; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::vars::EvaluationVars; use plonky2_field::field_types::Field; use plonky2_field::goldilocks_field::GoldilocksField; - use crate::gates::gate::Gate; - use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::switch::SwitchGate; - use crate::hash::hash_types::HashOut; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::vars::EvaluationVars; #[test] fn wire_indices() { diff --git a/waksman/src/lib.rs b/waksman/src/lib.rs index 1c2cc7cb..e9b0d4c5 100644 --- a/waksman/src/lib.rs +++ b/waksman/src/lib.rs @@ -6,5 +6,6 @@ #![allow(clippy::return_self_not_must_use)] pub mod bimap; +pub mod gates; pub mod permutation; pub mod sorting; diff --git a/waksman/src/permutation.rs b/waksman/src/permutation.rs index b25c2980..9a94b77c 100644 --- a/waksman/src/permutation.rs +++ b/waksman/src/permutation.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::marker::PhantomData; use plonky2::field::{extension_field::Extendable, field_types::Field}; -use plonky2::gates::switch::SwitchGate; use plonky2::hash::hash_types::RichField; use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::Target; @@ -10,6 +9,7 @@ use plonky2::iop::witness::{PartitionWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; use crate::bimap::bimap_from_lists; +use crate::gates::switch::SwitchGate; /// Assert that two lists of expressions evaluate to permutations of one another. pub fn assert_permutation, const D: usize>(