Skip to main content

axiom_eth/utils/component/circuit/
mod.rs

1use crate::Field;
2use crate::{rlc::circuit::builder::RlcCircuitBuilder, utils::build_utils::dummy::DummyFrom};
3use getset::Getters;
4use halo2_base::{
5    halo2_proofs::{circuit::Layouter, plonk::ConstraintSystem},
6    AssignedValue,
7};
8use serde::{de::DeserializeOwned, Deserialize, Serialize};
9
10use super::{
11    promise_collector::{
12        PromiseCaller, PromiseCallsGetter, PromiseCommitSetter, PromiseResultsGetter,
13    },
14    promise_loader::comp_loader::SingleComponentLoaderParams,
15    types::FixLenLogical,
16    ComponentType, ComponentTypeId, FlattenVirtualTable, LogicalResult,
17};
18
19mod comp_circuit_impl;
20pub use comp_circuit_impl::ComponentCircuitImpl;
21
22pub trait ComponentBuilder<F: Field> {
23    type Config: Clone = ();
24    type Params: Clone + Default = ();
25
26    /// Create Self.
27    fn new(params: Self::Params) -> Self;
28    /// Get params for this module.
29    fn get_params(&self) -> Self::Params;
30    /// Clear all stored witnesses. Data should be untouched.
31    fn clear_witnesses(&mut self) {}
32    /// Configure this module with params.
33    // Alas we cannot have default implementation only for Self::Config = ().
34    fn configure_with_params(meta: &mut ConstraintSystem<F>, params: Self::Params) -> Self::Config;
35    /// Calculate params for this module.
36    fn calculate_params(&mut self) -> Self::Params;
37}
38
39/// CoreBuilder must specify its output format.
40pub trait CoreBuilderParams {
41    /// Return the output capacity.
42    fn get_output_params(&self) -> CoreBuilderOutputParams;
43}
44#[derive(Clone, Default, Getters)]
45pub struct CoreBuilderOutputParams {
46    /// Capacities for each shard.
47    #[getset(get = "pub")]
48    cap_per_shard: Vec<usize>,
49}
50impl CoreBuilderOutputParams {
51    /// create a CoreBuilderOutputParams
52    pub fn new(cap_per_shard: Vec<usize>) -> Self {
53        assert!(cap_per_shard.is_empty() || cap_per_shard.len().is_power_of_two());
54        Self { cap_per_shard }
55    }
56}
57impl CoreBuilderParams for CoreBuilderOutputParams {
58    fn get_output_params(&self) -> CoreBuilderOutputParams {
59        self.clone()
60    }
61}
62/// Input for CoreBuilder.
63/// TODO: specify its output capacity.
64pub trait CoreBuilderInput<F: Field> = Serialize + DeserializeOwned + Clone + 'static;
65
66/// Output for CoreBuilder which is determined at phase0.
67pub struct CoreBuilderOutput<F: Field, T: ComponentType<F>> {
68    /// Public instances except the output commit.
69    pub public_instances: Vec<AssignedValue<F>>,
70    /// Flatten output virtual table.
71    pub virtual_table: FlattenVirtualTable<AssignedValue<F>>,
72    /// Value of logical results.
73    pub logical_results: Vec<LogicalResult<F, T>>,
74}
75
76pub trait CoreBuilder<F: Field>: ComponentBuilder<F, Params: CoreBuilderParams> {
77    type CompType: ComponentType<F>;
78    type PublicInstanceValue: FixLenLogical<F>;
79    type PublicInstanceWitness: FixLenLogical<AssignedValue<F>>;
80    type CoreInput: CoreBuilderInput<F> + DummyFrom<Self::Params>;
81    /// Feed inputs to this module.
82    fn feed_input(&mut self, input: Self::CoreInput) -> anyhow::Result<()>;
83    /// Generate witnesses for phase0. Any data passing to other steps should be stored inside `self`.
84    /// Return `(<output commit>, <other public instances>)`.
85    fn virtual_assign_phase0(
86        &mut self,
87        // TODO: This could be replaced with a more generic CircuitBuilder. Question: can be CircuitBuilder treated as something like PromiseCircuit?
88        builder: &mut RlcCircuitBuilder<F>,
89        // Core circuits can make promise calls.
90        promise_caller: PromiseCaller<F>,
91        // TODO: Output commitmment
92    ) -> CoreBuilderOutput<F, Self::CompType>;
93    /// Synthesize for phase0. Any data passing to other steps should be stored inside `self`.
94    #[allow(unused_variables)]
95    fn raw_synthesize_phase0(&mut self, config: &Self::Config, layouter: &mut impl Layouter<F>) {}
96    /// Generate witnesses for phase1. Any data passing to other steps should be stored inside `self`.
97    #[allow(unused_variables)]
98    fn virtual_assign_phase1(&mut self, builder: &mut RlcCircuitBuilder<F>) {}
99    /// Synthesize for phase1. Any data passing to other steps should be stored inside `self`.
100    #[allow(unused_variables)]
101    fn raw_synthesize_phase1(&mut self, config: &Self::Config, layouter: &mut impl Layouter<F>) {}
102}
103
104#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug)]
105pub struct LoaderParamsPerComponentType {
106    pub component_type_id: ComponentTypeId,
107    pub loader_params: SingleComponentLoaderParams,
108}
109
110/// A ComponentModule load promise results from other components and owns some columns and corresponding gates.
111/// All ComponentModules in a single circuit share a RlcCircuitBuilder and they communicate with each other through PromiseCollector.
112pub trait PromiseBuilder<F: Field>: ComponentBuilder<F> {
113    /// Get component type dependencies of this ComponentBuilder in a determinstic order.
114    fn get_component_type_dependencies() -> Vec<ComponentTypeId>;
115    /// Extract loader params per component type from circuit params.
116    /// Assumption: Return value is in a deterministic order which we use to compute the promise commit.
117    fn extract_loader_params_per_component_type(
118        params: &Self::Params,
119    ) -> Vec<LoaderParamsPerComponentType>;
120    /// Fulfill promise results.
121    fn fulfill_promise_results(&mut self, promise_results_getter: &impl PromiseResultsGetter<F>);
122    /// Generate witnesses for phase0. Any data passing to other steps should be stored inside `self`.
123    /// Also need to set promise result commits.
124    fn virtual_assign_phase0(
125        &mut self,
126        builder: &mut RlcCircuitBuilder<F>,
127        promise_commit_setter: &mut impl PromiseCommitSetter<F>,
128    );
129    /// Synthesize for phase0. Any data passing to other steps should be stored inside `self`.
130    fn raw_synthesize_phase0(&mut self, config: &Self::Config, layouter: &mut impl Layouter<F>);
131    /// Generate witnesses for phase1. Any data passing to other steps should be stored inside `self`.
132    fn virtual_assign_phase1(
133        &mut self,
134        builder: &mut RlcCircuitBuilder<F>,
135        promise_calls_getter: &mut impl PromiseCallsGetter<F>,
136    );
137    /// Synthesize for phase1. Any data passing to other steps should be stored inside `self`.
138    fn raw_synthesize_phase1(&mut self, config: &Self::Config, layouter: &mut impl Layouter<F>);
139}