diff --git a/bberg/src/flavor_builder.rs b/bberg/src/flavor_builder.rs index b9d6bb2534..1439fc95c4 100644 --- a/bberg/src/flavor_builder.rs +++ b/bberg/src/flavor_builder.rs @@ -498,7 +498,14 @@ fn create_commitment_labels(all_ents: &[String]) -> String { ) } +/// Create the compute_logderivative_inverses function +/// +/// If we do not have any lookups, we do not need to include this round fn create_compute_logderivative_inverses(flavor_name: &str, lookups: &[String]) -> String { + if lookups.is_empty() { + return "".to_string(); + } + let compute_inverse_transformation = |lookup_name: &String| { format!("bb::compute_logderivative_inverse<{flavor_name}Flavor, {lookup_name}_relation>(prover_polynomials, relation_parameters, this->circuit_size);") }; diff --git a/bberg/src/prover_builder.rs b/bberg/src/prover_builder.rs index b7a313e2d3..61f0202e1e 100644 --- a/bberg/src/prover_builder.rs +++ b/bberg/src/prover_builder.rs @@ -15,6 +15,7 @@ pub trait ProverBuilder { impl ProverBuilder for BBFiles { fn create_prover_hpp(&mut self, name: &str) { let include_str = includes_hpp(&snake_case(name)); + let prover_hpp = format!(" {include_str} namespace bb {{ @@ -91,7 +92,16 @@ impl ProverBuilder for BBFiles { let include_str = includes_cpp(&snake_case(name)); let polynomial_commitment_phase = create_commitments_phase(commitment_polys); - let log_derivative_inverse_phase = create_log_derivative_inverse_round(lookup_names); + + let (call_log_derivative_phase, log_derivative_inverse_phase): (String, String) = + if lookup_names.is_empty() { + ("".to_owned(), "".to_owned()) + } else { + ( + "execute_log_derivative_inverse_round();".to_owned(), + create_log_derivative_inverse_round(lookup_names), + ) + }; let prover_cpp = format!(" {include_str} @@ -208,7 +218,7 @@ impl ProverBuilder for BBFiles { execute_wire_commitments_round(); // Compute sorted list accumulator and commitment - execute_log_derivative_inverse_round(); + {call_log_derivative_phase} // Fiat-Shamir: alpha // Run sumcheck subprotocol. diff --git a/bberg/src/verifier_builder.rs b/bberg/src/verifier_builder.rs index db789e18cc..b1880e2e8e 100644 --- a/bberg/src/verifier_builder.rs +++ b/bberg/src/verifier_builder.rs @@ -4,13 +4,25 @@ use crate::{ }; pub trait VerifierBuilder { - fn create_verifier_cpp(&mut self, name: &str, witness: &[String], inverses: &[String]); + fn create_verifier_cpp( + &mut self, + name: &str, + witness: &[String], + inverses: &[String], + public_cols: &[String], + ); - fn create_verifier_hpp(&mut self, name: &str); + fn create_verifier_hpp(&mut self, name: &str, public_cols: &[String]); } impl VerifierBuilder for BBFiles { - fn create_verifier_cpp(&mut self, name: &str, witness: &[String], inverses: &[String]) { + fn create_verifier_cpp( + &mut self, + name: &str, + witness: &[String], + inverses: &[String], + public_cols: &[String], + ) { let include_str = includes_cpp(&snake_case(name)); let wire_transformation = |n: &String| { @@ -19,12 +31,63 @@ impl VerifierBuilder for BBFiles { ) }; let wire_commitments = map_with_newline(witness, wire_transformation); + + let has_public_input_columns = !public_cols.is_empty(); + let has_inverses = !inverses.is_empty(); + + let get_inverse_challenges = if has_inverses { + " + auto [beta, gamm] = transcript->template get_challenges(\"beta\", \"gamma\"); + relation_parameters.beta = beta; + relation_parameters.gamma = gamm; + " + .to_string() + } else { + "".to_owned() + }; + + let verify_proof_function_declaration: String = if has_public_input_columns { + format!("bool {name}Verifier::verify_proof(const HonkProof& proof, const std::vector& public_inputs)") + } else { + format!("bool {name}Verifier::verify_proof(const HonkProof& proof)") + }; + + let (public_inputs_check, evaluate_public_inputs) = if has_public_input_columns { + let public_inputs_column = public_cols[0].clone(); // asserted to be 1 for the meantime, this will be generalized when required + let inputs_check = format!( + " + FF public_column_evaluation = evaluate_public_input_column(public_inputs, multivariate_challenge); + if (public_column_evaluation != claimed_evaluations.{public_inputs_column}) {{ + return false; + }} + " + ); + let evaluate_public_inputs = format!( + " + + using FF = {name}Flavor::FF; + + // Evaluate the given public input column over the multivariate challenge points + [[maybe_unused]] FF evaluate_public_input_column(std::vector points, std::vector challenges) {{ + Polynomial polynomial(points); + return polynomial.evaluate_mle(challenges); + }} + " + ); + + (inputs_check, evaluate_public_inputs) + } else { + ("".to_owned(), "".to_owned()) + }; + let inverse_commitments = map_with_newline(inverses, wire_transformation); let ver_cpp = format!(" {include_str} namespace bb {{ + + {name}Verifier::{name}Verifier(std::shared_ptr verifier_key) : key(verifier_key) {{}} @@ -41,12 +104,15 @@ impl VerifierBuilder for BBFiles { commitments.clear(); return *this; }} + + {evaluate_public_inputs} + /** * @brief This function verifies an {name} Honk proof for given program settings. * */ - bool {name}Verifier::verify_proof(const HonkProof& proof) + {verify_proof_function_declaration} {{ using Flavor = {name}Flavor; using FF = Flavor::FF; @@ -72,9 +138,7 @@ impl VerifierBuilder for BBFiles { // Get commitments to VM wires {wire_commitments} - auto [beta, gamm] = transcript->template get_challenges(\"beta\", \"gamma\"); - relation_parameters.beta = beta; - relation_parameters.gamma = gamm; + {get_inverse_challenges} // Get commitments to inverses {inverse_commitments} @@ -97,6 +161,8 @@ impl VerifierBuilder for BBFiles { if (sumcheck_verified.has_value() && !sumcheck_verified.value()) {{ return false; }} + + {public_inputs_check} // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the // unrolled protocol. @@ -126,8 +192,17 @@ impl VerifierBuilder for BBFiles { ); } - fn create_verifier_hpp(&mut self, name: &str) { + fn create_verifier_hpp(&mut self, name: &str, public_cols: &[String]) { let include_str = include_hpp(&snake_case(name)); + + // If there are public input columns, then the generated verifier must take them in as an argument for the verify_proof + let verify_proof = if !public_cols.is_empty() { + "bool verify_proof(const HonkProof& proof, const std::vector& public_inputs);" + .to_string() + } else { + "bool verify_proof(const HonkProof& proof);".to_owned() + }; + let ver_hpp = format!( " {include_str} @@ -149,7 +224,7 @@ impl VerifierBuilder for BBFiles { {name}Verifier& operator=(const {name}Verifier& other) = delete; {name}Verifier& operator=({name}Verifier&& other) noexcept; - bool verify_proof(const HonkProof& proof); + {verify_proof} std::shared_ptr key; std::map commitments; @@ -188,6 +263,7 @@ fn includes_cpp(name: &str) -> String { #include \"./{name}_verifier.hpp\" #include \"barretenberg/commitment_schemes/zeromorph/zeromorph.hpp\" #include \"barretenberg/numeric/bitop/get_msb.hpp\" + #include \"barretenberg/polynomials/polynomial.hpp\" #include \"barretenberg/transcript/transcript.hpp\" " ) diff --git a/bberg/src/vm_builder.rs b/bberg/src/vm_builder.rs index ee877a2342..bb68d01842 100644 --- a/bberg/src/vm_builder.rs +++ b/bberg/src/vm_builder.rs @@ -1,5 +1,6 @@ use ast::analyzed::Analyzed; +use itertools::Itertools; use number::FieldElement; use crate::circuit_builder::CircuitBuilder; @@ -29,6 +30,8 @@ struct ColumnGroups { fixed: Vec, /// witness or commit columns in pil -> will be found in proof witness: Vec, + // public input columns, evaluations will be calculated within the verifier + public: Vec, /// witness or commit columns in pil, with out the inverse columns witnesses_without_inverses: Vec, /// fixed + witness columns without lookup inverses @@ -89,6 +92,7 @@ pub(crate) fn analyzed_to_cpp( let ColumnGroups { fixed, witness, + public, witnesses_without_inverses, all_cols, all_cols_without_inverses, @@ -130,8 +134,8 @@ pub(crate) fn analyzed_to_cpp( bb_files.create_composer_hpp(file_name); // ----------------------- Create the Verifier files ----------------------- - bb_files.create_verifier_cpp(file_name, &witnesses_without_inverses, &inverses); - bb_files.create_verifier_hpp(file_name); + bb_files.create_verifier_cpp(file_name, &witnesses_without_inverses, &inverses, &public); + bb_files.create_verifier_hpp(file_name, &public); // ----------------------- Create the Prover files ----------------------- bb_files.create_prover_cpp(file_name, &witnesses_without_inverses, &inverses); @@ -166,6 +170,7 @@ fn get_all_col_names( // Gather sanitized column names let fixed_names = collect_col(fixed, sanitize); let witness_names = collect_col(witness, sanitize); + let (witness_names, public_input_column_names) = extract_public_input_columns(witness_names); let inverses = flatten(&[perm_inverses, lookup_inverses]); let witnesses_without_inverses = flatten(&[witness_names.clone(), lookup_counts.clone()]); @@ -190,6 +195,7 @@ fn get_all_col_names( ColumnGroups { fixed: fixed_names, witness: witnesses_with_inverses, + public: public_input_column_names, all_cols_without_inverses, witnesses_without_inverses, all_cols, @@ -200,3 +206,23 @@ fn get_all_col_names( inverses, } } + +/// Extract public input columns +/// The compiler automatically suffixes the public input columns with "__is_public" +/// This function removes the suffix and collects the columns into their own container +pub fn extract_public_input_columns(witness_columns: Vec) -> (Vec, Vec) { + let witness_names: Vec = witness_columns + .clone(); + let public_input_column_names: Vec = witness_columns + .into_iter() + .filter(|name| + name.ends_with("__is_public") + ) + .collect(); + + assert!( + public_input_column_names.len() <= 1, + "There should only be one public input column (for now)" + ); + (witness_names, public_input_column_names) +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 340d143de9..cd258d1eab 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -83,7 +83,8 @@ mod test { name: "t".to_string(), array_size: None }], - None + None, + false ) ]) );