proof_of_sql/sql/evm_proof_plan/
proof_plan.rs

1use super::{plans::EVMDynProofPlan, EVMProofPlanError, EVMProofPlanResult};
2use crate::{
3    base::{
4        database::{
5            ColumnField, ColumnRef, ColumnType, LiteralValue, OwnedTable, Table, TableEvaluation,
6            TableRef,
7        },
8        map::{IndexMap, IndexSet},
9        proof::{PlaceholderResult, ProofError},
10        scalar::Scalar,
11    },
12    sql::{
13        proof::{
14            FinalRoundBuilder, FirstRoundBuilder, ProofPlan, ProverEvaluate, VerificationBuilder,
15        },
16        proof_plans::DynProofPlan,
17    },
18};
19use alloc::{
20    string::{String, ToString},
21    vec::Vec,
22};
23use bumpalo::Bump;
24use core::str::FromStr;
25use itertools::Itertools;
26use serde::{Deserialize, Serialize, Serializer};
27use sqlparser::ast::Ident;
28
29#[derive(Debug)]
30/// An implementation of `ProofPlan` that allows for EVM compatible serialization.
31/// Serialization should be done using bincode with fixint, big-endian encoding in order to be compatible with EVM.
32///
33/// This is simply a wrapper around a `DynProofPlan`.
34pub struct EVMProofPlan {
35    inner: DynProofPlan,
36}
37
38impl EVMProofPlan {
39    /// Create a new `EVMProofPlan` from a `DynProofPlan`.
40    #[must_use]
41    pub fn new(plan: DynProofPlan) -> Self {
42        Self { inner: plan }
43    }
44    /// Get the inner `DynProofPlan`.
45    #[must_use]
46    pub fn into_inner(self) -> DynProofPlan {
47        self.inner
48    }
49    /// Get a reference to the inner `DynProofPlan`.
50    #[must_use]
51    pub fn inner(&self) -> &DynProofPlan {
52        &self.inner
53    }
54}
55
56#[derive(Serialize, Deserialize)]
57struct CompactPlan {
58    tables: Vec<String>,
59    columns: Vec<(usize, String, ColumnType)>,
60    output_column_names: Vec<String>,
61    plan: EVMDynProofPlan,
62}
63
64impl TryFrom<&EVMProofPlan> for CompactPlan {
65    type Error = EVMProofPlanError;
66
67    fn try_from(value: &EVMProofPlan) -> Result<Self, Self::Error> {
68        let table_refs = value.get_table_references();
69        let column_refs = value.get_column_references();
70        let output_column_names = value
71            .get_column_result_fields()
72            .iter()
73            .map(|field| field.name().to_string())
74            .collect();
75
76        let plan = EVMDynProofPlan::try_from_proof_plan(value.inner(), &table_refs, &column_refs)?;
77        let columns = column_refs
78            .into_iter()
79            .map(|column_ref| -> EVMProofPlanResult<_> {
80                let table_index = table_refs
81                    .get_index_of(&column_ref.table_ref())
82                    .ok_or(EVMProofPlanError::TableNotFound)?;
83                Ok((
84                    table_index,
85                    column_ref.column_id().to_string(),
86                    *column_ref.column_type(),
87                ))
88            })
89            .try_collect()?;
90        let tables = table_refs.iter().map(ToString::to_string).collect();
91
92        Ok(Self {
93            tables,
94            columns,
95            output_column_names,
96            plan,
97        })
98    }
99}
100
101impl TryFrom<CompactPlan> for EVMProofPlan {
102    type Error = EVMProofPlanError;
103
104    fn try_from(value: CompactPlan) -> Result<Self, Self::Error> {
105        let table_refs: IndexSet<TableRef> = value
106            .tables
107            .iter()
108            .map(|table| TableRef::from_str(table).map_err(|_| EVMProofPlanError::InvalidTableName))
109            .try_collect()?;
110        let table_refs_clone = table_refs.clone();
111        let column_refs: IndexSet<ColumnRef> = value
112            .columns
113            .iter()
114            .map(|(i, ident, column_type)| -> EVMProofPlanResult<_> {
115                let table_ref = table_refs_clone
116                    .get_index(*i)
117                    .cloned()
118                    .ok_or(EVMProofPlanError::TableNotFound)?;
119                Ok(ColumnRef::new(table_ref, Ident::new(ident), *column_type))
120            })
121            .try_collect()?;
122        let output_column_names: IndexSet<String> = value.output_column_names.into_iter().collect();
123        Ok(Self {
124            inner: value.plan.try_into_proof_plan(
125                &table_refs,
126                &column_refs,
127                &output_column_names,
128            )?,
129        })
130    }
131}
132
133impl Serialize for EVMProofPlan {
134    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
135        CompactPlan::try_from(self)
136            .map_err(serde::ser::Error::custom)?
137            .serialize(serializer)
138    }
139}
140
141impl<'de> Deserialize<'de> for EVMProofPlan {
142    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
143    where
144        D: serde::Deserializer<'de>,
145    {
146        CompactPlan::deserialize(deserializer)?
147            .try_into()
148            .map_err(serde::de::Error::custom)
149    }
150}
151
152impl ProofPlan for EVMProofPlan {
153    fn verifier_evaluate<S: Scalar>(
154        &self,
155        builder: &mut impl VerificationBuilder<S>,
156        accessor: &IndexMap<TableRef, IndexMap<Ident, S>>,
157        result: Option<&OwnedTable<S>>,
158        chi_eval_map: &IndexMap<TableRef, S>,
159        params: &[LiteralValue],
160    ) -> Result<TableEvaluation<S>, ProofError> {
161        self.inner()
162            .verifier_evaluate(builder, accessor, result, chi_eval_map, params)
163    }
164    fn get_column_result_fields(&self) -> Vec<ColumnField> {
165        self.inner().get_column_result_fields()
166    }
167    fn get_column_references(&self) -> IndexSet<ColumnRef> {
168        self.inner().get_column_references()
169    }
170    fn get_table_references(&self) -> IndexSet<TableRef> {
171        self.inner().get_table_references()
172    }
173}
174impl ProverEvaluate for EVMProofPlan {
175    fn first_round_evaluate<'a, S: Scalar>(
176        &self,
177        builder: &mut FirstRoundBuilder<'a, S>,
178        alloc: &'a Bump,
179        table_map: &IndexMap<TableRef, Table<'a, S>>,
180        params: &[LiteralValue],
181    ) -> PlaceholderResult<Table<'a, S>> {
182        self.inner()
183            .first_round_evaluate(builder, alloc, table_map, params)
184    }
185    fn final_round_evaluate<'a, S: Scalar>(
186        &self,
187        builder: &mut FinalRoundBuilder<'a, S>,
188        alloc: &'a Bump,
189        table_map: &IndexMap<TableRef, Table<'a, S>>,
190        params: &[LiteralValue],
191    ) -> PlaceholderResult<Table<'a, S>> {
192        self.inner()
193            .final_round_evaluate(builder, alloc, table_map, params)
194    }
195}