diff --git a/crates/proof-of-sql/src/sql/proof/indexes.rs b/crates/proof-of-sql/src/sql/proof/indexes.rs deleted file mode 100644 index 4dc97470c..000000000 --- a/crates/proof-of-sql/src/sql/proof/indexes.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::base::{polynomial::compute_truncated_lagrange_basis_sum, scalar::Scalar}; -use alloc::vec::Vec; -use core::{ops::Range, slice}; -use num_traits::Zero; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -/// Indexes of a table for use in the [`ProvableQueryResult`](crate::sql::proof::ProvableQueryResult) -pub enum Indexes { - /// Sparse indexes. (i.e. explicitly specified indexes) - Sparse(Vec), - /// Dense indexes. (i.e. all indexes in a range, which means the indexes do not need to be sent to the verifier) - Dense(Range), -} - -impl Default for Indexes { - fn default() -> Self { - Self::Sparse(Vec::default()) - } -} - -impl Indexes { - /// Check if the indexes are valid for a table with n rows - pub fn valid(&self, n: usize) -> bool { - let n = n as u64; - match &self { - Self::Sparse(ix) => { - if ix.is_empty() { - return true; - } - let index = ix[0]; - if index >= n { - return false; - } - let mut prev_index = index; - for index in ix.iter().skip(1) { - if *index <= prev_index || *index >= n { - return false; - } - prev_index = *index; - } - true - } - Self::Dense(range) => range.end <= n && (range.start < range.end || range.start == 0), - } - } - /// Get an iterator over the indexes - pub fn iter(&self) -> impl Iterator + '_ { - enum Iter<'a> { - Sparse(slice::Iter<'a, u64>), - Dense(Range), - } - impl<'a> Iterator for Iter<'a> { - type Item = u64; - fn next(&mut self) -> Option { - match self { - Iter::Sparse(iter) => iter.next().copied(), - Iter::Dense(iter) => iter.next(), - } - } - } - match self { - Self::Sparse(vec) => Iter::Sparse(vec.iter()), - Self::Dense(range) => Iter::Dense(range.clone()), - } - } - /// Get the number of indexes - pub fn len(&self) -> usize { - match self { - Self::Sparse(vec) => vec.len(), - Self::Dense(range) => { - if range.end <= range.start { - 0 - } else { - (range.end - range.start) as usize - } - } - } - } - /// Check if the number of indexes is zero. - pub fn is_empty(&self) -> bool { - match self { - Self::Sparse(vec) => vec.is_empty(), - Self::Dense(range) => range.end <= range.start, - } - } - - /// Evaluates the mle that is 1 at the indexes and 0 elsewhere at the given evaluation point. - /// This returne None for Sparse indexes and the actual value for Dense indexes. - pub fn evaluate_at_point(&self, evaluation_point: &[S]) -> Option { - match self { - Indexes::Sparse(_) => None, - Indexes::Dense(range) => { - if range.is_empty() { - Some(Zero::zero()) - } else if range.end as usize > 2usize.pow(evaluation_point.len() as u32) { - // This only happens when the indexes are tampered with. - None - } else { - Some( - compute_truncated_lagrange_basis_sum(range.end as usize, evaluation_point) - - compute_truncated_lagrange_basis_sum( - range.start as usize, - evaluation_point, - ), - ) - } - } - } - } -} diff --git a/crates/proof-of-sql/src/sql/proof/indexes_test.rs b/crates/proof-of-sql/src/sql/proof/indexes_test.rs deleted file mode 100644 index b6a717f8d..000000000 --- a/crates/proof-of-sql/src/sql/proof/indexes_test.rs +++ /dev/null @@ -1,218 +0,0 @@ -use super::Indexes; -use crate::base::{ - polynomial::compute_evaluation_vector, - scalar::{Curve25519Scalar, MontScalar}, -}; -use num_traits::Zero; - -#[test] -fn an_empty_sparse_index_slice_is_always_valid() { - let ix = Indexes::Sparse(vec![]); - assert!(ix.valid(0)); - assert!(ix.valid(1)); -} - -#[test] -fn a_single_sparse_index_is_valid_if_within_range() { - let ix = Indexes::Sparse(vec![0]); - assert!(!ix.valid(0)); - assert!(ix.valid(1)); -} - -#[test] -fn multiple_sparse_indexes_are_valid_if_sorted_and_within_range() { - let ix = Indexes::Sparse(vec![0, 1]); - assert!(ix.valid(2)); - assert!(!ix.valid(1)); - - let ix = Indexes::Sparse(vec![1, 0]); - assert!(!ix.valid(2)); - - let ix = Indexes::Sparse(vec![0, 2, 3, 7]); - assert!(ix.valid(8)); - assert!(!ix.valid(7)); - - let ix = Indexes::Sparse(vec![0, 3, 2, 7]); - assert!(!ix.valid(8)); -} - -#[test] -fn repeated_sparse_indexes_are_invalid() { - let ix = Indexes::Sparse(vec![0, 1, 1]); - assert!(!ix.valid(2)); -} - -#[test] -fn dense_indexes_are_valid_if_within_range() { - let ix = Indexes::Dense(0..0); - assert!(ix.valid(1)); - assert!(ix.valid(0)); - - let ix = Indexes::Dense(0..1); - assert!(ix.valid(1)); - assert!(!ix.valid(0)); - - let ix = Indexes::Dense(0..2); - assert!(ix.valid(2)); - assert!(!ix.valid(1)); - - let ix = Indexes::Dense(1..2); - assert!(ix.valid(2)); - assert!(!ix.valid(1)); - - let ix = Indexes::Dense(2..8); - assert!(ix.valid(8)); - assert!(!ix.valid(7)); -} - -#[test] -fn empty_dense_indexes_are_invalid_if_start_and_end_are_not_0() { - let ix = Indexes::Dense(0..0); - assert!(ix.valid(10)); - assert!(ix.valid(0)); - let ix = Indexes::Dense(3..3); - assert!(!ix.valid(10)); - assert!(!ix.valid(0)); - #[allow(clippy::reversed_empty_ranges)] - let ix = Indexes::Dense(3..2); - assert!(!ix.valid(10)); - assert!(!ix.valid(0)); -} - -#[test] -fn we_can_get_the_len_of_indexes() { - let ix = Indexes::Sparse(vec![0, 1, 1]); - assert_eq!(ix.len(), 3); - - let ix = Indexes::Sparse(vec![]); - assert_eq!(ix.len(), 0); - - let ix = Indexes::Dense(0..0); - assert_eq!(ix.len(), 0); - - let ix = Indexes::Dense(0..1); - assert_eq!(ix.len(), 1); - - #[allow(clippy::reversed_empty_ranges)] - let ix = Indexes::Dense(3..2); - assert_eq!(ix.len(), 0); - - let ix = Indexes::Dense(1..2); - assert_eq!(ix.len(), 1); - - let ix = Indexes::Dense(2..8); - assert_eq!(ix.len(), 6); -} - -#[test] -fn we_can_get_the_emptiness_of_indexes() { - let ix = Indexes::Sparse(vec![0, 1, 1]); - assert!(!ix.is_empty()); - - let ix = Indexes::Sparse(vec![]); - assert!(ix.is_empty()); - - let ix = Indexes::Dense(0..0); - assert!(ix.is_empty()); - - let ix = Indexes::Dense(0..1); - assert!(!ix.is_empty()); - - #[allow(clippy::reversed_empty_ranges)] - let ix = Indexes::Dense(3..2); - assert!(ix.is_empty()); - - let ix = Indexes::Dense(1..2); - assert!(!ix.is_empty()); - - let ix = Indexes::Dense(2..8); - assert!(!ix.is_empty()); -} - -#[test] -fn we_can_calculate_the_sum_and_prod_using_iter_for_indexes() { - let ix = Indexes::Sparse(vec![0, 1, 1]); - assert_eq!(ix.iter().sum::(), 2); - assert_eq!(ix.iter().product::(), 0); - - let ix = Indexes::Sparse(vec![]); - assert_eq!(ix.iter().sum::(), 0); - assert_eq!(ix.iter().product::(), 1); - - let ix = Indexes::Sparse(vec![2, 3, 5]); - assert_eq!(ix.iter().sum::(), 10); - assert_eq!(ix.iter().product::(), 30); - - let ix = Indexes::Dense(0..0); - assert_eq!(ix.iter().sum::(), 0); - assert_eq!(ix.iter().product::(), 1); - - let ix = Indexes::Dense(0..1); - assert_eq!(ix.iter().sum::(), 0); - assert_eq!(ix.iter().product::(), 0); - - #[allow(clippy::reversed_empty_ranges)] - let ix = Indexes::Dense(3..2); - assert_eq!(ix.iter().sum::(), 0); - assert_eq!(ix.iter().product::(), 1); - - let ix = Indexes::Dense(1..2); - assert_eq!(ix.iter().sum::(), 1); - assert_eq!(ix.iter().product::(), 1); - - let ix = Indexes::Dense(2..8); - assert_eq!(ix.iter().sum::(), 27); - assert_eq!(ix.iter().product::(), 5040); -} - -#[test] -fn we_can_evaluate_indexes_at_an_evaluation_point() { - let evaluation_point = [ - Curve25519Scalar::from(3u64), - Curve25519Scalar::from(5u64), - Curve25519Scalar::from(7u64), - ]; - let mut evaluation_vector = vec![MontScalar::default(); 8]; - compute_evaluation_vector(&mut evaluation_vector, &evaluation_point); - - let ix = Indexes::Sparse(vec![0, 1, 1]); - assert_eq!(ix.evaluate_at_point(&evaluation_point), None); - - let ix = Indexes::Sparse(vec![]); - assert_eq!(ix.evaluate_at_point(&evaluation_point), None); - - let ix = Indexes::Sparse(vec![2, 3, 5]); - assert_eq!(ix.evaluate_at_point(&evaluation_point), None); - - let ix = Indexes::Dense(0..0); - assert_eq!(ix.evaluate_at_point(&evaluation_point), Some(Zero::zero())); - - let ix = Indexes::Dense(0..1); - assert_eq!( - ix.evaluate_at_point(&evaluation_point), - Some(evaluation_vector[0]) - ); - - #[allow(clippy::reversed_empty_ranges)] - let ix = Indexes::Dense(3..2); - assert_eq!(ix.evaluate_at_point(&evaluation_point), Some(Zero::zero())); - - let ix = Indexes::Dense(1..2); - assert_eq!( - ix.evaluate_at_point(&evaluation_point), - Some(evaluation_vector[1]) - ); - - let ix = Indexes::Dense(2..8); - assert_eq!( - ix.evaluate_at_point(&evaluation_point), - Some( - evaluation_vector[2] - + evaluation_vector[3] - + evaluation_vector[4] - + evaluation_vector[5] - + evaluation_vector[6] - + evaluation_vector[7] - ) - ); -} diff --git a/crates/proof-of-sql/src/sql/proof/mod.rs b/crates/proof-of-sql/src/sql/proof/mod.rs index 4c993760a..c3082b476 100644 --- a/crates/proof-of-sql/src/sql/proof/mod.rs +++ b/crates/proof-of-sql/src/sql/proof/mod.rs @@ -68,10 +68,5 @@ pub(crate) use result_element_serialization::{ decode_and_convert, decode_multiple_elements, ProvableResultElement, }; -mod indexes; -pub(crate) use indexes::Indexes; -#[cfg(test)] -mod indexes_test; - mod result_builder; pub(crate) use result_builder::ResultBuilder; diff --git a/crates/proof-of-sql/src/sql/proof/proof_builder_test.rs b/crates/proof-of-sql/src/sql/proof/proof_builder_test.rs index d5d258940..788920551 100644 --- a/crates/proof-of-sql/src/sql/proof/proof_builder_test.rs +++ b/crates/proof-of-sql/src/sql/proof/proof_builder_test.rs @@ -6,7 +6,7 @@ use crate::{ polynomial::{compute_evaluation_vector, CompositePolynomial, MultilinearExtension}, scalar::Curve25519Scalar, }, - sql::proof::{Indexes, SumcheckSubpolynomialType}, + sql::proof::SumcheckSubpolynomialType, }; use alloc::sync::Arc; #[cfg(feature = "arrow")] @@ -136,10 +136,9 @@ fn we_can_form_an_aggregated_sumcheck_polynomial() { #[cfg(feature = "arrow")] #[test] fn we_can_form_the_provable_query_result() { - let result_indexes = Indexes::Sparse(vec![1, 2]); - let col1: Column = Column::BigInt(&[10_i64, 11, 12]); - let col2: Column = Column::BigInt(&[-2_i64, -3, -4]); - let res = ProvableQueryResult::new(&result_indexes, &[col1, col2]); + let col1: Column = Column::BigInt(&[11_i64, 12]); + let col2: Column = Column::BigInt(&[-3_i64, -4]); + let res = ProvableQueryResult::new(2, &[col1, col2]); let column_fields = vec![ ColumnField::new("a".parse().unwrap(), ColumnType::BigInt), diff --git a/crates/proof-of-sql/src/sql/proof/provable_query_result.rs b/crates/proof-of-sql/src/sql/proof/provable_query_result.rs index 57d037780..9e4e7ba14 100644 --- a/crates/proof-of-sql/src/sql/proof/provable_query_result.rs +++ b/crates/proof-of-sql/src/sql/proof/provable_query_result.rs @@ -1,6 +1,4 @@ -use super::{ - decode_and_convert, decode_multiple_elements, Indexes, ProvableResultColumn, QueryError, -}; +use super::{decode_and_convert, decode_multiple_elements, ProvableResultColumn, QueryError}; use crate::base::{ database::{Column, ColumnField, ColumnType, OwnedColumn, OwnedTable}, polynomial::compute_evaluation_vector, @@ -15,7 +13,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct ProvableQueryResult { num_columns: u64, - indexes: Indexes, + pub(crate) table_length: u64, data: Vec, } @@ -25,23 +23,17 @@ impl ProvableQueryResult { pub fn num_columns(&self) -> usize { self.num_columns as usize } - /// The indexes in the result. - #[must_use] - pub fn indexes(&self) -> &Indexes { - &self.indexes - } - /// A mutable reference to a the indexes in the result. Because the struct is deserialized from untrusted data, it - /// cannot maintain any invariant on its data members; hence, this function is available to allow for easy manipulation for testing. - #[cfg(test)] - pub fn indexes_mut(&mut self) -> &mut Indexes { - &mut self.indexes - } /// A mutable reference to the number of columns in the result. Because the struct is deserialized from untrusted data, it /// cannot maintain any invariant on its data members; hence, this function is available to allow for easy manipulation for testing. #[cfg(test)] pub fn num_columns_mut(&mut self) -> &mut u64 { &mut self.num_columns } + /// The number of rows in the result + #[must_use] + pub fn table_length(&self) -> usize { + self.table_length as usize + } /// A mutable reference to the underlying encoded data of the result. Because the struct is deserialized from untrusted data, it /// cannot maintain any invariant on its data members; hence, this function is available to allow for easy manipulation for testing. #[cfg(test)] @@ -51,29 +43,36 @@ impl ProvableQueryResult { /// This function is available to allow for easy creation for testing. #[cfg(test)] #[must_use] - pub fn new_from_raw_data(num_columns: u64, indexes: Indexes, data: Vec) -> Self { + pub fn new_from_raw_data(num_columns: u64, table_length: u64, data: Vec) -> Self { Self { num_columns, - indexes, + table_length, data, } } /// Form intermediate query result from index rows and result columns + /// # Panics + /// + /// Will panic if `table_length` is somehow larger than the length of some column + /// which should never happen. #[must_use] - pub fn new<'a, S: Scalar>(indexes: &'a Indexes, columns: &'a [Column<'a, S>]) -> Self { + pub fn new<'a, S: Scalar>(table_length: u64, columns: &'a [Column<'a, S>]) -> Self { + assert!(columns + .iter() + .all(|column| table_length == column.len() as u64)); let mut sz = 0; for col in columns { - sz += col.num_bytes(indexes); + sz += col.num_bytes(table_length); } let mut data = vec![0u8; sz]; let mut sz = 0; for col in columns { - sz += col.write(&mut data[sz..], indexes); + sz += col.write(&mut data[sz..], table_length); } ProvableQueryResult { num_columns: columns.len() as u64, - indexes: indexes.clone(), + table_length, data, } } @@ -91,32 +90,20 @@ impl ProvableQueryResult { pub fn evaluate( &self, evaluation_point: &[S], - table_length: usize, + output_length: usize, column_result_fields: &[ColumnField], ) -> Result, QueryError> { if self.num_columns as usize != column_result_fields.len() { return Err(QueryError::InvalidColumnCount); } - - if !self.indexes.valid(table_length) { - return Err(QueryError::InvalidIndexes); - } - - let evaluation_vec_len = self - .indexes - .iter() - .max() - .map(|max| max as usize + 1) - .unwrap_or(0); - let mut evaluation_vec = vec![Zero::zero(); evaluation_vec_len]; + let mut evaluation_vec = vec![Zero::zero(); output_length]; compute_evaluation_vector(&mut evaluation_vec, evaluation_point); - let mut offset: usize = 0; let mut res = Vec::with_capacity(self.num_columns as usize); for field in column_result_fields { let mut val = S::zero(); - for index in self.indexes.iter() { + for entry in evaluation_vec.iter().take(output_length) { let (x, sz) = match field.data_type() { ColumnType::Boolean => decode_and_convert::(&self.data[offset..]), ColumnType::TinyInt => decode_and_convert::(&self.data[offset..]), @@ -133,12 +120,11 @@ impl ProvableQueryResult { decode_and_convert::(&self.data[offset..]) } }?; - val += evaluation_vec[index as usize] * x; + val += *entry * x; offset += sz; } res.push(val); } - if offset != self.data.len() { return Err(QueryError::MiscellaneousEvaluationError); } @@ -161,7 +147,7 @@ impl ProvableQueryResult { return Err(QueryError::InvalidColumnCount); } - let n = self.indexes.len(); + let n = self.table_length(); let mut offset: usize = 0; let owned_table = OwnedTable::try_new( diff --git a/crates/proof-of-sql/src/sql/proof/provable_query_result_test.rs b/crates/proof-of-sql/src/sql/proof/provable_query_result_test.rs index ce2088ee9..3540de040 100644 --- a/crates/proof-of-sql/src/sql/proof/provable_query_result_test.rs +++ b/crates/proof-of-sql/src/sql/proof/provable_query_result_test.rs @@ -1,12 +1,9 @@ use super::{ProvableQueryResult, QueryError}; -use crate::{ - base::{ - database::{Column, ColumnField, ColumnType}, - math::decimal::Precision, - polynomial::compute_evaluation_vector, - scalar::{Curve25519Scalar, Scalar}, - }, - sql::proof::Indexes, +use crate::base::{ + database::{Column, ColumnField, ColumnType}, + math::decimal::Precision, + polynomial::compute_evaluation_vector, + scalar::{Curve25519Scalar, Scalar}, }; use alloc::sync::Arc; use arrow::{ @@ -19,7 +16,7 @@ use num_traits::Zero; #[test] fn we_can_convert_an_empty_provable_result_to_a_final_result() { let cols: [Column; 1] = [Column::BigInt(&[0_i64; 0])]; - let res = ProvableQueryResult::new(&Indexes::Sparse(vec![]), &cols); + let res = ProvableQueryResult::new(0, &cols); let column_fields = vec![ColumnField::new("a1".parse().unwrap(), ColumnType::BigInt)]; let res = RecordBatch::try_from( res.to_owned_table::(&column_fields) @@ -38,42 +35,37 @@ fn we_can_convert_an_empty_provable_result_to_a_final_result() { #[test] fn we_can_evaluate_result_columns_as_mles() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, -12])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 1] = [Column::BigInt(&[10, -12])]; + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 2, &column_fields[..]) .unwrap(); #[allow(clippy::possible_missing_comma)] let expected_evals = [Curve25519Scalar::from(10u64) * evaluation_vec[0] - - Curve25519Scalar::from(12u64) * evaluation_vec[2]]; + - Curve25519Scalar::from(12u64) * evaluation_vec[1]]; assert_eq!(evals, expected_evals); } #[test] fn we_can_evaluate_result_columns_with_no_rows() { - let indexes = Indexes::Sparse(vec![]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let res = ProvableQueryResult::new(&indexes, &cols); - let evaluation_point = [ - Curve25519Scalar::from(10u64), - Curve25519Scalar::from(100u64), - ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let cols: [Column; 1] = [Column::BigInt(&[0; 0])]; + let res = ProvableQueryResult::new(0, &cols); + let evaluation_point = []; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 0]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 0, &column_fields[..]) .unwrap(); let expected_evals = [Curve25519Scalar::zero()]; assert_eq!(evals, expected_evals); @@ -81,52 +73,48 @@ fn we_can_evaluate_result_columns_with_no_rows() { #[test] fn we_can_evaluate_multiple_result_columns_as_mles() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 2] = - [Column::BigInt(&[10, 11, 12]), Column::BigInt(&[5, 7, 9])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 2] = [Column::BigInt(&[10, 12]), Column::BigInt(&[5, 9])]; + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 2, &column_fields[..]) .unwrap(); let expected_evals = [ Curve25519Scalar::from(10u64) * evaluation_vec[0] - + Curve25519Scalar::from(12u64) * evaluation_vec[2], + + Curve25519Scalar::from(12u64) * evaluation_vec[1], Curve25519Scalar::from(5u64) * evaluation_vec[0] - + Curve25519Scalar::from(9u64) * evaluation_vec[2], + + Curve25519Scalar::from(9u64) * evaluation_vec[1], ]; assert_eq!(evals, expected_evals); } #[test] fn we_can_evaluate_multiple_result_columns_as_mles_with_128_bits() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 2] = - [Column::Int128(&[10, 11, 12]), Column::Int128(&[5, 7, 9])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 2] = [Column::Int128(&[10, 12]), Column::Int128(&[5, 9])]; + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::Int128); cols.len()]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 2, &column_fields[..]) .unwrap(); let expected_evals = [ Curve25519Scalar::from(10u64) * evaluation_vec[0] - + Curve25519Scalar::from(12u64) * evaluation_vec[2], + + Curve25519Scalar::from(12u64) * evaluation_vec[1], Curve25519Scalar::from(5u64) * evaluation_vec[0] - + Curve25519Scalar::from(9u64) * evaluation_vec[2], + + Curve25519Scalar::from(9u64) * evaluation_vec[1], ]; assert_eq!(evals, expected_evals); } @@ -134,194 +122,141 @@ fn we_can_evaluate_multiple_result_columns_as_mles_with_128_bits() { #[allow(clippy::similar_names)] #[test] fn we_can_evaluate_multiple_result_columns_as_mles_with_scalar_columns() { - let indexes = Indexes::Sparse(vec![0, 2]); - let col0 = [10, 11, 12] + let col0 = [10, 12] .iter() .map(|v| Curve25519Scalar::from(*v)) .collect::>(); - let col1 = [5, 7, 9] + let col1 = [5, 9] .iter() .map(|v| Curve25519Scalar::from(*v)) .collect::>(); let cols: [Column; 2] = [Column::Scalar(&col0), Column::Scalar(&col1)]; - let res = ProvableQueryResult::new(&indexes, &cols); + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::Scalar); cols.len()]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 2, &column_fields[..]) .unwrap(); let expected_evals = [ Curve25519Scalar::from(10u64) * evaluation_vec[0] - + Curve25519Scalar::from(12u64) * evaluation_vec[2], + + Curve25519Scalar::from(12u64) * evaluation_vec[1], Curve25519Scalar::from(5u64) * evaluation_vec[0] - + Curve25519Scalar::from(9u64) * evaluation_vec[2], + + Curve25519Scalar::from(9u64) * evaluation_vec[1], ]; assert_eq!(evals, expected_evals); } #[test] fn we_can_evaluate_multiple_result_columns_as_mles_with_mixed_data_types() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 2] = - [Column::BigInt(&[10, 11, 12]), Column::Int128(&[5, 7, 9])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 2] = [Column::BigInt(&[10, 12]), Column::Int128(&[5, 9])]; + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = [ ColumnField::new("a".parse().unwrap(), ColumnType::BigInt), ColumnField::new("a".parse().unwrap(), ColumnType::Int128), ]; let evals = res - .evaluate(&evaluation_point, 4, &column_fields[..]) + .evaluate(&evaluation_point, 2, &column_fields[..]) .unwrap(); let expected_evals = [ Curve25519Scalar::from(10u64) * evaluation_vec[0] - + Curve25519Scalar::from(12u64) * evaluation_vec[2], + + Curve25519Scalar::from(12u64) * evaluation_vec[1], Curve25519Scalar::from(5u64) * evaluation_vec[0] - + Curve25519Scalar::from(9u64) * evaluation_vec[2], + + Curve25519Scalar::from(9u64) * evaluation_vec[1], ]; assert_eq!(evals, expected_evals); } -#[test] -fn evaluation_fails_if_indexes_are_out_of_range() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let mut res = ProvableQueryResult::new(&indexes, &cols); - match res.indexes_mut() { - Indexes::Sparse(indexes) => indexes[1] = 20, - _ => panic!("unexpected indexes type"), - } - let evaluation_point = [ - Curve25519Scalar::from(10u64), - Curve25519Scalar::from(100u64), - ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; - compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); - let column_fields = - vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; - assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), - Err(QueryError::InvalidIndexes) - )); -} - -#[test] -fn evaluation_fails_if_indexes_are_not_sorted() { - let indexes = Indexes::Sparse(vec![1, 0]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let res = ProvableQueryResult::new(&indexes, &cols); - let evaluation_point = [ - Curve25519Scalar::from(10u64), - Curve25519Scalar::from(100u64), - ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; - compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); - let column_fields = - vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; - assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), - Err(QueryError::InvalidIndexes) - )); -} - #[test] fn evaluation_fails_if_extra_data_is_included() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let mut res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 1] = [Column::BigInt(&[10, 12])]; + let mut res = ProvableQueryResult::new(2, &cols); res.data_mut().push(3u8); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); cols.len()]; assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), + res.evaluate(&evaluation_point, 2, &column_fields[..]), Err(QueryError::MiscellaneousEvaluationError) )); } #[test] fn evaluation_fails_if_the_result_cant_be_decoded() { - let mut res = ProvableQueryResult::new_from_raw_data( - 1, - Indexes::Sparse(vec![0]), - vec![0b1111_1111_u8; 38], - ); + let mut res = ProvableQueryResult::new_from_raw_data(1, 1, vec![0b1111_1111_u8; 38]); res.data_mut()[37] = 0b0000_0001_u8; let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); res.num_columns()]; assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), + res.evaluate(&evaluation_point, 2, &column_fields[..]), Err(QueryError::Overflow) )); } #[test] fn evaluation_fails_if_integer_overflow_happens() { - let indexes = Indexes::Sparse(vec![0, 2]); - let binding = [i64::from(i32::MAX) + 1_i64, 11, 12]; + let binding = [i64::from(i32::MAX) + 1_i64, 12]; let cols: [Column; 1] = [Column::BigInt(&binding)]; - let res = ProvableQueryResult::new(&indexes, &cols); + let res = ProvableQueryResult::new(2, &cols); let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::Int); res.num_columns()]; assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), + res.evaluate(&evaluation_point, 2, &column_fields[..]), Err(QueryError::Overflow) )); } #[test] fn evaluation_fails_if_data_is_missing() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let mut res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 1] = [Column::BigInt(&[10, 12])]; + let mut res = ProvableQueryResult::new(2, &cols); *res.num_columns_mut() = 3; let evaluation_point = [ Curve25519Scalar::from(10u64), Curve25519Scalar::from(100u64), ]; - let mut evaluation_vec = [Curve25519Scalar::ZERO; 4]; + let mut evaluation_vec = [Curve25519Scalar::ZERO; 2]; compute_evaluation_vector(&mut evaluation_vec, &evaluation_point); let column_fields = vec![ColumnField::new("a".parse().unwrap(), ColumnType::BigInt); res.num_columns()]; assert!(matches!( - res.evaluate(&evaluation_point, 4, &column_fields[..]), + res.evaluate(&evaluation_point, 2, &column_fields[..]), Err(QueryError::Overflow) )); } #[test] fn we_can_convert_a_provable_result_to_a_final_result() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::BigInt(&[10, 11, 12])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 1] = [Column::BigInt(&[10, 12])]; + let res = ProvableQueryResult::new(2, &cols); let column_fields = vec![ColumnField::new("a1".parse().unwrap(), ColumnType::BigInt)]; let res = RecordBatch::try_from( res.to_owned_table::(&column_fields) @@ -340,9 +275,8 @@ fn we_can_convert_a_provable_result_to_a_final_result() { #[test] fn we_can_convert_a_provable_result_to_a_final_result_with_128_bits() { - let indexes = Indexes::Sparse(vec![0, 2]); - let cols: [Column; 1] = [Column::Int128(&[10, 11, i128::MAX])]; - let res = ProvableQueryResult::new(&indexes, &cols); + let cols: [Column; 1] = [Column::Int128(&[10, i128::MAX])]; + let res = ProvableQueryResult::new(2, &cols); let column_fields = vec![ColumnField::new("a1".parse().unwrap(), ColumnType::Int128)]; let res = RecordBatch::try_from( res.to_owned_table::(&column_fields) @@ -368,15 +302,10 @@ fn we_can_convert_a_provable_result_to_a_final_result_with_128_bits() { #[test] fn we_can_convert_a_provable_result_to_a_final_result_with_252_bits() { - let indexes = Indexes::Sparse(vec![0, 2]); - let values = [ - Curve25519Scalar::from(10), - Curve25519Scalar::from(11), - Curve25519Scalar::MAX_SIGNED, - ]; + let values = [Curve25519Scalar::from(10), Curve25519Scalar::MAX_SIGNED]; let cols: [Column; 1] = [Column::Scalar(&values)]; - let res = ProvableQueryResult::new(&indexes, &cols); + let res = ProvableQueryResult::new(2, &cols); let column_fields = vec![ColumnField::new( "a1".parse().unwrap(), ColumnType::Decimal75(Precision::new(75).unwrap(), 0), @@ -406,19 +335,14 @@ fn we_can_convert_a_provable_result_to_a_final_result_with_252_bits() { #[test] fn we_can_convert_a_provable_result_to_a_final_result_with_mixed_data_types() { - let indexes = Indexes::Sparse(vec![0, 2]); - let values1: [i64; 3] = [6, 7, i64::MAX]; - let values2: [i128; 3] = [10, 11, i128::MAX]; - let values3 = ["abc", "fg", "de"]; + let values1: [i64; 2] = [6, i64::MAX]; + let values2: [i128; 2] = [10, i128::MAX]; + let values3 = ["abc", "de"]; let scalars3 = values3 .iter() .map(|v| Curve25519Scalar::from(*v)) .collect::>(); - let values4 = [ - Curve25519Scalar::from(10), - Curve25519Scalar::from(11), - Curve25519Scalar::MAX_SIGNED, - ]; + let values4 = [Curve25519Scalar::from(10), Curve25519Scalar::MAX_SIGNED]; let cols: [Column; 4] = [ Column::BigInt(&values1), @@ -426,7 +350,7 @@ fn we_can_convert_a_provable_result_to_a_final_result_with_mixed_data_types() { Column::VarChar((&values3, &scalars3)), Column::Scalar(&values4), ]; - let res = ProvableQueryResult::new(&indexes, &cols); + let res = ProvableQueryResult::new(2, &cols); let column_fields = vec![ ColumnField::new("a1".parse().unwrap(), ColumnType::BigInt), ColumnField::new("a2".parse().unwrap(), ColumnType::Int128), diff --git a/crates/proof-of-sql/src/sql/proof/provable_result_column.rs b/crates/proof-of-sql/src/sql/proof/provable_result_column.rs index bf883245b..c804e4738 100644 --- a/crates/proof-of-sql/src/sql/proof/provable_result_column.rs +++ b/crates/proof-of-sql/src/sql/proof/provable_result_column.rs @@ -1,4 +1,3 @@ -use super::Indexes; use crate::{ base::{database::Column, scalar::Scalar}, sql::proof::ProvableResultElement, @@ -7,24 +6,21 @@ use crate::{ /// Interface for serializing an intermediate result column pub trait ProvableResultColumn { /// The number of bytes of the serialized result column - fn num_bytes(&self, selection: &Indexes) -> usize; + fn num_bytes(&self, length: u64) -> usize; /// Serialize the result column - fn write(&self, out: &mut [u8], selection: &Indexes) -> usize; + fn write(&self, out: &mut [u8], length: u64) -> usize; } impl<'a, T: ProvableResultElement<'a>> ProvableResultColumn for &[T] { - fn num_bytes(&self, selection: &Indexes) -> usize { - let mut res = 0; - for i in selection.iter() { - res += self[i as usize].required_bytes(); - } - res + fn num_bytes(&self, length: u64) -> usize { + assert_eq!(self.len() as u64, length); + self.iter().map(ProvableResultElement::required_bytes).sum() } - fn write(&self, out: &mut [u8], selection: &Indexes) -> usize { + fn write(&self, out: &mut [u8], length: u64) -> usize { let mut res = 0; - for i in selection.iter() { + for i in 0..length { res += self[i as usize].encode(&mut out[res..]); } res @@ -32,39 +28,39 @@ impl<'a, T: ProvableResultElement<'a>> ProvableResultColumn for &[T] { } impl ProvableResultColumn for Column<'_, S> { - fn num_bytes(&self, selection: &Indexes) -> usize { + fn num_bytes(&self, length: u64) -> usize { match self { - Column::Boolean(col) => col.num_bytes(selection), - Column::TinyInt(col) => col.num_bytes(selection), - Column::SmallInt(col) => col.num_bytes(selection), - Column::Int(col) => col.num_bytes(selection), - Column::BigInt(col) | Column::TimestampTZ(_, _, col) => col.num_bytes(selection), - Column::Int128(col) => col.num_bytes(selection), - Column::Decimal75(_, _, col) | Column::Scalar(col) => col.num_bytes(selection), - Column::VarChar((col, _)) => col.num_bytes(selection), + Column::Boolean(col) => col.num_bytes(length), + Column::TinyInt(col) => col.num_bytes(length), + Column::SmallInt(col) => col.num_bytes(length), + Column::Int(col) => col.num_bytes(length), + Column::BigInt(col) | Column::TimestampTZ(_, _, col) => col.num_bytes(length), + Column::Int128(col) => col.num_bytes(length), + Column::Decimal75(_, _, col) | Column::Scalar(col) => col.num_bytes(length), + Column::VarChar((col, _)) => col.num_bytes(length), } } - fn write(&self, out: &mut [u8], selection: &Indexes) -> usize { + fn write(&self, out: &mut [u8], length: u64) -> usize { match self { - Column::Boolean(col) => col.write(out, selection), - Column::TinyInt(col) => col.write(out, selection), - Column::SmallInt(col) => col.write(out, selection), - Column::Int(col) => col.write(out, selection), - Column::BigInt(col) | Column::TimestampTZ(_, _, col) => col.write(out, selection), - Column::Int128(col) => col.write(out, selection), - Column::Decimal75(_, _, col) | Column::Scalar(col) => col.write(out, selection), - Column::VarChar((col, _)) => col.write(out, selection), + Column::Boolean(col) => col.write(out, length), + Column::TinyInt(col) => col.write(out, length), + Column::SmallInt(col) => col.write(out, length), + Column::Int(col) => col.write(out, length), + Column::BigInt(col) | Column::TimestampTZ(_, _, col) => col.write(out, length), + Column::Int128(col) => col.write(out, length), + Column::Decimal75(_, _, col) | Column::Scalar(col) => col.write(out, length), + Column::VarChar((col, _)) => col.write(out, length), } } } impl<'a, T: ProvableResultElement<'a>, const N: usize> ProvableResultColumn for [T; N] { - fn num_bytes(&self, selection: &Indexes) -> usize { - (&self[..]).num_bytes(selection) + fn num_bytes(&self, length: u64) -> usize { + (&self[..]).num_bytes(length) } - fn write(&self, out: &mut [u8], selection: &Indexes) -> usize { - (&self[..]).write(out, selection) + fn write(&self, out: &mut [u8], length: u64) -> usize { + (&self[..]).write(out, length) } } diff --git a/crates/proof-of-sql/src/sql/proof/query_proof.rs b/crates/proof-of-sql/src/sql/proof/query_proof.rs index dae0cd566..afa488d7c 100644 --- a/crates/proof-of-sql/src/sql/proof/query_proof.rs +++ b/crates/proof-of-sql/src/sql/proof/query_proof.rs @@ -53,10 +53,10 @@ impl QueryProof { assert!(num_sumcheck_variables > 0); let alloc = Bump::new(); - let mut result_builder = ResultBuilder::new(table_length); + let mut result_builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut result_builder, &alloc, accessor); let provable_result = - ProvableQueryResult::new(&result_builder.result_index_vector, &result_cols); + ProvableQueryResult::new(result_builder.result_table_length() as u64, &result_cols); // construct a transcript for the proof let mut transcript: Keccak256Transcript = @@ -145,9 +145,10 @@ impl QueryProof { result: &ProvableQueryResult, setup: &CP::VerifierPublicSetup<'_>, ) -> QueryResult { - let table_length = expr.get_length(accessor); + let input_length = expr.get_length(accessor); + let output_length = result.table_length(); let generator_offset = expr.get_offset(accessor); - let num_sumcheck_variables = cmp::max(log2_up(table_length), 1); + let num_sumcheck_variables = cmp::max(log2_up(input_length), 1); assert!(num_sumcheck_variables > 0); // validate bit decompositions @@ -175,7 +176,7 @@ impl QueryProof { // construct a transcript for the proof let mut transcript: Keccak256Transcript = - make_transcript(expr, result, table_length, generator_offset); + make_transcript(expr, result, input_length, generator_offset); // These are the challenges that will be consumed by the proof // Specifically, these are the challenges that the verifier sends to @@ -197,7 +198,7 @@ impl QueryProof { .take(num_random_scalars) .collect(); let sumcheck_random_scalars = - SumcheckRandomScalars::new(&random_scalars, table_length, num_sumcheck_variables); + SumcheckRandomScalars::new(&random_scalars, input_length, num_sumcheck_variables); // verify sumcheck up to the evaluation check let poly_info = CompositePolynomialInfo { @@ -226,11 +227,11 @@ impl QueryProof { // pass over the provable AST to fill in the verification builder let sumcheck_evaluations = SumcheckMleEvaluations::new( - table_length, + input_length, + output_length, &subclaim.evaluation_point, &sumcheck_random_scalars, &self.pcs_proof_evaluations, - result.indexes(), ); let mut builder = VerificationBuilder::new( generator_offset, @@ -247,7 +248,7 @@ impl QueryProof { // compute the evaluation of the result MLEs let result_evaluations = result.evaluate( &subclaim.evaluation_point, - table_length, + output_length, &column_result_fields[..], )?; // check the evaluation of the result MLEs @@ -274,7 +275,7 @@ impl QueryProof { &product, &subclaim.evaluation_point, generator_offset as u64, - table_length, + input_length, setup, ) .map_err(|_e| ProofError::VerificationError { diff --git a/crates/proof-of-sql/src/sql/proof/query_proof_test.rs b/crates/proof-of-sql/src/sql/proof/query_proof_test.rs index 05c0754d6..3817c3e19 100644 --- a/crates/proof-of-sql/src/sql/proof/query_proof_test.rs +++ b/crates/proof-of-sql/src/sql/proof/query_proof_test.rs @@ -14,7 +14,7 @@ use crate::{ proof::ProofError, scalar::{Curve25519Scalar, Scalar}, }, - sql::proof::{Indexes, QueryData, ResultBuilder, SumcheckSubpolynomialType}, + sql::proof::{QueryData, ResultBuilder, SumcheckSubpolynomialType}, }; use bumpalo::Bump; use serde::Serialize; @@ -47,9 +47,9 @@ impl ProverEvaluate for TrivialTestProofPlan { alloc: &'a Bump, _accessor: &'a dyn DataAccessor, ) -> Vec> { - let col = alloc.alloc_slice_fill_copy(builder.table_length(), self.column_fill_value); - let indexes = Indexes::Sparse(vec![0u64]); - builder.set_result_indexes(indexes); + let input_length = self.length; + let col = alloc.alloc_slice_fill_copy(input_length, self.column_fill_value); + builder.set_result_table_length(input_length); vec![Column::BigInt(col)] } @@ -124,7 +124,8 @@ fn verify_a_trivial_query_proof_with_given_offset(n: usize, offset_generators: u table, } = proof.verify(&expr, &accessor, &result, &()).unwrap(); assert_ne!(verification_hash, [0; 32]); - let expected_result = owned_table([bigint("a1", [0])]); + let expected_col = vec![0_i64; n]; + let expected_result = owned_table([bigint("a1", expected_col)]); assert_eq!(table, expected_result); } @@ -203,8 +204,8 @@ impl ProverEvaluate for SquareTestProofPlan { alloc: &'a Bump, _accessor: &'a dyn DataAccessor, ) -> Vec> { - builder.set_result_indexes(Indexes::Sparse(vec![0, 1])); let res: &[_] = alloc.alloc_slice_copy(&self.res); + builder.set_result_table_length(2); vec![Column::BigInt(res)] } @@ -384,8 +385,8 @@ impl ProverEvaluate for DoubleSquareTestProofPlan { alloc: &'a Bump, _accessor: &'a dyn DataAccessor, ) -> Vec> { - builder.set_result_indexes(Indexes::Sparse(vec![0, 1])); let res: &[_] = alloc.alloc_slice_copy(&self.res); + builder.set_result_table_length(2); vec![Column::BigInt(res)] } @@ -595,8 +596,8 @@ impl ProverEvaluate for ChallengeTestProofPlan { _alloc: &'a Bump, _accessor: &'a dyn DataAccessor, ) -> Vec> { - builder.set_result_indexes(Indexes::Sparse(vec![0, 1])); builder.request_post_result_challenges(2); + builder.set_result_table_length(2); vec![Column::BigInt(&[9, 25])] } diff --git a/crates/proof-of-sql/src/sql/proof/query_result.rs b/crates/proof-of-sql/src/sql/proof/query_result.rs index cdefda189..31b9ad994 100644 --- a/crates/proof-of-sql/src/sql/proof/query_result.rs +++ b/crates/proof-of-sql/src/sql/proof/query_result.rs @@ -21,9 +21,6 @@ pub enum QueryError { /// Decoding errors other than overflow and invalid string. #[snafu(display("Miscellaneous decoding error"))] MiscellaneousDecodingError, - /// Indexes are invalid. - #[snafu(display("Invalid indexes"))] - InvalidIndexes, /// Miscellaneous evaluation error. #[snafu(display("Miscellaneous evaluation error"))] MiscellaneousEvaluationError, diff --git a/crates/proof-of-sql/src/sql/proof/result_builder.rs b/crates/proof-of-sql/src/sql/proof/result_builder.rs index d25a190b7..4f296c46f 100644 --- a/crates/proof-of-sql/src/sql/proof/result_builder.rs +++ b/crates/proof-of-sql/src/sql/proof/result_builder.rs @@ -1,10 +1,6 @@ -use super::Indexes; - /// Track the result created by a query pub struct ResultBuilder { - table_length: usize, - /// TODO: add docs - pub(crate) result_index_vector: Indexes, + result_table_length: usize, /// The number of challenges used in the proof. /// Specifically, these are the challenges that the verifier sends to @@ -13,24 +9,29 @@ pub struct ResultBuilder { num_post_result_challenges: usize, } +impl Default for ResultBuilder { + fn default() -> Self { + Self::new() + } +} + impl ResultBuilder { /// Create a new result builder for a table with the given length. For multi table queries, this will likely need to change. - pub fn new(table_length: usize) -> Self { + pub fn new() -> Self { Self { - table_length, - result_index_vector: Indexes::default(), + result_table_length: 0, num_post_result_challenges: 0, } } - /// Get the length of the table - pub fn table_length(&self) -> usize { - self.table_length + /// Get the length of the output table + pub fn result_table_length(&self) -> usize { + self.result_table_length } - /// Set the indexes of the rows select in the result - pub fn set_result_indexes(&mut self, result_index: Indexes) { - self.result_index_vector = result_index; + /// Set the length of the output table + pub fn set_result_table_length(&mut self, result_table_length: usize) { + self.result_table_length = result_table_length; } /// The number of challenges used in the proof. diff --git a/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations.rs b/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations.rs index d03b265a2..9fabd9e13 100644 --- a/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations.rs +++ b/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations.rs @@ -1,4 +1,4 @@ -use super::{Indexes, SumcheckRandomScalars}; +use super::SumcheckRandomScalars; use crate::base::{ polynomial::{ compute_truncated_lagrange_basis_inner_product, compute_truncated_lagrange_basis_sum, @@ -10,17 +10,20 @@ use crate::base::{ #[derive(Default)] pub struct SumcheckMleEvaluations<'a, S: Scalar> { /// The length of the input table for a basic filter. When we support more complex queries, this may need to split. - pub table_length: usize, + pub input_length: usize, + /// The length of the output table for a basic filter. When we support more complex queries, this may need to split. + pub output_length: usize, /// The number of sumcheck variables. pub num_sumcheck_variables: usize, /// The evaluation (at the random point generated by sumcheck) of an MLE `{x_i}` where - /// `x_i = 1` if `i < table_length;` + /// `x_i = 1` if `i < input_length;` /// = 0, otherwise - pub one_evaluation: S, + pub input_one_evaluation: S, - /// The evaluation (at the random point generated by sumcheck) of the MLE that is 1 at the result indexes and 0 elsewhere. - /// This is only computed if the result indexes are dense, and is None otherwise. - pub result_indexes_evaluation: Option, + /// The evaluation (at the random point generated by sumcheck) of an MLE `{x_i}` where + /// `x_i = 1` if `i < output_length;` + /// = 0, otherwise + pub output_one_evaluation: S, /// The evaluation (at the random point generated by sumcheck) of the MLE formed from entrywise random scalars. /// @@ -42,35 +45,35 @@ impl<'a, S: Scalar> SumcheckMleEvaluations<'a, S> { /// - `evaluation_point` - the point, outputted by sumcheck, at which to evaluate the MLEs /// - `sumcheck_random_scalars` - the random scalars used to batch the evaluations that are proven via IPA /// - `pcs_proof_evaluations` - the evaluations of the MLEs that are proven via IPA - /// - `result_indexes` - the indexes of the entries in the result columns. This can be sparse or dense pub fn new( - table_length: usize, + input_length: usize, + output_length: usize, evaluation_point: &[S], sumcheck_random_scalars: &SumcheckRandomScalars, pcs_proof_evaluations: &'a [S], - result_indexes: &Indexes, ) -> Self { assert_eq!( evaluation_point.len(), sumcheck_random_scalars.entrywise_point.len() ); - assert_eq!(table_length, sumcheck_random_scalars.table_length); + assert_eq!(input_length, sumcheck_random_scalars.table_length); let random_evaluation = compute_truncated_lagrange_basis_inner_product( - table_length, + input_length, evaluation_point, sumcheck_random_scalars.entrywise_point, ); - let one_evaluation = compute_truncated_lagrange_basis_sum(table_length, evaluation_point); - - let result_indexes_evaluation = result_indexes.evaluate_at_point(evaluation_point); - + let input_one_evaluation = + compute_truncated_lagrange_basis_sum(input_length, evaluation_point); + let output_one_evaluation = + compute_truncated_lagrange_basis_sum(output_length, evaluation_point); Self { - table_length, + input_length, + output_length, num_sumcheck_variables: evaluation_point.len(), - one_evaluation, + input_one_evaluation, + output_one_evaluation, random_evaluation, pcs_proof_evaluations, - result_indexes_evaluation, } } } diff --git a/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations_test.rs b/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations_test.rs index 9a603722d..5baaf54c3 100644 --- a/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations_test.rs +++ b/crates/proof-of-sql/src/sql/proof/sumcheck_mle_evaluations_test.rs @@ -1,4 +1,4 @@ -use super::{Indexes, SumcheckMleEvaluations}; +use super::SumcheckMleEvaluations; use crate::{base::scalar::Curve25519Scalar, sql::proof::SumcheckRandomScalars}; use num_traits::One; @@ -14,11 +14,11 @@ fn we_can_track_the_evaluation_of_mles_used_within_sumcheck() { let pcs_proof_evaluations = [Curve25519Scalar::from(42u64)]; let evals = SumcheckMleEvaluations::new( + 3, 3, &evaluation_point, &sumcheck_random_scalars, &pcs_proof_evaluations, - &Indexes::Sparse(vec![]), ); let expected_eval = (Curve25519Scalar::one() - evaluation_point[0]) * (Curve25519Scalar::one() - evaluation_point[1]) @@ -38,28 +38,6 @@ fn we_can_track_the_evaluation_of_mles_used_within_sumcheck() { * (Curve25519Scalar::one() - evaluation_point[1]) + (evaluation_point[0]) * (Curve25519Scalar::one() - evaluation_point[1]) + (Curve25519Scalar::one() - evaluation_point[0]) * (evaluation_point[1]); - assert_eq!(evals.one_evaluation, expected_eval); - // Because the Indexes are sparse, this should not be evaluated. - assert_eq!(evals.result_indexes_evaluation, None); -} -#[test] -fn we_can_track_the_evaluation_of_dense_indexes() { - let evaluation_point = [Curve25519Scalar::from(3u64), Curve25519Scalar::from(5u64)]; - let random_scalars = [ - Curve25519Scalar::from(123u64), - Curve25519Scalar::from(456u64), - ]; - - let sumcheck_random_scalars = SumcheckRandomScalars::new(&random_scalars, 3, 2); - - let pcs_proof_evaluations = [Curve25519Scalar::from(42u64)]; - let evals = SumcheckMleEvaluations::new( - 3, - &evaluation_point, - &sumcheck_random_scalars, - &pcs_proof_evaluations, - &Indexes::Dense(0..3), - ); - // Because the range is the entire table, these should be the same. - assert_eq!(evals.result_indexes_evaluation, Some(evals.one_evaluation)); + assert_eq!(evals.input_one_evaluation, expected_eval); + assert_eq!(evals.output_one_evaluation, expected_eval); } diff --git a/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test.rs b/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test.rs index 02efaf453..505984fb8 100644 --- a/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test.rs +++ b/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test.rs @@ -27,12 +27,13 @@ pub(super) struct EmptyTestQueryExpr { impl ProverEvaluate for EmptyTestQueryExpr { fn result_evaluate<'a>( &self, - _builder: &mut ResultBuilder, + builder: &mut ResultBuilder, alloc: &'a Bump, _accessor: &'a dyn DataAccessor, ) -> Vec> { let zeros = vec![0; self.length]; let res: &[_] = alloc.alloc_slice_copy(&zeros); + builder.set_result_table_length(self.length); vec![Column::BigInt(res); self.columns] } fn prover_evaluate<'a>( diff --git a/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test_utility.rs b/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test_utility.rs index 956c013dd..3616af825 100644 --- a/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test_utility.rs +++ b/crates/proof-of-sql/src/sql/proof/verifiable_query_result_test_utility.rs @@ -2,13 +2,10 @@ use super::{ verifiable_query_result_test::EmptyTestQueryExpr, ProofPlan, ProvableQueryResult, QueryProof, VerifiableQueryResult, }; -use crate::{ - base::{ - commitment::{Commitment, CommittableColumn}, - database::{Column, CommitmentAccessor, OwnedTableTestAccessor, TableRef, TestAccessor}, - scalar::Curve25519Scalar, - }, - sql::proof::Indexes, +use crate::base::{ + commitment::{Commitment, CommittableColumn}, + database::{Column, CommitmentAccessor, OwnedTableTestAccessor, TableRef, TestAccessor}, + scalar::Curve25519Scalar, }; use blitzar::proof::InnerProductProof; use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity}; @@ -94,7 +91,7 @@ fn tamper_no_result( // add a result let mut res_p = res.clone(); let cols: [Column<'_, Curve25519Scalar>; 1] = [Column::BigInt(&[0_i64; 0])]; - res_p.provable_result = Some(ProvableQueryResult::new(&Indexes::Sparse(vec![]), &cols)); + res_p.provable_result = Some(ProvableQueryResult::new(0, &cols)); assert!(res_p.verify(expr, accessor, &()).is_err()); // add a proof @@ -117,7 +114,7 @@ fn tamper_empty_result( // try to add a result let mut res_p = res.clone(); let cols: [Column<'_, Curve25519Scalar>; 1] = [Column::BigInt(&[123_i64])]; - res_p.provable_result = Some(ProvableQueryResult::new(&Indexes::Sparse(vec![0]), &cols)); + res_p.provable_result = Some(ProvableQueryResult::new(1, &cols)); assert!(res_p.verify(expr, accessor, &()).is_err()); } @@ -126,8 +123,6 @@ fn tamper_empty_result( /// Will panic if: /// - `res.provable_result` is `None`, which leads to calling `unwrap()` on it in the subsequent /// code and may cause an unexpected behavior. -/// - The `provable_res.indexes()` returns an empty vector, which leads to attempting to modify an -/// index of an empty result, causing an invalid state. /// - The assertion `assert!(res_p.verify(expr, accessor, &()).is_err())` fails, indicating that the /// verification did not fail as expected after tampering. fn tamper_result( @@ -140,24 +135,12 @@ fn tamper_result( return; } let provable_res = res.provable_result.as_ref().unwrap(); - if provable_res.indexes().is_empty() { + + if provable_res.table_length() == 0 { tamper_empty_result(res, expr, accessor); return; } - // try to change an index - let mut res_p = res.clone(); - let mut provable_res_p = provable_res.clone(); - match provable_res_p.indexes_mut() { - Indexes::Sparse(indexes) => indexes[0] += 1, - Indexes::Dense(range) => { - range.start += 1; - range.end += 1; - } - } - res_p.provable_result = Some(provable_res_p); - assert!(res_p.verify(expr, accessor, &()).is_err()); - // try to change data let mut res_p = res.clone(); let mut provable_res_p = provable_res.clone(); diff --git a/crates/proof-of-sql/src/sql/proof/verification_builder.rs b/crates/proof-of-sql/src/sql/proof/verification_builder.rs index 532914584..e60be0d16 100644 --- a/crates/proof-of-sql/src/sql/proof/verification_builder.rs +++ b/crates/proof-of-sql/src/sql/proof/verification_builder.rs @@ -63,7 +63,7 @@ impl<'a, C: Commitment> VerificationBuilder<'a, C> { } pub fn table_length(&self) -> usize { - self.mle_evaluations.table_length + self.mle_evaluations.input_length } pub fn generator_offset(&self) -> usize { diff --git a/crates/proof-of-sql/src/sql/proof/verification_builder_test.rs b/crates/proof-of-sql/src/sql/proof/verification_builder_test.rs index acc1782d5..5d850d7ea 100644 --- a/crates/proof-of-sql/src/sql/proof/verification_builder_test.rs +++ b/crates/proof-of-sql/src/sql/proof/verification_builder_test.rs @@ -7,7 +7,7 @@ use rand_core::OsRng; #[test] fn an_empty_sumcheck_polynomial_evaluates_to_zero() { let mle_evaluations = SumcheckMleEvaluations { - table_length: 1, + input_length: 1, num_sumcheck_variables: 1, ..Default::default() }; @@ -28,7 +28,7 @@ fn an_empty_sumcheck_polynomial_evaluates_to_zero() { #[test] fn we_build_up_a_sumcheck_polynomial_evaluation_from_subpolynomial_evaluations() { let mle_evaluations = SumcheckMleEvaluations { - table_length: 1, + input_length: 1, num_sumcheck_variables: 1, ..Default::default() }; @@ -65,7 +65,7 @@ fn we_build_up_the_folded_pcs_proof_commitment() { Curve25519Scalar::from(456u64), ]; let mle_evaluations = SumcheckMleEvaluations { - table_length: 1, + input_length: 1, num_sumcheck_variables: 1, pcs_proof_evaluations: &pcs_proof_evaluations, ..Default::default() diff --git a/crates/proof-of-sql/src/sql/proof_exprs/equals_expr.rs b/crates/proof-of-sql/src/sql/proof_exprs/equals_expr.rs index a845076fd..faf9af5e1 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/equals_expr.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/equals_expr.rs @@ -152,7 +152,7 @@ pub fn verifier_evaluate_equals_zero( // consume mle evaluations let lhs_pseudo_inv_eval = builder.consume_intermediate_mle(); let selection_not_eval = builder.consume_intermediate_mle(); - let selection_eval = builder.mle_evaluations.one_evaluation - selection_not_eval; + let selection_eval = builder.mle_evaluations.input_one_evaluation - selection_not_eval; // subpolynomial: selection * lhs builder.produce_sumcheck_subpolynomial_evaluation( diff --git a/crates/proof-of-sql/src/sql/proof_exprs/inequality_expr.rs b/crates/proof-of-sql/src/sql/proof_exprs/inequality_expr.rs index 099e888df..06ce2a217 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/inequality_expr.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/inequality_expr.rs @@ -123,7 +123,7 @@ impl ProofExpr for InequalityExpr { builder: &mut VerificationBuilder, accessor: &dyn CommitmentAccessor, ) -> Result { - let one_eval = builder.mle_evaluations.one_evaluation; + let one_eval = builder.mle_evaluations.input_one_evaluation; let lhs_eval = self.lhs.verifier_evaluate(builder, accessor)?; let rhs_eval = self.rhs.verifier_evaluate(builder, accessor)?; let lhs_scale = self.lhs.data_type().scale().unwrap_or(0); diff --git a/crates/proof-of-sql/src/sql/proof_exprs/literal_expr.rs b/crates/proof-of-sql/src/sql/proof_exprs/literal_expr.rs index fd4b646b9..4ea429cc5 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/literal_expr.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/literal_expr.rs @@ -70,7 +70,7 @@ impl ProofExpr for LiteralExpr { builder: &mut VerificationBuilder, _accessor: &dyn CommitmentAccessor, ) -> Result { - let mut commitment = builder.mle_evaluations.one_evaluation; + let mut commitment = builder.mle_evaluations.input_one_evaluation; commitment *= self.value.to_scalar(); Ok(commitment) } diff --git a/crates/proof-of-sql/src/sql/proof_exprs/not_expr.rs b/crates/proof-of-sql/src/sql/proof_exprs/not_expr.rs index 1cdf204f6..c0f2f899f 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/not_expr.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/not_expr.rs @@ -66,7 +66,7 @@ impl ProofExpr for NotExpr { accessor: &dyn CommitmentAccessor, ) -> Result { let eval = self.expr.verifier_evaluate(builder, accessor)?; - Ok(builder.mle_evaluations.one_evaluation - eval) + Ok(builder.mle_evaluations.input_one_evaluation - eval) } fn get_column_references(&self, columns: &mut IndexSet) { diff --git a/crates/proof-of-sql/src/sql/proof_exprs/sign_expr.rs b/crates/proof-of-sql/src/sql/proof_exprs/sign_expr.rs index 67dae7b47..9e614d22e 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/sign_expr.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/sign_expr.rs @@ -247,7 +247,7 @@ fn verify_bit_decomposition( ) { let mut eval = expr_eval; let sign_eval = bit_evals.last().unwrap(); - let sign_eval = builder.mle_evaluations.one_evaluation - C::Scalar::TWO * *sign_eval; + let sign_eval = builder.mle_evaluations.input_one_evaluation - C::Scalar::TWO * *sign_eval; let mut vary_index = 0; eval -= sign_eval * C::Scalar::from(dist.constant_part()); dist.for_each_abs_varying_bit(|int_index: usize, bit_index: usize| { diff --git a/crates/proof-of-sql/src/sql/proof_exprs/sign_expr_test.rs b/crates/proof-of-sql/src/sql/proof_exprs/sign_expr_test.rs index f8177d551..7e24b66ae 100644 --- a/crates/proof-of-sql/src/sql/proof_exprs/sign_expr_test.rs +++ b/crates/proof-of-sql/src/sql/proof_exprs/sign_expr_test.rs @@ -2,7 +2,7 @@ use super::{count_sign, prover_evaluate_sign, result_evaluate_sign, verifier_eva use crate::{ base::{bit::BitDistribution, polynomial::MultilinearExtension, scalar::Curve25519Scalar}, sql::proof::{ - CountBuilder, Indexes, ProofBuilder, SumcheckMleEvaluations, SumcheckRandomScalars, + CountBuilder, ProofBuilder, SumcheckMleEvaluations, SumcheckRandomScalars, VerificationBuilder, }, }; @@ -58,13 +58,13 @@ fn we_can_verify_a_constant_decomposition() { let sumcheck_random_scalars = SumcheckRandomScalars::new(&scalars, data.len(), 2); let evaluation_point = [Curve25519Scalar::from(324), Curve25519Scalar::from(97)]; let sumcheck_evaluations = SumcheckMleEvaluations::new( + data.len(), data.len(), &evaluation_point, &sumcheck_random_scalars, &[], - &Indexes::default(), ); - let one_eval = sumcheck_evaluations.one_evaluation; + let one_eval = sumcheck_evaluations.input_one_evaluation; let mut builder: VerificationBuilder = VerificationBuilder::new(0, sumcheck_evaluations, &dists, &[], &[], &[], Vec::new()); @@ -82,13 +82,13 @@ fn verification_of_constant_data_fails_if_the_commitment_doesnt_match_the_bit_di let sumcheck_random_scalars = SumcheckRandomScalars::new(&scalars, data.len(), 2); let evaluation_point = [Curve25519Scalar::from(324), Curve25519Scalar::from(97)]; let sumcheck_evaluations = SumcheckMleEvaluations::new( + data.len(), data.len(), &evaluation_point, &sumcheck_random_scalars, &[], - &Indexes::default(), ); - let one_eval = sumcheck_evaluations.one_evaluation; + let one_eval = sumcheck_evaluations.input_one_evaluation; let mut builder: VerificationBuilder = VerificationBuilder::new(0, sumcheck_evaluations, &dists, &[], &[], &[], Vec::new()); diff --git a/crates/proof-of-sql/src/sql/proof_plans/filter_exec.rs b/crates/proof-of-sql/src/sql/proof_plans/filter_exec.rs index c1c18c00f..2408a8303 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/filter_exec.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/filter_exec.rs @@ -13,7 +13,7 @@ use crate::{ }, sql::{ proof::{ - CountBuilder, HonestProver, Indexes, ProofBuilder, ProofPlan, ProverEvaluate, + CountBuilder, HonestProver, ProofBuilder, ProofPlan, ProverEvaluate, ProverHonestyMarker, ResultBuilder, SumcheckSubpolynomialType, VerificationBuilder, }, proof_exprs::{AliasedDynProofExpr, DynProofExpr, ProofExpr, TableExpr}, @@ -101,13 +101,7 @@ where .map(|aliased_expr| aliased_expr.expr.verifier_evaluate(builder, accessor)) .collect::, _>>()?, ); - // 3. indexes - let indexes_eval = builder.mle_evaluations.result_indexes_evaluation.ok_or( - ProofError::VerificationError { - error: "invalid indexes", - }, - )?; - // 4. filtered_columns + // 3. filtered_columns let filtered_columns_evals: Vec<_> = repeat_with(|| builder.consume_intermediate_mle()) .take(self.aliased_results.len()) .collect(); @@ -158,10 +152,11 @@ impl ProverEvaluate for FilterExec { alloc: &'a Bump, accessor: &'a dyn DataAccessor, ) -> Vec> { + let input_length = accessor.get_length(self.table.table_ref); // 1. selection let selection_column: Column<'a, C::Scalar> = self.where_clause - .result_evaluate(builder.table_length(), alloc, accessor); + .result_evaluate(input_length, alloc, accessor); let selection = selection_column .as_boolean() .expect("selection is not boolean"); @@ -173,14 +168,13 @@ impl ProverEvaluate for FilterExec { .map(|aliased_expr| { aliased_expr .expr - .result_evaluate(builder.table_length(), alloc, accessor) + .result_evaluate(input_length, alloc, accessor) }) .collect(); // Compute filtered_columns and indexes let (filtered_columns, result_len) = filter_columns(alloc, &columns, selection); - // 3. set indexes - builder.set_result_indexes(Indexes::Dense(0..(result_len as u64))); + builder.set_result_table_length(result_len); builder.request_post_result_challenges(2); filtered_columns } @@ -206,7 +200,7 @@ impl ProverEvaluate for FilterExec { .iter() .map(|aliased_expr| aliased_expr.expr.prover_evaluate(builder, alloc, accessor)) .collect(); - // Compute filtered_columns and indexes + // Compute filtered_columns let (filtered_columns, result_len) = filter_columns(alloc, &columns, selection); // 3. Produce MLEs filtered_columns.iter().copied().for_each(|column| { @@ -238,13 +232,8 @@ fn verify_filter( s_eval: C::Scalar, d_evals: &[C::Scalar], ) -> Result<(), ProofError> { - let one_eval = builder.mle_evaluations.one_evaluation; - - let Some(chi_eval) = builder.mle_evaluations.result_indexes_evaluation else { - return Err(ProofError::VerificationError { - error: "Result indexes not valid.", - }); - }; + let one_eval = builder.mle_evaluations.input_one_evaluation; + let chi_eval = builder.mle_evaluations.output_one_evaluation; let c_fold_eval = alpha * one_eval + fold_vals(beta, c_evals); let d_bar_fold_eval = alpha * one_eval + fold_vals(beta, d_evals); diff --git a/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test.rs b/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test.rs index 1f2bb55de..f9a9363c3 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test.rs @@ -192,7 +192,7 @@ fn we_can_get_an_empty_result_from_a_basic_filter_on_an_empty_table_using_result where_clause, ); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(0); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[ ColumnField::new("b".parse().unwrap(), ColumnType::BigInt), @@ -204,7 +204,7 @@ fn we_can_get_an_empty_result_from_a_basic_filter_on_an_empty_table_using_result ), ]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected: OwnedTable = owned_table([ @@ -237,7 +237,7 @@ fn we_can_get_an_empty_result_from_a_basic_filter_using_result_evaluate() { where_clause, ); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(5); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[ ColumnField::new("b".parse().unwrap(), ColumnType::BigInt), @@ -249,7 +249,7 @@ fn we_can_get_an_empty_result_from_a_basic_filter_using_result_evaluate() { ), ]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected: OwnedTable = owned_table([ @@ -278,11 +278,11 @@ fn we_can_get_no_columns_from_a_basic_filter_with_no_selected_columns_using_resu equal(column(t, "a", &accessor), const_int128(5)); let expr = filter(cols_expr_plan(t, &[], &accessor), tab(t), where_clause); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(5); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected = OwnedTable::try_new(IndexMap::default()).unwrap(); @@ -309,7 +309,7 @@ fn we_can_get_the_correct_result_from_a_basic_filter_using_result_evaluate() { where_clause, ); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(5); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[ ColumnField::new("b".parse().unwrap(), ColumnType::BigInt), @@ -321,7 +321,7 @@ fn we_can_get_the_correct_result_from_a_basic_filter_using_result_evaluate() { ), ]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected: OwnedTable = owned_table([ diff --git a/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test_dishonest_prover.rs b/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test_dishonest_prover.rs index cf2fa969d..efcb0695c 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test_dishonest_prover.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/filter_exec_test_dishonest_prover.rs @@ -8,7 +8,7 @@ use crate::{ }, sql::{ proof::{ - Indexes, ProofBuilder, ProverEvaluate, ProverHonestyMarker, QueryError, ResultBuilder, + ProofBuilder, ProverEvaluate, ProverHonestyMarker, QueryError, ResultBuilder, VerifiableQueryResult, }, // Making this explicit to ensure that we don't accidentally use the @@ -41,10 +41,11 @@ impl ProverEvaluate for DishonestFilterExec { alloc: &'a Bump, accessor: &'a dyn DataAccessor, ) -> Vec> { + let input_length = accessor.get_length(self.table.table_ref); // 1. selection let selection_column: Column<'a, Curve25519Scalar> = self.where_clause - .result_evaluate(builder.table_length(), alloc, accessor); + .result_evaluate(input_length, alloc, accessor); let selection = selection_column .as_boolean() .expect("selection is not boolean"); @@ -55,14 +56,13 @@ impl ProverEvaluate for DishonestFilterExec { .map(|aliased_expr| { aliased_expr .expr - .result_evaluate(builder.table_length(), alloc, accessor) + .result_evaluate(input_length, alloc, accessor) }) .collect(); - // Compute filtered_columns and indexes + // Compute filtered_columns let (filtered_columns, result_len) = filter_columns(alloc, &columns, selection); + builder.set_result_table_length(result_len); let filtered_columns = tamper_column(alloc, filtered_columns); - // 3. set indexes - builder.set_result_indexes(Indexes::Dense(0..(result_len as u64))); builder.request_post_result_challenges(2); filtered_columns } @@ -91,7 +91,7 @@ impl ProverEvaluate for DishonestFilterExec { .iter() .map(|aliased_expr| aliased_expr.expr.prover_evaluate(builder, alloc, accessor)) .collect(); - // Compute filtered_columns and indexes + // Compute filtered_columns let (filtered_columns, result_len) = filter_columns(alloc, &columns, selection); let filtered_columns = tamper_column(alloc, filtered_columns); // 3. Produce MLEs diff --git a/crates/proof-of-sql/src/sql/proof_plans/group_by_exec.rs b/crates/proof-of-sql/src/sql/proof_plans/group_by_exec.rs index a5053f203..35d324516 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/group_by_exec.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/group_by_exec.rs @@ -16,7 +16,7 @@ use crate::{ }, sql::{ proof::{ - CountBuilder, Indexes, ProofBuilder, ProofPlan, ProverEvaluate, ResultBuilder, + CountBuilder, ProofBuilder, ProofPlan, ProverEvaluate, ResultBuilder, SumcheckSubpolynomialType, VerificationBuilder, }, proof_exprs::{AliasedDynProofExpr, ColumnExpr, DynProofExpr, ProofExpr, TableExpr}, @@ -120,13 +120,7 @@ impl ProofPlan for GroupByExec { .iter() .map(|aliased_expr| aliased_expr.expr.verifier_evaluate(builder, accessor)) .collect::, _>>()?; - // 3. indexes - let indexes_eval = builder.mle_evaluations.result_indexes_evaluation.ok_or( - ProofError::VerificationError { - error: "invalid indexes", - }, - )?; - // 4. filtered_columns + // 3. filtered_columns let group_by_result_columns_evals: Vec<_> = repeat_with(|| builder.consume_intermediate_mle()) @@ -218,10 +212,11 @@ impl ProverEvaluate for GroupByExec { alloc: &'a Bump, accessor: &'a dyn DataAccessor, ) -> Vec> { + let input_length = accessor.get_length(self.table.table_ref); // 1. selection let selection_column: Column<'a, C::Scalar> = self.where_clause - .result_evaluate(builder.table_length(), alloc, accessor); + .result_evaluate(input_length, alloc, accessor); let selection = selection_column .as_boolean() @@ -231,7 +226,7 @@ impl ProverEvaluate for GroupByExec { let group_by_columns = self .group_by_exprs .iter() - .map(|expr| expr.result_evaluate(builder.table_length(), alloc, accessor)) + .map(|expr| expr.result_evaluate(input_length, alloc, accessor)) .collect::>(); let sum_columns = self .sum_expr @@ -239,10 +234,10 @@ impl ProverEvaluate for GroupByExec { .map(|aliased_expr| { aliased_expr .expr - .result_evaluate(builder.table_length(), alloc, accessor) + .result_evaluate(input_length, alloc, accessor) }) .collect::>(); - // Compute filtered_columns and indexes + // Compute filtered_columns let AggregatedColumns { group_by_columns: group_by_result_columns, sum_columns: sum_result_columns, @@ -250,9 +245,8 @@ impl ProverEvaluate for GroupByExec { .. } = aggregate_columns(alloc, &group_by_columns, &sum_columns, &[], &[], selection) .expect("columns should be aggregatable"); - // 3. set indexes - builder.set_result_indexes(Indexes::Dense(0..(count_column.len() as u64))); let sum_result_columns_iter = sum_result_columns.iter().map(|col| Column::Scalar(col)); + builder.set_result_table_length(count_column.len()); builder.request_post_result_challenges(2); group_by_result_columns .into_iter() @@ -287,7 +281,7 @@ impl ProverEvaluate for GroupByExec { .iter() .map(|aliased_expr| aliased_expr.expr.prover_evaluate(builder, alloc, accessor)) .collect::>(); - // 3. Compute filtered_columns and indexes + // 3. Compute filtered_columns let AggregatedColumns { group_by_columns: group_by_result_columns, sum_columns: sum_result_columns, @@ -331,7 +325,7 @@ fn verify_group_by( (g_in_evals, sum_in_evals, sel_in_eval): (Vec, Vec, C::Scalar), (g_out_evals, sum_out_evals, count_out_eval): (Vec, Vec, C::Scalar), ) -> Result<(), ProofError> { - let one_eval = builder.mle_evaluations.one_evaluation; + let one_eval = builder.mle_evaluations.input_one_evaluation; // g_in_fold = alpha + sum beta^j * g_in[j] let g_in_fold_eval = alpha * one_eval + fold_vals(beta, &g_in_evals); diff --git a/crates/proof-of-sql/src/sql/proof_plans/projection_exec.rs b/crates/proof-of-sql/src/sql/proof_plans/projection_exec.rs index b0551969c..001e4b9f1 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/projection_exec.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/projection_exec.rs @@ -10,7 +10,7 @@ use crate::{ }, sql::{ proof::{ - CountBuilder, Indexes, ProofBuilder, ProofPlan, ProverEvaluate, ResultBuilder, + CountBuilder, ProofBuilder, ProofPlan, ProverEvaluate, ResultBuilder, VerificationBuilder, }, proof_exprs::{AliasedDynProofExpr, ProofExpr, TableExpr}, @@ -102,16 +102,18 @@ impl ProverEvaluate for ProjectionExec { alloc: &'a Bump, accessor: &'a dyn DataAccessor, ) -> Vec> { + let input_length = accessor.get_length(self.table.table_ref); let columns: Vec<_> = self .aliased_results .iter() .map(|aliased_expr| { aliased_expr .expr - .result_evaluate(builder.table_length(), alloc, accessor) + .result_evaluate(input_length, alloc, accessor) }) .collect(); - builder.set_result_indexes(Indexes::Dense(0..(builder.table_length() as u64))); + // For projection, the result table length is the same as the input table length + builder.set_result_table_length(input_length); columns } diff --git a/crates/proof-of-sql/src/sql/proof_plans/projection_exec_test.rs b/crates/proof-of-sql/src/sql/proof_plans/projection_exec_test.rs index 604a3ca58..53914c11c 100644 --- a/crates/proof-of-sql/src/sql/proof_plans/projection_exec_test.rs +++ b/crates/proof-of-sql/src/sql/proof_plans/projection_exec_test.rs @@ -165,7 +165,7 @@ fn we_can_get_an_empty_result_from_a_basic_projection_on_an_empty_table_using_re let expr: DynProofPlan = projection(cols_expr_plan(t, &["b", "c", "d", "e"], &accessor), tab(t)); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(0); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[ ColumnField::new("b".parse().unwrap(), ColumnType::BigInt), @@ -177,7 +177,7 @@ fn we_can_get_an_empty_result_from_a_basic_projection_on_an_empty_table_using_re ), ]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected: OwnedTable = owned_table([ @@ -204,11 +204,11 @@ fn we_can_get_no_columns_from_a_basic_projection_with_no_selected_columns_using_ accessor.add_table(t, data, 0); let expr: DynProofPlan = projection(cols_expr_plan(t, &[], &accessor), tab(t)); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(5); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected = OwnedTable::try_new(IndexMap::default()).unwrap(); @@ -240,7 +240,7 @@ fn we_can_get_the_correct_result_from_a_basic_projection_using_result_evaluate() tab(t), ); let alloc = Bump::new(); - let mut builder = ResultBuilder::new(5); + let mut builder = ResultBuilder::new(); let result_cols = expr.result_evaluate(&mut builder, &alloc, &accessor); let fields = &[ ColumnField::new("b".parse().unwrap(), ColumnType::BigInt), @@ -252,7 +252,7 @@ fn we_can_get_the_correct_result_from_a_basic_projection_using_result_evaluate() ), ]; let res: OwnedTable = - ProvableQueryResult::new(&builder.result_index_vector, &result_cols) + ProvableQueryResult::new(builder.result_table_length() as u64, &result_cols) .to_owned_table(fields) .unwrap(); let expected: OwnedTable = owned_table([