proof_of_sql/sql/evm_proof_plan/
proof_plan.rs

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