From eadd00e326c34f18f4c1be2200b2bf648b20ffc2 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Sun, 15 Oct 2023 13:20:18 -0700 Subject: [PATCH 1/3] Prepares test for debug --- synthesizer/snark/src/lib.rs | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/synthesizer/snark/src/lib.rs b/synthesizer/snark/src/lib.rs index c5063edf4f..da8e98814e 100644 --- a/synthesizer/snark/src/lib.rs +++ b/synthesizer/snark/src/lib.rs @@ -160,4 +160,52 @@ mod test { println!("\nShould not verify (i.e. verifier messages should print below):"); assert!(!verifying_key.verify("test", &[one, one + one], &proof)); } + + #[test] + fn test_varuna_verify_public_input_size() { + /// Creates a simple circuit: a * b. + fn create_assignment() -> circuit::Assignment<::Field> { + use circuit::{environment::Mode, types::Field, Inject}; + + // Ensure the circuit environment is clean. + Circuit::reset(); + + // Inject a field element. + let console_field = console::types::Field::::one(); + let circuit_field_0 = Field::::new(Mode::Private, console_field); + + // Inject another field element. + let console_field = console_field.double(); + let circuit_field_1 = Field::::new(Mode::Private, console_field); + + // Multiply the two field elements. + let _circuit_field_2 = circuit_field_0 * circuit_field_1; + + // Eject the assignment. + Circuit::eject_assignment_and_reset() + } + + let assignment = create_assignment(); + assert_eq!(assignment.num_public(), 1); + assert_eq!(assignment.num_private(), 3); + + let srs = UniversalSRS::::load().unwrap(); + let (proving_key, verifying_key) = srs.to_circuit_key("test", &assignment).unwrap(); + println!("Called circuit setup"); + + let proof = proving_key.prove("test", &assignment, &mut TestRng::default()).unwrap(); + println!("Called prover"); + + // Should pass. + let one = ::BaseField::one(); + assert!(verifying_key.verify("test", &[one], &proof)); + + // Should fail. + assert!(!verifying_key.verify("test", &[one, one], &proof)); + assert!(!verifying_key.verify("test", &[one, one + one], &proof)); + assert!(!verifying_key.verify("test", &[one, one, one], &proof)); + assert!(!verifying_key.verify("test", &[one, one, one + one], &proof)); + + println!("Called verifier"); + } } From c03d79b97d9f0b9d04fa7e75338df953fb19731c Mon Sep 17 00:00:00 2001 From: Victor Sint Nicolaas Date: Tue, 17 Oct 2023 14:50:11 +0200 Subject: [PATCH 2/3] Err but not panic when passing more inputs than expected --- algorithms/src/errors.rs | 3 ++ algorithms/src/snark/varuna/ahp/ahp.rs | 33 +++++++++---------- .../varuna/data_structures/test_circuit.rs | 5 +++ algorithms/src/snark/varuna/tests.rs | 2 +- algorithms/src/snark/varuna/varuna.rs | 10 ++++-- synthesizer/snark/src/lib.rs | 1 + 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/algorithms/src/errors.rs b/algorithms/src/errors.rs index a1dedf9f12..dd932b2b28 100644 --- a/algorithms/src/errors.rs +++ b/algorithms/src/errors.rs @@ -41,6 +41,9 @@ pub enum SNARKError { #[error("Batch size was different between public input and proof")] BatchSizeMismatch, + #[error("Public input size was different from the circuit")] + PublicInputSizeMismatch, + #[error("Circuit not found")] CircuitNotFound, } diff --git a/algorithms/src/snark/varuna/ahp/ahp.rs b/algorithms/src/snark/varuna/ahp/ahp.rs index 0b88868473..7594358674 100644 --- a/algorithms/src/snark/varuna/ahp/ahp.rs +++ b/algorithms/src/snark/varuna/ahp/ahp.rs @@ -180,23 +180,20 @@ impl AHPForR1CS { let max_constraint_domain = state.max_constraint_domain; let max_variable_domain = state.max_variable_domain; let max_non_zero_domain = state.max_non_zero_domain; - let public_inputs = state - .circuit_specific_states - .iter() - .map(|(circuit_id, circuit_state)| { - let input_domain = circuit_state.input_domain; - let public_inputs = public_inputs[circuit_id] - .iter() - .map(|p| { - let public_input = prover::ConstraintSystem::format_public_input(p); - Self::formatted_public_input_is_admissible(&public_input)?; - Ok::<_, AHPError>(public_input) - }) - .collect::, _>>()?; - ensure!(public_inputs[0].len() == input_domain.size()); - Ok(public_inputs) - }) - .collect::, _>>()?; + let mut formatted_public_inputs = Vec::with_capacity(state.circuit_specific_states.len()); + for (circuit_id, circuit_state) in &state.circuit_specific_states { + let input_domain = circuit_state.input_domain; + let public_inputs_i = public_inputs[circuit_id] + .iter() + .map(|p| { + let public_input = prover::ConstraintSystem::format_public_input(p); + Self::formatted_public_input_is_admissible(&public_input)?; + Ok::<_, AHPError>(public_input) + }) + .collect::, _>>()?; + assert_eq!(public_inputs_i[0].len(), input_domain.size()); + formatted_public_inputs.push(public_inputs_i); + } let verifier::FirstMessage { batch_combiners } = state.first_round_message.as_ref().unwrap(); let verifier::SecondMessage { alpha, eta_b, eta_c } = state.second_round_message.unwrap(); @@ -286,7 +283,7 @@ impl AHPForR1CS { .enumerate() .map(|(i, (circuit_id, circuit_state))| { let lag_at_beta = circuit_state.input_domain.evaluate_all_lagrange_coefficients(beta); - let x_at_beta = public_inputs[i] + let x_at_beta = formatted_public_inputs[i] .iter() .map(|x| x.iter().zip_eq(&lag_at_beta).map(|(x, l)| *x * l).sum::()) .collect_vec(); diff --git a/algorithms/src/snark/varuna/data_structures/test_circuit.rs b/algorithms/src/snark/varuna/data_structures/test_circuit.rs index e269ef7d46..2bd66fa259 100644 --- a/algorithms/src/snark/varuna/data_structures/test_circuit.rs +++ b/algorithms/src/snark/varuna/data_structures/test_circuit.rs @@ -40,6 +40,11 @@ impl core::fmt::Debug for TestCircuit { impl ConstraintSynthesizer for TestCircuit { fn generate_constraints>(&self, cs: &mut CS) -> Result<(), SynthesisError> { + // Ensure the given `cs` is starting off clean. + assert_eq!(1, cs.num_public_variables()); + assert_eq!(0, cs.num_private_variables()); + assert_eq!(0, cs.num_constraints()); + let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?; let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?; diff --git a/algorithms/src/snark/varuna/tests.rs b/algorithms/src/snark/varuna/tests.rs index 2d2f20bccb..3c786162b5 100644 --- a/algorithms/src/snark/varuna/tests.rs +++ b/algorithms/src/snark/varuna/tests.rs @@ -76,7 +76,7 @@ mod varuna { assert!($snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, public_inputs, &proof).unwrap()); println!("Called verifier"); eprintln!("\nShould not verify (i.e. verifier messages should print below):"); - assert!(!$snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, [random, random], &proof).unwrap()); + assert!(!$snark_inst::verify(universal_verifier, &fs_parameters, &index_vk, [random], &proof).unwrap()); } for circuit_batch_size in (0..4).map(|i| 2usize.pow(i)) { diff --git a/algorithms/src/snark/varuna/varuna.rs b/algorithms/src/snark/varuna/varuna.rs index df01ee4425..329cc776b0 100644 --- a/algorithms/src/snark/varuna/varuna.rs +++ b/algorithms/src/snark/varuna/varuna.rs @@ -657,7 +657,7 @@ where let mut input_domains = BTreeMap::new(); let mut circuit_infos = BTreeMap::new(); let mut circuit_ids = Vec::with_capacity(keys_to_inputs.len()); - for (vk, public_inputs_i) in keys_to_inputs.iter() { + for (&vk, &public_inputs_i) in keys_to_inputs.iter() { max_num_constraints = max_num_constraints.max(vk.circuit_info.num_constraints); max_num_variables = max_num_variables.max(vk.circuit_info.num_variables); @@ -670,7 +670,13 @@ where let input_fields = public_inputs_i .iter() - .map(|input| input.borrow().to_field_elements()) + .map(|input| { + let input = input.borrow().to_field_elements()?; + if input.len() > input_domain.size() - 1 { + bail!(SNARKError::PublicInputSizeMismatch); + } + Ok(input) + }) .collect::, _>>()?; let (padded_public_inputs_i, parsed_public_inputs_i): (Vec<_>, Vec<_>) = { diff --git a/synthesizer/snark/src/lib.rs b/synthesizer/snark/src/lib.rs index da8e98814e..f0a0c292c5 100644 --- a/synthesizer/snark/src/lib.rs +++ b/synthesizer/snark/src/lib.rs @@ -205,6 +205,7 @@ mod test { assert!(!verifying_key.verify("test", &[one, one + one], &proof)); assert!(!verifying_key.verify("test", &[one, one, one], &proof)); assert!(!verifying_key.verify("test", &[one, one, one + one], &proof)); + assert!(!verifying_key.verify("test", &[one, one, one, one], &proof)); println!("Called verifier"); } From e0ea4593decc3f608e015c283222676210f63bad Mon Sep 17 00:00:00 2001 From: Victor Sint Nicolaas Date: Thu, 28 Dec 2023 12:57:18 +0100 Subject: [PATCH 3/3] Use ensure instead of assert_eq --- algorithms/src/snark/varuna/ahp/ahp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/src/snark/varuna/ahp/ahp.rs b/algorithms/src/snark/varuna/ahp/ahp.rs index 7594358674..4cbeb52919 100644 --- a/algorithms/src/snark/varuna/ahp/ahp.rs +++ b/algorithms/src/snark/varuna/ahp/ahp.rs @@ -191,7 +191,7 @@ impl AHPForR1CS { Ok::<_, AHPError>(public_input) }) .collect::, _>>()?; - assert_eq!(public_inputs_i[0].len(), input_domain.size()); + ensure!(public_inputs_i[0].len() == input_domain.size()); formatted_public_inputs.push(public_inputs_i); }