diff --git a/plonky2/src/batch_fri/oracle.rs b/plonky2/src/batch_fri/oracle.rs index 58deeaa3c..1f34cfef3 100644 --- a/plonky2/src/batch_fri/oracle.rs +++ b/plonky2/src/batch_fri/oracle.rs @@ -460,7 +460,7 @@ mod test { &fri_instances, &fri_openings, &fri_challenges, - &[merkle_cap.clone()], + std::slice::from_ref(&merkle_cap), &proof, &fri_params, )?; diff --git a/plonky2/src/fri/validate_shape.rs b/plonky2/src/fri/validate_shape.rs index be675ed61..8805478f6 100644 --- a/plonky2/src/fri/validate_shape.rs +++ b/plonky2/src/fri/validate_shape.rs @@ -20,7 +20,7 @@ where F: RichField + Extendable, C: GenericConfig, { - validate_batch_fri_proof_shape::(proof, &[instance.clone()], params) + validate_batch_fri_proof_shape::(proof, std::slice::from_ref(instance), params) } pub(crate) fn validate_batch_fri_proof_shape( diff --git a/plonky2/src/gates/addition_base.rs b/plonky2/src/gates/addition_base.rs index ca7e95673..38cc04a9b 100644 --- a/plonky2/src/gates/addition_base.rs +++ b/plonky2/src/gates/addition_base.rs @@ -1,7 +1,5 @@ extern crate alloc; use alloc::string::ToString; -#[cfg(not(feature = "std"))] -use alloc::{format, string::String, vec::Vec}; use anyhow::Result; @@ -242,12 +240,20 @@ impl, const D: usize> SimpleGenerator #[cfg(test)] mod tests { use anyhow::Result; + use plonky2_field::types::Sample; use crate::field::goldilocks_field::GoldilocksField; + use crate::field::types::Field; + #[allow(unused_imports)] + use crate::field::types::Field64; use crate::gates::addition_base::AdditionGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::plonk::circuit_data::CircuitConfig; + use crate::iop::target::Target; + use crate::iop::witness::{PartialWitness, WitnessWrite}; + use crate::plonk::circuit_builder::CircuitBuilder; + use crate::plonk::circuit_data::{CircuitConfig, CircuitData}; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::util::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer}; #[test] fn low_degree() { @@ -263,4 +269,199 @@ mod tests { let gate = AdditionGate::new_from_config(&CircuitConfig::standard_recursion_config()); test_eval_fns::(gate) } + + #[test] + fn test_success() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) -> Result<()> { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = AdditionGate::new_from_config(&config); + let constants = [F::ONE, F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, AdditionGate::wire_ith_addend_0(i)); + let wire_y = Target::wire(gate_row, AdditionGate::wire_ith_addend_1(i)); + let wire_output = Target::wire(gate_row, AdditionGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + + let mut pw = PartialWitness::new(); + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 + value2; + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + pw.set_target(*output_value, expected)?; + } + + let proof = circuit_data.prove(pw)?; + circuit_data.verify(proof)?; + + Ok(()) + } + + flag_test(63)?; // flag enabled + flag_test(62)?; // flag disabled + + Ok(()) + } + + #[test] + #[should_panic] + fn test_failure() { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = AdditionGate::new_from_config(&config); + let constants = [F::ONE, F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, AdditionGate::wire_ith_addend_0(i)); + let wire_y = Target::wire(gate_row, AdditionGate::wire_ith_addend_1(i)); + let wire_output = Target::wire(gate_row, AdditionGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + + let mut pw = PartialWitness::new(); + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 + value2; + let mut incorrect_value = F::rand(); + while incorrect_value == expected { + incorrect_value = F::rand(); + } + pw.set_target(*x, value1).unwrap(); + pw.set_target(*y, value2).unwrap(); + pw.set_target(*output_value, incorrect_value).unwrap(); + } + + let proof = circuit_data.prove(pw).unwrap(); + circuit_data.verify(proof).unwrap(); + } + + flag_test(63); // flag enabled + flag_test(62); // flag disabled + } + + #[test] + fn test_serialization_addition() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = AdditionGate::new_from_config(&config); + let constants = [F::ONE, F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, AdditionGate::wire_ith_addend_0(i)); + let wire_y = Target::wire(gate_row, AdditionGate::wire_ith_addend_1(i)); + let wire_output = Target::wire(gate_row, AdditionGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + // let filename = "test_circuit"; + let gate_serializer = DefaultGateSerializer; + let generator_serializer = DefaultGeneratorSerializer::::default(); + + let data_bytes = circuit_data + .to_bytes(&gate_serializer, &generator_serializer) + .map_err(|_| anyhow::Error::msg("Serialization failed."))?; + + // fs::write(filename, &data_bytes)?; + + // let read_data_bytes = fs::read(filename)?; + + let deserialized_circuit_data = CircuitData::::from_bytes( + &data_bytes, + &gate_serializer, + &generator_serializer, + ) + .map_err(|_| anyhow::Error::msg("Deserialization failed."))?; + + assert_eq!(deserialized_circuit_data, circuit_data); + + let mut pw = PartialWitness::new(); + + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 + value2; + + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + pw.set_target(*output_value, expected)?; + } + + let proof = deserialized_circuit_data.prove(pw.clone())?; + deserialized_circuit_data.verify(proof.clone())?; + + // std::fs::remove_file(filename)?; + + Ok(()) + } } diff --git a/plonky2/src/gates/equality_base.rs b/plonky2/src/gates/equality_base.rs index 50a315e81..b09625c8f 100644 --- a/plonky2/src/gates/equality_base.rs +++ b/plonky2/src/gates/equality_base.rs @@ -283,6 +283,7 @@ impl, const D: usize> SimpleGenerator #[cfg(test)] mod tests { use anyhow::Result; + use plonky2_field::types::Sample; use crate::field::goldilocks_field::GoldilocksField; use crate::field::types::Field; @@ -293,8 +294,9 @@ mod tests { use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::circuit_data::{CircuitConfig, CircuitData}; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::util::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer}; #[test] fn low_degree() { @@ -312,7 +314,7 @@ mod tests { } #[test] - fn test_succes() -> Result<()> { + fn test_succes_initial() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; type F = >::F; @@ -356,4 +358,229 @@ mod tests { Ok(()) } + + #[test] + #[should_panic] + fn test_failure() { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + let gate = EqualityGate::new_from_config(&config); + let ref_gate = gate.clone(); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, ref_gate.wire_ith_element_0(i)); + let wire_y = Target::wire(gate_row, ref_gate.wire_ith_element_1(i)); + let wire_equal = Target::wire(gate_row, ref_gate.wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_equal); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + let mut pw = PartialWitness::new(); + + for (i, (x, y, output_value)) in pairs.iter().enumerate() { + if i < 50 { + let value = F::rand(); + pw.set_target(*x, value).unwrap(); + pw.set_target(*y, value).unwrap(); + let incorrect_value = F::ZERO; + pw.set_target(*output_value, incorrect_value).unwrap(); + } else { + let value1 = F::rand(); + let mut value2 = F::rand(); + + while value2 == value1 { + value2 = F::rand(); + } + + pw.set_target(*x, value1).unwrap(); + pw.set_target(*y, value2).unwrap(); + let incorrect_value = F::ONE; + pw.set_target(*output_value, incorrect_value).unwrap(); + } + } + + let proof = circuit_data.prove(pw).unwrap(); + circuit_data.verify(proof).unwrap(); + } + + flag_test(63); // flag enabled + flag_test(55); // flag disabled + } + + #[test] + fn test_success() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) -> Result<()> { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + let gate = EqualityGate::new_from_config(&config); + let ref_gate = gate.clone(); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, ref_gate.wire_ith_element_0(i)); + let wire_y = Target::wire(gate_row, ref_gate.wire_ith_element_1(i)); + let wire_equal = Target::wire(gate_row, ref_gate.wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_equal); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + let mut pw = PartialWitness::new(); + + for (i, (x, y, output_value)) in pairs.iter().enumerate() { + if i < 50 { + let value = F::rand(); + pw.set_target(*x, value)?; + pw.set_target(*y, value)?; + let expected = F::ONE; + + pw.set_target(*output_value, expected)?; + } else { + let value1 = F::rand(); + let mut value2 = F::rand(); + + while value2 == value1 { + value2 = F::rand(); + } + + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + let expected = F::ZERO; + pw.set_target(*output_value, expected)?; + } + } + + let proof = circuit_data.prove(pw)?; + circuit_data.verify(proof)?; + + Ok(()) + } + + flag_test(63)?; // flag enabled + flag_test(55)?; // flag disabled + + Ok(()) + } + + #[test] + fn test_serialization_equality() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = EqualityGate::new_from_config(&config); + let ref_gate = gate.clone(); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, ref_gate.wire_ith_element_0(i)); + let wire_y = Target::wire(gate_row, ref_gate.wire_ith_element_1(i)); + let wire_equal = Target::wire(gate_row, ref_gate.wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_equal); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + let gate_serializer = DefaultGateSerializer; + let generator_serializer = DefaultGeneratorSerializer::::default(); + + let data_bytes = circuit_data + .to_bytes(&gate_serializer, &generator_serializer) + .map_err(|_| anyhow::Error::msg("Serialization failed."))?; + + let deserialized_circuit_data = CircuitData::::from_bytes( + &data_bytes, + &gate_serializer, + &generator_serializer, + ) + .map_err(|_| anyhow::Error::msg("Deserialization failed."))?; + + assert_eq!(deserialized_circuit_data, circuit_data); + + let mut pw = PartialWitness::new(); + + for (i, (x, y, output_value)) in pairs.iter().enumerate() { + if i < 50 { + let value = F::rand(); + pw.set_target(*x, value)?; + pw.set_target(*y, value)?; + let expected = F::ONE; + + pw.set_target(*output_value, expected)?; + } else { + let value1 = F::rand(); + let mut value2 = F::rand(); + + while value2 == value1 { + value2 = F::rand(); + } + + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + let expected = F::ZERO; + pw.set_target(*output_value, expected)?; + } + } + + let proof = circuit_data.prove(pw.clone())?; + circuit_data.verify(proof.clone())?; + + Ok(()) + } } diff --git a/plonky2/src/gates/multiplication_base.rs b/plonky2/src/gates/multiplication_base.rs index cfe264992..f73516f32 100644 --- a/plonky2/src/gates/multiplication_base.rs +++ b/plonky2/src/gates/multiplication_base.rs @@ -231,12 +231,20 @@ impl, const D: usize> SimpleGenerator #[cfg(test)] mod tests { use anyhow::Result; + use plonky2_field::types::Sample; use crate::field::goldilocks_field::GoldilocksField; + use crate::field::types::Field; + #[allow(unused_imports)] + use crate::field::types::Field64; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::multiplication_base::MultiplicationGate; - use crate::plonk::circuit_data::CircuitConfig; + use crate::iop::target::Target; + use crate::iop::witness::{PartialWitness, WitnessWrite}; + use crate::plonk::circuit_builder::CircuitBuilder; + use crate::plonk::circuit_data::{CircuitConfig, CircuitData}; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::util::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer}; #[test] fn low_degree() { @@ -252,4 +260,192 @@ mod tests { let gate = MultiplicationGate::new_from_config(&CircuitConfig::standard_recursion_config()); test_eval_fns::(gate) } + + #[test] + fn test_success() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) -> Result<()> { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = MultiplicationGate::new_from_config(&config); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_0(i)); + let wire_y = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_1(i)); + let wire_output = Target::wire(gate_row, MultiplicationGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + + let mut pw = PartialWitness::new(); + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 * value2; + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + pw.set_target(*output_value, expected)?; + } + + let proof = circuit_data.prove(pw)?; + circuit_data.verify(proof)?; + + Ok(()) + } + + flag_test(63)?; // flag enabled + flag_test(61)?; // flag disabled + + Ok(()) + } + + #[test] + #[should_panic] + fn test_failure() { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = MultiplicationGate::new_from_config(&config); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_0(i)); + let wire_y = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_1(i)); + let wire_output = Target::wire(gate_row, MultiplicationGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + + let mut pw = PartialWitness::new(); + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 * value2; + let mut incorrect_value = F::rand(); + while incorrect_value == expected { + incorrect_value = F::rand(); + } + pw.set_target(*x, value1).unwrap(); + pw.set_target(*y, value2).unwrap(); + pw.set_target(*output_value, incorrect_value).unwrap(); + } + + let proof = circuit_data.prove(pw).unwrap(); + circuit_data.verify(proof).unwrap(); + } + + flag_test(63); // flag enabled + flag_test(61); // flag disabled + } + + #[test] + fn test_serialization_multiplication() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = MultiplicationGate::new_from_config(&config); + let constants = [F::ONE]; + + for _ in 0..100 { + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + let output_value = builder.add_virtual_target(); + + let (gate_row, i) = builder.find_slot(gate.clone(), &constants, &constants); + + let wire_x = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_0(i)); + let wire_y = Target::wire(gate_row, MultiplicationGate::wire_ith_multiplicand_1(i)); + let wire_output = Target::wire(gate_row, MultiplicationGate::wire_ith_output(i)); + + builder.connect(x, wire_x); + builder.connect(y, wire_y); + builder.connect(output_value, wire_output); + + pairs.push((x, y, output_value)); + } + + let circuit_data = builder.build::(); + let gate_serializer = DefaultGateSerializer; + let generator_serializer = DefaultGeneratorSerializer::::default(); + + let data_bytes = circuit_data + .to_bytes(&gate_serializer, &generator_serializer) + .map_err(|_| anyhow::Error::msg("Serialization failed."))?; + + let deserialized_circuit_data = CircuitData::::from_bytes( + &data_bytes, + &gate_serializer, + &generator_serializer, + ) + .map_err(|_| anyhow::Error::msg("Deserialization failed."))?; + + assert_eq!(deserialized_circuit_data, circuit_data); + + let mut pw = PartialWitness::new(); + + for (x, y, output_value) in pairs.iter() { + let value1 = F::rand(); + let value2 = F::rand(); + let expected = value1 * value2; + + pw.set_target(*x, value1)?; + pw.set_target(*y, value2)?; + pw.set_target(*output_value, expected)?; + } + + let proof = deserialized_circuit_data.prove(pw)?; + deserialized_circuit_data.verify(proof)?; + + Ok(()) + } } diff --git a/plonky2/src/gates/select_base.rs b/plonky2/src/gates/select_base.rs index 51e4070ca..eb6de52ed 100644 --- a/plonky2/src/gates/select_base.rs +++ b/plonky2/src/gates/select_base.rs @@ -268,6 +268,7 @@ impl, const D: usize> SimpleGenerator #[cfg(test)] mod tests { use anyhow::Result; + use plonky2_field::types::Sample; use crate::field::goldilocks_field::GoldilocksField; use crate::field::types::Field; @@ -278,8 +279,9 @@ mod tests { use crate::iop::target::Target; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::circuit_data::{CircuitConfig, CircuitData}; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::util::serialization::{DefaultGateSerializer, DefaultGeneratorSerializer}; #[test] fn low_degree() { @@ -332,4 +334,240 @@ mod tests { circuit_data.verify(proof)?; Ok(()) } + + #[test] + fn test_success() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) -> Result<()> { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = SelectionGate::new_from_config(&config); + let ref_gate = gate.clone(); + + for _ in 0..100 { + let b = builder.add_virtual_bool_target_safe(); + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + + let (row, i) = builder.find_slot(gate.clone(), &[], &[]); + + builder.connect(b.target, Target::wire(row, ref_gate.wire_ith_selector(i))); + builder.connect(x, Target::wire(row, ref_gate.wire_ith_element_0(i))); + builder.connect(y, Target::wire(row, ref_gate.wire_ith_element_1(i))); + + let output = Target::wire(row, ref_gate.wire_ith_output(i)); + let result = builder.add_virtual_target(); + builder.connect(result, output); + + pairs.push((b, x, y, result)); + } + + let circuit_data = builder.build::(); + let mut pw = PartialWitness::new(); + + for (i, (b, x, y, result)) in pairs.iter().enumerate() { + if i < 50 { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = true; + let expected = x_val; + + pw.set_target(*x, x_val)?; + pw.set_target(*y, y_val)?; + pw.set_bool_target(*b, b_val)?; + pw.set_target(*result, expected)?; + } else { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = false; + let expected = y_val; + + pw.set_target(*x, x_val)?; + pw.set_target(*y, y_val)?; + pw.set_bool_target(*b, b_val)?; + pw.set_target(*result, expected)?; + } + } + + let proof = circuit_data.prove(pw)?; + circuit_data.verify(proof)?; + + Ok(()) + } + + flag_test(63)?; // flag enabled + flag_test(31)?; // flag disabled + + Ok(()) + } + + #[test] + #[should_panic] + fn test_failure() { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + fn flag_test(flag: usize) { + let config = CircuitConfig { + optimization_flags: flag, + ..CircuitConfig::standard_recursion_config() + }; + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = SelectionGate::new_from_config(&config); + let ref_gate = gate.clone(); + + for _ in 0..100 { + let b = builder.add_virtual_bool_target_safe(); + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + + let (row, i) = builder.find_slot(gate.clone(), &[], &[]); + + builder.connect(b.target, Target::wire(row, ref_gate.wire_ith_selector(i))); + builder.connect(x, Target::wire(row, ref_gate.wire_ith_element_0(i))); + builder.connect(y, Target::wire(row, ref_gate.wire_ith_element_1(i))); + + let output = Target::wire(row, ref_gate.wire_ith_output(i)); + let result = builder.add_virtual_target(); + builder.connect(result, output); + + pairs.push((b, x, y, result)); + } + + let circuit_data = builder.build::(); + let mut pw = PartialWitness::new(); + + for (i, (b, x, y, result)) in pairs.iter().enumerate() { + if i < 50 { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = true; + let expected = x_val; + let mut incorrect_value = F::rand(); + while incorrect_value == expected { + incorrect_value = F::rand(); + } + + pw.set_target(*x, x_val).unwrap(); + pw.set_target(*y, y_val).unwrap(); + pw.set_bool_target(*b, b_val).unwrap(); + pw.set_target(*result, incorrect_value).unwrap(); + } else { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = false; + let expected = y_val; + let mut incorrect_value = F::rand(); + while incorrect_value == expected { + incorrect_value = F::rand(); + } + + pw.set_target(*x, x_val).unwrap(); + pw.set_target(*y, y_val).unwrap(); + pw.set_bool_target(*b, b_val).unwrap(); + pw.set_target(*result, incorrect_value).unwrap(); + } + } + + let proof = circuit_data.prove(pw).unwrap(); + circuit_data.verify(proof).unwrap(); + } + + flag_test(63); // flag enabled + flag_test(31); // flag disabled + } + + #[test] + fn test_serialization_select() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config.clone()); + + let mut pairs = vec![]; + + let gate = SelectionGate::new_from_config(&config); + let ref_gate = gate.clone(); + + for _ in 0..100 { + let b = builder.add_virtual_bool_target_safe(); + let x = builder.add_virtual_target(); + let y = builder.add_virtual_target(); + + let (row, i) = builder.find_slot(gate.clone(), &[], &[]); + + builder.connect(b.target, Target::wire(row, ref_gate.wire_ith_selector(i))); + builder.connect(x, Target::wire(row, ref_gate.wire_ith_element_0(i))); + builder.connect(y, Target::wire(row, ref_gate.wire_ith_element_1(i))); + + let output = Target::wire(row, ref_gate.wire_ith_output(i)); + let result = builder.add_virtual_target(); + builder.connect(result, output); + + pairs.push((b, x, y, result)); + } + + let circuit_data = builder.build::(); + let gate_serializer = DefaultGateSerializer; + let generator_serializer = DefaultGeneratorSerializer::::default(); + + let data_bytes = circuit_data + .to_bytes(&gate_serializer, &generator_serializer) + .map_err(|_| anyhow::Error::msg("Serialization failed."))?; + + let deserialized_circuit_data = CircuitData::::from_bytes( + &data_bytes, + &gate_serializer, + &generator_serializer, + ) + .map_err(|_| anyhow::Error::msg("Deserialization failed."))?; + + assert_eq!(deserialized_circuit_data, circuit_data); + + let mut pw = PartialWitness::new(); + + for (i, (b, x, y, result)) in pairs.iter().enumerate() { + if i < 50 { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = true; + let expected = x_val; + + pw.set_target(*x, x_val)?; + pw.set_target(*y, y_val)?; + pw.set_bool_target(*b, b_val)?; + pw.set_target(*result, expected)?; + } else { + let x_val = F::rand(); + let y_val = F::rand(); + let b_val = false; + let expected = y_val; + + pw.set_target(*x, x_val)?; + pw.set_target(*y, y_val)?; + pw.set_bool_target(*b, b_val)?; + pw.set_target(*result, expected)?; + } + } + + let proof = deserialized_circuit_data.prove(pw.clone())?; + deserialized_circuit_data.verify(proof.clone())?; + + Ok(()) + } } diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 424e03ae6..16791911a 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -59,7 +59,7 @@ pub fn verify_merkle_proof_to_cap>( proof: &MerkleProof, ) -> Result<()> { verify_batch_merkle_proof_to_cap( - &[leaf_data.clone()], + std::slice::from_ref(&leaf_data), &[proof.siblings.len()], leaf_index, merkle_cap, diff --git a/plonky2/src/util/serialization/gate_serialization.rs b/plonky2/src/util/serialization/gate_serialization.rs index 46f60b9f5..936726eac 100644 --- a/plonky2/src/util/serialization/gate_serialization.rs +++ b/plonky2/src/util/serialization/gate_serialization.rs @@ -115,6 +115,7 @@ pub mod default { use crate::gates::random_access::RandomAccessGate; use crate::gates::reducing::ReducingGate; use crate::gates::reducing_extension::ReducingExtensionGate; + use crate::gates::select_base::SelectionGate; use crate::hash::hash_types::RichField; use crate::util::serialization::GateSerializer; /// A gate serializer that can be used to serialize all default gates supported @@ -149,7 +150,8 @@ pub mod default { PublicInputGate, RandomAccessGate, ReducingExtensionGate, - ReducingGate + ReducingGate, + SelectionGate } } }