use super::{DynProofExpr, PlaceholderExpr, ProofExpr};
use crate::{
base::{
commitment::InnerProductProof,
database::{
owned_table_utility::*, table_utility::*, Column, ColumnType, LiteralValue,
OwnedTableTestAccessor, Table, TableRef, TableTestAccessor,
},
proof::{PlaceholderError, ProofError},
},
proof_primitive::inner_product::curve_25519_scalar::Curve25519Scalar,
sql::{
proof::{QueryError, VerifiableQueryResult},
proof_exprs::test_utility::*,
proof_plans::test_utility::*,
},
};
use bumpalo::Bump;
use rand::{
distributions::{Distribution, Uniform},
rngs::StdRng,
};
use rand_core::SeedableRng;
#[test]
fn we_can_get_id_and_type_of_placeholder_expr() {
let expr = PlaceholderExpr::try_new(1, ColumnType::Boolean).unwrap();
assert_eq!(expr.data_type(), ColumnType::Boolean);
assert_eq!(expr.index(), 0);
}
fn test_random_tables_with_given_offset(offset: usize) {
let dist = Uniform::new(-3, 4);
let mut rng = StdRng::from_seed([0u8; 32]);
for _ in 0..20 {
let n = Uniform::new(1, 21).sample(&mut rng);
let data = owned_table([
boolean("a", dist.sample_iter(&mut rng).take(n).map(|v| v < 0)),
varchar(
"b",
dist.sample_iter(&mut rng).take(n).map(|v| format!("s{v}")),
),
bigint("c", dist.sample_iter(&mut rng).take(n)),
]);
let random_bigint = dist.sample(&mut rng);
let random_bigint_literal = LiteralValue::BigInt(random_bigint);
let random_varchar = format!("s{}", dist.sample(&mut rng));
let random_varchar_literal = LiteralValue::VarChar(random_varchar.clone());
let t = TableRef::new("sxt", "t");
let accessor = OwnedTableTestAccessor::<InnerProductProof>::new_from_table(
t.clone(),
data.clone(),
offset,
(),
);
let ast = filter(
vec![
col_expr_plan(&t, "a", &accessor),
col_expr_plan(&t, "b", &accessor),
col_expr_plan(&t, "c", &accessor),
aliased_placeholder(1, ColumnType::BigInt, "p1"),
aliased_placeholder(2, ColumnType::VarChar, "p2"),
],
table_exec(
t.clone(),
vec![
column_field("a", ColumnType::Boolean),
column_field("b", ColumnType::VarChar),
column_field("c", ColumnType::BigInt),
],
),
const_bool(true),
);
let params = vec![random_bigint_literal, random_varchar_literal];
let verifiable_res =
VerifiableQueryResult::<InnerProductProof>::new(&ast, &accessor, &(), ¶ms).unwrap();
let res = verifiable_res
.verify(&ast, &accessor, &(), ¶ms)
.unwrap()
.table;
let expected_a: Vec<bool> = data["a"].bool_iter().copied().collect();
let expected_b: Vec<String> = data["b"].string_iter().cloned().collect();
let expected_c: Vec<i64> = data["c"].i64_iter().copied().collect();
let expected_p1: Vec<i64> = vec![random_bigint; n];
let expected_p2: Vec<String> = vec![random_varchar.clone(); n];
let expected_result = owned_table([
boolean("a", expected_a),
varchar("b", expected_b),
bigint("c", expected_c),
bigint("p1", expected_p1),
varchar("p2", expected_p2),
]);
assert_eq!(expected_result, res);
}
}
#[test]
fn we_can_query_random_tables_using_a_zero_offset() {
test_random_tables_with_given_offset(0);
}
#[test]
fn we_can_query_random_tables_using_a_non_zero_offset() {
test_random_tables_with_given_offset(5121);
}
#[test]
fn we_can_prove_a_query_with_a_single_selected_row() {
let data = owned_table([bigint("a", [123_i64])]);
let expected_res = owned_table([boolean("p1", [true])]);
let t = TableRef::new("sxt", "t");
let accessor =
OwnedTableTestAccessor::<InnerProductProof>::new_from_table(t.clone(), data, 0, ());
let ast = filter(
vec![aliased_placeholder(1, ColumnType::Boolean, "p1")],
table_exec(t.clone(), vec![column_field("a", ColumnType::BigInt)]),
const_bool(true),
);
let verifiable_res = VerifiableQueryResult::<InnerProductProof>::new(
&ast,
&accessor,
&(),
&[LiteralValue::Boolean(true)],
)
.unwrap();
let res = verifiable_res
.verify(&ast, &accessor, &(), &[LiteralValue::Boolean(true)])
.unwrap()
.table;
assert_eq!(res, expected_res);
}
#[test]
fn we_can_prove_a_query_with_a_single_non_selected_row() {
let data = owned_table([bigint("a", [123_i64])]);
let expected_res = owned_table([boolean("p1", [true; 0])]);
let t = TableRef::new("sxt", "t");
let accessor =
OwnedTableTestAccessor::<InnerProductProof>::new_from_table(t.clone(), data, 0, ());
let ast = filter(
vec![aliased_placeholder(1, ColumnType::Boolean, "p1")],
table_exec(t.clone(), vec![column_field("a", ColumnType::BigInt)]),
const_bool(false),
);
let verifiable_res = VerifiableQueryResult::<InnerProductProof>::new(
&ast,
&accessor,
&(),
&[LiteralValue::Boolean(true)],
)
.unwrap();
let res = verifiable_res
.verify(&ast, &accessor, &(), &[LiteralValue::Boolean(true)])
.unwrap()
.table;
assert_eq!(res, expected_res);
}
#[test]
fn we_can_compute_the_correct_output_of_a_placeholder_expr_using_first_round_evaluate() {
let alloc = Bump::new();
let data: Table<Curve25519Scalar> =
table([borrowed_bigint("a", [123_i64, 456, 789, 1011], &alloc)]);
let placeholder_expr: DynProofExpr =
DynProofExpr::try_new_placeholder(1, ColumnType::BigInt).unwrap();
let res = placeholder_expr
.first_round_evaluate(&alloc, &data, &[LiteralValue::BigInt(504_i64)])
.unwrap();
let expected_res = Column::BigInt(&[504, 504, 504, 504]);
assert_eq!(res, expected_res);
}
#[test]
fn we_cannot_prove_placeholder_expr_if_interpolate_fails() {
let alloc = Bump::new();
let data: Table<Curve25519Scalar> = table([borrowed_bigint("a", [123_i64], &alloc)]);
let t = TableRef::new("sxt", "t");
let accessor = TableTestAccessor::<InnerProductProof>::new_from_table(t.clone(), data, 0, ());
let ast = filter(
vec![aliased_placeholder(1, ColumnType::Boolean, "p1")],
table_exec(t.clone(), vec![column_field("a", ColumnType::BigInt)]),
const_bool(true),
);
assert!(matches!(
VerifiableQueryResult::<InnerProductProof>::new(&ast, &accessor, &(), &[],),
Err(PlaceholderError::InvalidPlaceholderIndex { .. })
));
}
#[test]
fn we_cannot_verify_placeholder_expr_if_interpolate_fails() {
let alloc = Bump::new();
let data: Table<Curve25519Scalar> = table([borrowed_bigint("a", [123_i64], &alloc)]);
let t = TableRef::new("sxt", "t");
let accessor = TableTestAccessor::<InnerProductProof>::new_from_table(t.clone(), data, 0, ());
let ast = filter(
vec![aliased_placeholder(1, ColumnType::Boolean, "p1")],
table_exec(t.clone(), vec![column_field("a", ColumnType::BigInt)]),
const_bool(true),
);
let verifiable_res = VerifiableQueryResult::<InnerProductProof>::new(
&ast,
&accessor,
&(),
&[LiteralValue::Boolean(true)],
)
.unwrap();
assert!(matches!(
verifiable_res.verify(&ast, &accessor, &(), &[]),
Err(QueryError::ProofError {
source: ProofError::PlaceholderError { .. }
})
));
}
#[test]
fn we_can_verify_placeholder_expr_if_and_only_if_prover_and_verifier_have_the_same_valid_params() {
let alloc = Bump::new();
let data: Table<Curve25519Scalar> = table([borrowed_bigint("a", [123_i64, 456], &alloc)]);
let t = TableRef::new("sxt", "t");
let accessor = TableTestAccessor::<InnerProductProof>::new_from_table(t.clone(), data, 0, ());
let ast = filter(
vec![
col_expr_plan(&t, "a", &accessor),
aliased_placeholder(1, ColumnType::BigInt, "p1"),
aliased_placeholder(2, ColumnType::VarChar, "p2"),
],
table_exec(t.clone(), vec![column_field("a", ColumnType::BigInt)]),
const_bool(true),
);
let verifiable_res = VerifiableQueryResult::<InnerProductProof>::new(
&ast,
&accessor,
&(),
&[
LiteralValue::BigInt(504_i64),
LiteralValue::VarChar("abc".to_string()),
],
)
.unwrap();
assert!(matches!(
verifiable_res.clone().verify(
&ast,
&accessor,
&(),
&[
LiteralValue::BigInt(503_i64),
LiteralValue::VarChar("abc".to_string())
]
),
Err(QueryError::ProofError { .. })
));
assert!(matches!(
verifiable_res.clone().verify(
&ast,
&accessor,
&(),
&[
LiteralValue::BigInt(504_i64),
LiteralValue::VarChar("abcd".to_string())
]
),
Err(QueryError::ProofError { .. })
));
assert!(matches!(
verifiable_res.clone().verify(
&ast,
&accessor,
&(),
&[
LiteralValue::BigInt(503_i64),
LiteralValue::VarChar("abcd".to_string())
]
),
Err(QueryError::ProofError { .. })
));
let res = verifiable_res
.verify(
&ast,
&accessor,
&(),
&[
LiteralValue::BigInt(504_i64),
LiteralValue::VarChar("abc".to_string()),
],
)
.unwrap()
.table;
let expected_res = owned_table([
bigint("a", [123_i64, 456]),
bigint("p1", [504_i64, 504]),
varchar("p2", ["abc", "abc"]),
]);
assert_eq!(res, expected_res);
}