Skip to content

Commit

Permalink
Merge branch 'main' into refactor-ident
Browse files Browse the repository at this point in the history
  • Loading branch information
varshith257 authored Dec 16, 2024
2 parents e5e1163 + c8ac34f commit 2e6b0f3
Show file tree
Hide file tree
Showing 26 changed files with 1,020 additions and 18 deletions.
3 changes: 3 additions & 0 deletions crates/proof-of-sql/src/base/slice_ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ mod mul_add_assign_test;
mod slice_cast;
#[cfg(test)]
mod slice_cast_test;
mod sub;

pub use add_const::*;
pub use inner_product::*;
pub use mul_add_assign::*;
pub use slice_cast::*;
#[allow(unused_imports)]
pub use sub::*;

mod batch_inverse;
pub use batch_inverse::*;
Expand Down
76 changes: 76 additions & 0 deletions crates/proof-of-sql/src/base/slice_ops/sub.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::base::if_rayon;
use core::ops::Sub;
#[cfg(feature = "rayon")]
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};

#[allow(dead_code)]
/// This operation does `result[i] = lhs[i] - rhs[i]` for `i` in `0..lhs.len()`.
///
/// # Panics
/// Panics if the length of `lhs` and `rhs` are not equal.
pub fn sub<T>(result: &mut [T], lhs: &[T], rhs: &[T])
where
T: Send + Sync + Sub<Output = T> + Copy,
{
assert!(
lhs.len() == rhs.len(),
"The length of lhs and rhs must be equal"
);
if_rayon!(
result.par_iter_mut().with_min_len(super::MIN_RAYON_LEN),
result.iter_mut()
)
.zip(lhs)
.zip(rhs)
.for_each(|((res_i, &lhs_i), &rhs_i)| {
*res_i = lhs_i - rhs_i;
});
}

#[cfg(test)]
mod tests {
use super::sub;
use crate::base::scalar::{test_scalar::TestScalar, Scalar};

#[test]
fn test_sub() {
let lhs = vec![5, 10, 15, 20];
let rhs = vec![1, 2, 3, 4];
let mut result = vec![0; lhs.len()];
sub(&mut result, &lhs, &rhs);
assert_eq!(result, vec![4, 8, 12, 16]);
}

#[test]
#[should_panic(expected = "The length of lhs and rhs must be equal")]
fn test_sub_panic() {
let lhs = vec![5, 10, 15];
let rhs = vec![1, 2, 3, 4];
let mut result = vec![0; lhs.len()];
sub(&mut result, &lhs, &rhs);
}

#[test]
fn test_sub_with_scalars() {
let lhs = vec![
TestScalar::from(5),
TestScalar::from(10),
TestScalar::from(15),
];
let rhs = vec![
TestScalar::from(10),
TestScalar::from(9),
TestScalar::from(3),
];
let mut result = vec![TestScalar::ZERO; lhs.len()];
sub(&mut result, &lhs, &rhs);
assert_eq!(
result,
vec![
TestScalar::from(-5),
TestScalar::from(1),
TestScalar::from(12)
]
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub const FILTER_EXEC_NUM: u8 = 0;

pub const COLUMN_EXPR_NUM: u8 = 0;
pub const EQUALS_EXPR_NUM: u8 = 1;
pub const LITERAL_EXPR_NUM: u8 = 2;

pub const BIGINT_TYPE_NUM: u8 = 0;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use snafu::Snafu;

/// Errors that can occur during proof plan serialization.
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(super)))]
pub enum ProofPlanSerializationError {
/// Error indicating that the operation is not supported.
#[snafu(display("Not supported"))]
NotSupported,
/// Error indicating that there are more than 255 results in the filter.
#[snafu(display("More than 255 results in filter."))]
TooManyResults,
/// Error indicating that there are more than 255 tables referenced in the plan.
#[snafu(display("More than 255 tables referenced in the plan."))]
TooManyTables,
/// Error indicating that there are more than 255 columns referenced in the plan.
#[snafu(display("More than 255 columns referenced in the plan."))]
TooManyColumns,
/// Error indicating that the table was not found.
#[snafu(display("Table not found"))]
TableNotFound,
/// Error indicating that the column was not found.
#[snafu(display("Column not found"))]
ColumnNotFound,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// This module contains constants used in the proof serialization process.
pub(super) mod constants;

/// This module defines errors that can occur during proof plan serialization.
mod error;

/// This module handles the serialization of proof expressions.
mod serialize_proof_expr;

/// This module handles the serialization of proof plans.
mod serialize_proof_plan;

/// This module provides the main serializer for proof plans.
mod serializer;

pub use error::ProofPlanSerializationError;
pub use serializer::DynProofPlanSerializer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
use super::{
constants::{BIGINT_TYPE_NUM, COLUMN_EXPR_NUM, EQUALS_EXPR_NUM, LITERAL_EXPR_NUM},
error::{ColumnNotFoundSnafu, NotSupportedSnafu},
DynProofPlanSerializer, ProofPlanSerializationError,
};
use crate::{
base::{database::LiteralValue, scalar::Scalar},
evm_compatibility::primitive_serialize_ext::PrimitiveSerializeExt,
sql::proof_exprs::{ColumnExpr, DynProofExpr, EqualsExpr, LiteralExpr},
};
use snafu::OptionExt;

impl<S: Scalar> DynProofPlanSerializer<S> {
pub(super) fn serialize_dyn_proof_expr(
self,
expr: &DynProofExpr,
) -> Result<Self, ProofPlanSerializationError> {
match expr {
DynProofExpr::Column(column_expr) => self
.serialize_u8(COLUMN_EXPR_NUM)
.serialize_column_expr(column_expr),
DynProofExpr::Literal(literal_expr) => self
.serialize_u8(LITERAL_EXPR_NUM)
.serialize_literal_expr(literal_expr),
DynProofExpr::Equals(equals_expr) => self
.serialize_u8(EQUALS_EXPR_NUM)
.serialize_equals_expr(equals_expr),
_ => NotSupportedSnafu.fail(),
}
}

fn serialize_column_expr(
self,
column_expr: &ColumnExpr,
) -> Result<Self, ProofPlanSerializationError> {
let column_number = self
.column_refs
.get(&column_expr.column_ref)
.copied()
.context(ColumnNotFoundSnafu)?;
Ok(self.serialize_u8(column_number))
}

fn serialize_literal_expr(
self,
literal_expr: &LiteralExpr,
) -> Result<Self, ProofPlanSerializationError> {
match literal_expr.value {
LiteralValue::BigInt(value) => Ok(self
.serialize_u8(BIGINT_TYPE_NUM)
.serialize_scalar(value.into())),
_ => NotSupportedSnafu.fail(),
}
}

fn serialize_equals_expr(
self,
equals_expr: &EqualsExpr,
) -> Result<Self, ProofPlanSerializationError> {
self.serialize_dyn_proof_expr(equals_expr.lhs.as_ref())?
.serialize_dyn_proof_expr(equals_expr.rhs.as_ref())
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
base::{
database::{ColumnRef, ColumnType, TableRef},
map::indexset,
scalar::test_scalar::TestScalar,
},
sql::proof_exprs::AndExpr,
};
use core::iter;
use itertools::Itertools;

#[test]
fn we_can_serialize_a_column_expr() {
let table_ref: TableRef = "namespace.table".parse().unwrap();
let column_0_ref: ColumnRef =
ColumnRef::new(table_ref, "column_0".parse().unwrap(), ColumnType::BigInt);
let column_1_ref: ColumnRef =
ColumnRef::new(table_ref, "column_1".parse().unwrap(), ColumnType::BigInt);
let column_2_ref: ColumnRef =
ColumnRef::new(table_ref, "column_2".parse().unwrap(), ColumnType::BigInt);
let serializer = DynProofPlanSerializer::<TestScalar>::try_new(
indexset! {},
indexset! { column_0_ref, column_1_ref },
)
.unwrap();

// Serialization of column 0 should result in a single byte with value 0.
let column_0_expr = ColumnExpr::new(column_0_ref);
let bytes_0 = serializer
.clone()
.serialize_column_expr(&column_0_expr)
.unwrap()
.into_bytes();
assert_eq!(bytes_0, vec![0]);

// Serialization of column 1 should result in a single byte with value 1.
let column_1_expr = ColumnExpr::new(column_1_ref);
let bytes_1 = serializer
.clone()
.serialize_column_expr(&column_1_expr)
.unwrap()
.into_bytes();
assert_eq!(bytes_1, vec![1]);

// Wrapping the column expression in a `DynProofExpr` should result in the same serialization,
// but with the column expression number prepended.
let wrapped_column_1_expr = DynProofExpr::Column(column_1_expr);
let wrapped_bytes_1 = serializer
.clone()
.serialize_dyn_proof_expr(&wrapped_column_1_expr)
.unwrap()
.into_bytes();
assert_eq!(wrapped_bytes_1, vec![COLUMN_EXPR_NUM, 1]);

// Serialization of column 2 should result in an error because there are only two columns.
let column_2_expr = ColumnExpr::new(column_2_ref);
let result = serializer.clone().serialize_column_expr(&column_2_expr);
assert!(matches!(
result,
Err(ProofPlanSerializationError::ColumnNotFound)
));
}

#[test]
fn we_can_serialize_a_literal_expr() {
let serializer =
DynProofPlanSerializer::<TestScalar>::try_new(indexset! {}, indexset! {}).unwrap();

// Serialization of a big int literal should result in a byte with the big int type number,
// followed by the big int value in big-endian form, padded with leading zeros to 32 bytes.
let literal_bigint_expr = LiteralExpr::new(LiteralValue::BigInt(4200));
let bigint_bytes = serializer
.clone()
.serialize_literal_expr(&literal_bigint_expr)
.unwrap()
.into_bytes();
let expected_bigint_bytes = iter::empty::<u8>()
.chain([BIGINT_TYPE_NUM])
.chain([0; 30])
.chain([16, 104])
.collect_vec();
assert_eq!(bigint_bytes, expected_bigint_bytes);

// Wrapping the literal expression in a `DynProofExpr` should result in the same serialization,
// but with the literal expression number prepended.
let wrapped_literal_expr = DynProofExpr::Literal(literal_bigint_expr);
let wrapped_bytes = serializer
.clone()
.serialize_dyn_proof_expr(&wrapped_literal_expr)
.unwrap()
.into_bytes();
let expected_wrapped_bytes = iter::empty::<u8>()
.chain([LITERAL_EXPR_NUM])
.chain(expected_bigint_bytes)
.collect_vec();
assert_eq!(wrapped_bytes, expected_wrapped_bytes);

// Serialization of a small int literal should result in an error
// because only big int literals are supported so far
let literal_smallint_expr = LiteralExpr::new(LiteralValue::SmallInt(4200));
let result = serializer
.clone()
.serialize_literal_expr(&literal_smallint_expr);
assert!(matches!(
result,
Err(ProofPlanSerializationError::NotSupported)
));
}

#[test]
fn we_can_serialize_an_equals_expr() {
let table_ref: TableRef = "namespace.table".parse().unwrap();
let column_0_ref: ColumnRef =
ColumnRef::new(table_ref, "column_0".parse().unwrap(), ColumnType::BigInt);
let serializer =
DynProofPlanSerializer::<TestScalar>::try_new(indexset! {}, indexset! { column_0_ref })
.unwrap();

let lhs = DynProofExpr::Column(ColumnExpr::new(column_0_ref));
let rhs = DynProofExpr::Literal(LiteralExpr::new(LiteralValue::BigInt(4200)));
let lhs_bytes = serializer
.clone()
.serialize_dyn_proof_expr(&lhs)
.unwrap()
.into_bytes();
let rhs_bytes = serializer
.clone()
.serialize_dyn_proof_expr(&rhs)
.unwrap()
.into_bytes();

// Serialization of an equals expression should result in the serialization of the left-hand side,
// followed by the serialization of the right-hand side.
let equals_expr = EqualsExpr::new(Box::new(lhs.clone()), Box::new(rhs.clone()));
let bytes = serializer
.clone()
.serialize_equals_expr(&equals_expr)
.unwrap()
.into_bytes();
let expected_bytes = iter::empty::<u8>()
.chain(lhs_bytes.clone())
.chain(rhs_bytes.clone())
.collect_vec();
assert_eq!(bytes, expected_bytes);

// Wrapping the equals expression in a `DynProofExpr` should result in the same serialization,
// but with the equals expression number prepended.
let wrapped_equals_expr = DynProofExpr::Equals(equals_expr);
let wrapped_bytes = serializer
.clone()
.serialize_dyn_proof_expr(&wrapped_equals_expr)
.unwrap()
.into_bytes();
let expected_wrapped_bytes = iter::empty::<u8>()
.chain([EQUALS_EXPR_NUM])
.chain(expected_bytes)
.collect_vec();
assert_eq!(wrapped_bytes, expected_wrapped_bytes);
}

#[test]
fn we_cannot_serialize_an_unsupported_expr() {
let table_ref: TableRef = "namespace.table".parse().unwrap();
let column_0_ref: ColumnRef =
ColumnRef::new(table_ref, "column_0".parse().unwrap(), ColumnType::BigInt);
let serializer =
DynProofPlanSerializer::<TestScalar>::try_new(indexset! {}, indexset! { column_0_ref })
.unwrap();

let lhs = DynProofExpr::Column(ColumnExpr::new(column_0_ref));
let rhs = DynProofExpr::Literal(LiteralExpr::new(LiteralValue::BigInt(4200)));
let expr = DynProofExpr::And(AndExpr::new(Box::new(lhs.clone()), Box::new(rhs.clone())));
let result = serializer.clone().serialize_dyn_proof_expr(&expr);
assert!(matches!(
result,
Err(ProofPlanSerializationError::NotSupported)
));
}
}
Loading

0 comments on commit 2e6b0f3

Please sign in to comment.