use std::any::TypeId;
use std::collections::HashMap;
use crate::franklin_crypto::bellman::pairing::Engine;
use crate::franklin_crypto::bellman::plonk::better_better_cs::cs::ConstraintSystem;
use crate::boojum::cs::cs_builder::new_builder;
use crate::boojum::cs::cs_builder::CsBuilderImpl;
use crate::boojum::cs::traits::circuit::{CircuitBuilder, CircuitBuilderProxy};
use crate::boojum::cs::traits::evaluator::GateBatchEvaluationComparisonFunction;
use crate::boojum::cs::traits::evaluator::GatePlacementType;
use crate::boojum::cs::traits::evaluator::PerChunkOffset;
use crate::boojum::cs::{CSGeometry, LookupParameters};
use crate::boojum::field::goldilocks::GoldilocksField as GL;
use crate::traits::circuit::ErasedBuilderForWrapperVerifier;
use crate::verifier_structs::gate_evaluator::TypeErasedGateEvaluationWrapperVerificationFunction;
use crate::verifier_structs::WrapperVerifier;
impl<E: Engine, CS: ConstraintSystem<E> + 'static, T: CircuitBuilder<GL>> ErasedBuilderForWrapperVerifier<E, CS> for CircuitBuilderProxy<GL, T> {
fn geometry(&self) -> CSGeometry {
T::geometry()
}
fn lookup_parameters(&self) -> LookupParameters {
T::lookup_parameters()
}
fn create_wrapper_verifier(&self, cs: &mut CS) -> WrapperVerifier<E, CS> {
let geometry = T::geometry();
let builder_impl = CsWrapperVerifierBuilder::<'_, E, CS>::new_from_parameters(cs, geometry);
let builder = new_builder::<_, GL>(builder_impl);
let builder = T::configure_builder(builder);
let verifier = builder.build(());
verifier
}
}
pub struct CsWrapperVerifierBuilder<'a, E: Engine, CS: ConstraintSystem<E> + 'static> {
pub(crate) cs: &'a mut CS,
pub parameters: CSGeometry,
pub lookup_parameters: LookupParameters,
pub(crate) gate_type_ids_for_specialized_columns: Vec<TypeId>,
pub(crate) evaluators_over_specialized_columns: Vec<TypeErasedGateEvaluationWrapperVerificationFunction<E, CS>>,
pub(crate) offsets_for_specialized_evaluators: Vec<(PerChunkOffset, PerChunkOffset, usize)>,
pub(crate) evaluators_over_general_purpose_columns: Vec<TypeErasedGateEvaluationWrapperVerificationFunction<E, CS>>,
pub(crate) general_purpose_evaluators_comparison_functions: HashMap<TypeId, Vec<(GateBatchEvaluationComparisonFunction, usize)>>,
pub(crate) total_num_variables_for_specialized_columns: usize,
pub(crate) total_num_witnesses_for_specialized_columns: usize,
pub(crate) total_num_constants_for_specialized_columns: usize,
}
impl<'a, E: Engine, CS: ConstraintSystem<E> + 'static> CsWrapperVerifierBuilder<'a, E, CS> {
pub fn new_from_parameters(cs: &'a mut CS, parameters: CSGeometry) -> Self {
Self {
cs,
parameters: parameters,
lookup_parameters: LookupParameters::NoLookup,
gate_type_ids_for_specialized_columns: Vec::with_capacity(16),
evaluators_over_specialized_columns: Vec::with_capacity(16),
offsets_for_specialized_evaluators: Vec::with_capacity(16),
evaluators_over_general_purpose_columns: Vec::with_capacity(16),
general_purpose_evaluators_comparison_functions: HashMap::with_capacity(16),
total_num_variables_for_specialized_columns: 0,
total_num_witnesses_for_specialized_columns: 0,
total_num_constants_for_specialized_columns: 0,
}
}
}
use crate::boojum::cs::cs_builder::CsBuilder;
use crate::boojum::cs::gates::lookup_marker::LookupFormalGate;
use crate::boojum::cs::gates::LookupTooling;
use crate::boojum::cs::traits::gate::GatePlacementStrategy;
use crate::boojum::cs::traits::{evaluator::GateConstraintEvaluator, gate::Gate};
use crate::boojum::cs::GateConfigurationHolder;
use crate::boojum::cs::GateTypeEntry;
use crate::boojum::cs::StaticToolboxHolder;
use crate::boojum::cs::Tool;
impl<'a, E: Engine, CS: ConstraintSystem<E> + 'static> CsBuilderImpl<GL, CsWrapperVerifierBuilder<'a, E, CS>> for CsWrapperVerifierBuilder<'a, E, CS> {
type Final<GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder> = WrapperVerifier<E, CS>;
type BuildParams<'b> = ();
fn parameters<GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder>(builder: &CsBuilder<Self, GL, GC, TB>) -> CSGeometry {
builder.implementation.parameters
}
fn allow_gate<GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder, G: Gate<GL>, TAux: 'static + Send + Sync + Clone>(
mut builder: CsBuilder<Self, GL, GC, TB>,
placement_strategy: GatePlacementStrategy,
params: <<G as Gate<GL>>::Evaluator as GateConstraintEvaluator<GL>>::UniqueParameterizationParams,
aux_data: TAux,
) -> CsBuilder<Self, GL, (GateTypeEntry<GL, G, TAux>, GC), TB> {
let this = &mut builder.implementation;
let new_configuration = builder.gates_config.add_gate::<G, _>(placement_strategy, params.clone(), aux_data);
let evaluator_type_id = TypeId::of::<G::Evaluator>();
let gate_type_id = TypeId::of::<G>();
let evaluator = G::Evaluator::new_from_parameters(params.clone());
match placement_strategy {
GatePlacementStrategy::UseGeneralPurposeColumns => {
if let Some(comparison_fns) = this.general_purpose_evaluators_comparison_functions.get_mut(&evaluator_type_id) {
let (dynamic_evaluator, comparator) = TypeErasedGateEvaluationWrapperVerificationFunction::from_evaluator(this.cs, evaluator, &this.parameters, placement_strategy);
let mut existing_idx = None;
for (other_comparator, idx) in comparison_fns.iter() {
if other_comparator.equals_to(&comparator) {
existing_idx = Some(*idx);
break;
}
}
if let Some(_existing_idx) = existing_idx {
} else {
if comparison_fns.len() > 0 {
panic!("not yet supported");
}
let idx = this.evaluators_over_general_purpose_columns.len();
this.evaluators_over_general_purpose_columns.push(dynamic_evaluator);
comparison_fns.push((comparator, idx));
}
} else {
let idx = this.evaluators_over_general_purpose_columns.len();
let (dynamic_evaluator, comparator) = TypeErasedGateEvaluationWrapperVerificationFunction::from_evaluator(this.cs, evaluator, &this.parameters, placement_strategy);
this.evaluators_over_general_purpose_columns.push(dynamic_evaluator);
this.general_purpose_evaluators_comparison_functions.insert(evaluator_type_id, vec![(comparator, idx)]);
}
}
GatePlacementStrategy::UseSpecializedColumns { num_repetitions, share_constants } => {
let (dynamic_evaluator, _comparator) = TypeErasedGateEvaluationWrapperVerificationFunction::from_evaluator(this.cs, evaluator.clone(), &this.parameters, placement_strategy);
let _idx = this.evaluators_over_specialized_columns.len();
this.gate_type_ids_for_specialized_columns.push(gate_type_id);
this.evaluators_over_specialized_columns.push(dynamic_evaluator);
let principal_width = evaluator.instance_width();
let mut total_width = principal_width;
for _ in 1..num_repetitions {
total_width.num_variables += principal_width.num_variables;
total_width.num_witnesses += principal_width.num_witnesses;
if share_constants == false {
total_width.num_constants += principal_width.num_constants;
}
}
let total_constants_available = principal_width.num_constants;
if share_constants {
match evaluator.placement_type() {
GatePlacementType::MultipleOnRow { per_chunk_offset: _ } => {}
GatePlacementType::UniqueOnRow => {
panic!("Can not share constants if placement type is unique");
}
}
}
let initial_offset = PerChunkOffset {
variables_offset: this.parameters.num_columns_under_copy_permutation + this.total_num_variables_for_specialized_columns,
witnesses_offset: this.parameters.num_witness_columns + this.total_num_witnesses_for_specialized_columns,
constants_offset: this.total_num_constants_for_specialized_columns, };
let offset_per_repetition = if share_constants == false {
PerChunkOffset {
variables_offset: principal_width.num_variables,
witnesses_offset: principal_width.num_witnesses,
constants_offset: principal_width.num_constants,
}
} else {
let offset_per_repetition = match evaluator.placement_type() {
GatePlacementType::MultipleOnRow { per_chunk_offset } => per_chunk_offset,
GatePlacementType::UniqueOnRow => {
panic!("Can not share constants if placement type is unique");
}
};
assert_eq!(offset_per_repetition.variables_offset, principal_width.num_variables);
assert_eq!(offset_per_repetition.witnesses_offset, principal_width.num_witnesses);
offset_per_repetition
};
this.offsets_for_specialized_evaluators.push((initial_offset, offset_per_repetition, total_constants_available));
this.total_num_variables_for_specialized_columns += total_width.num_variables;
this.total_num_witnesses_for_specialized_columns += total_width.num_witnesses;
this.total_num_constants_for_specialized_columns += total_width.num_constants;
}
}
CsBuilder {
gates_config: new_configuration,
..builder
}
}
fn add_tool<GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder, M: 'static + Send + Sync + Clone, T: 'static + Send + Sync>(
builder: CsBuilder<Self, GL, GC, TB>,
tool: T,
) -> CsBuilder<Self, GL, GC, (Tool<M, T>, TB)> {
let new_toolbox = builder.toolbox.add_tool(tool);
CsBuilder { toolbox: new_toolbox, ..builder }
}
type GcWithLookup<GC: GateConfigurationHolder<GL>> = (GateTypeEntry<GL, LookupFormalGate, LookupTooling>, GC);
fn allow_lookup<GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder>(
builder: CsBuilder<Self, GL, GC, TB>,
lookup_parameters: LookupParameters,
) -> CsBuilder<Self, GL, Self::GcWithLookup<GC>, TB> {
let mut builder = builder;
builder.implementation.lookup_parameters = lookup_parameters;
let (placement_strategy, num_variables, num_constants, share_table_id) = match lookup_parameters {
LookupParameters::NoLookup => {
(
GatePlacementStrategy::UseSpecializedColumns {
num_repetitions: 0,
share_constants: false,
},
0,
0,
false,
)
}
LookupParameters::TableIdAsVariable { width, share_table_id } => {
assert!(share_table_id == false, "other option is not yet implemented");
assert!(builder.implementation.parameters.num_columns_under_copy_permutation >= (width + 1) as usize);
(GatePlacementStrategy::UseGeneralPurposeColumns, (width + 1) as usize, 0, share_table_id)
}
LookupParameters::TableIdAsConstant { width, share_table_id } => {
assert!(share_table_id == true, "other option is not yet implemented");
assert!(builder.implementation.parameters.num_columns_under_copy_permutation >= width as usize);
(GatePlacementStrategy::UseGeneralPurposeColumns, width as usize, 1, share_table_id)
}
LookupParameters::UseSpecializedColumnsWithTableIdAsVariable {
width,
num_repetitions,
share_table_id,
} => {
assert!(share_table_id == false, "other option is not yet implemented");
(
GatePlacementStrategy::UseSpecializedColumns {
num_repetitions,
share_constants: false,
},
(width + 1) as usize,
0,
share_table_id,
)
}
LookupParameters::UseSpecializedColumnsWithTableIdAsConstant {
width,
num_repetitions,
share_table_id,
} => {
assert!(share_table_id == true, "other option is not yet implemented");
(
GatePlacementStrategy::UseSpecializedColumns {
num_repetitions,
share_constants: share_table_id,
},
width as usize,
1,
share_table_id,
)
}
};
Self::allow_gate(builder, placement_strategy, (num_variables, num_constants, share_table_id), (Vec::with_capacity(32), 0))
}
fn build<'b, GC: GateConfigurationHolder<GL>, TB: StaticToolboxHolder, ARG: Into<Self::BuildParams<'b>>>(builder: CsBuilder<Self, GL, GC, TB>, _params: ARG) -> Self::Final<GC, TB> {
let this: CsWrapperVerifierBuilder<E, CS> = builder.implementation;
assert_eq!(this.evaluators_over_specialized_columns.len(), this.gate_type_ids_for_specialized_columns.len());
let capacity = this.evaluators_over_specialized_columns.len();
let mut placement_strategies = HashMap::with_capacity(capacity);
for gate_type_id in this.gate_type_ids_for_specialized_columns.iter() {
let placement_strategy = builder.gates_config.placement_strategy_for_type_id(*gate_type_id).expect("gate must be allowed");
placement_strategies.insert(*gate_type_id, placement_strategy);
}
WrapperVerifier {
parameters: this.parameters,
lookup_parameters: this.lookup_parameters,
gate_type_ids_for_specialized_columns: this.gate_type_ids_for_specialized_columns,
evaluators_over_specialized_columns: this.evaluators_over_specialized_columns,
offsets_for_specialized_evaluators: this.offsets_for_specialized_evaluators,
evaluators_over_general_purpose_columns: this.evaluators_over_general_purpose_columns,
total_num_variables_for_specialized_columns: this.total_num_variables_for_specialized_columns,
total_num_witnesses_for_specialized_columns: this.total_num_witnesses_for_specialized_columns,
total_num_constants_for_specialized_columns: this.total_num_constants_for_specialized_columns,
placement_strategies,
}
}
}