Skip to content

Commit

Permalink
refactor!: drop counts from verifier (#427)
Browse files Browse the repository at this point in the history
# Rationale for this change

In order to simplify the verifier, we wish to only need to traverse the
ProofPlan once. The `counts` method requires a second pass in addition
to `verifier_evaluate`. This PR removes the need for this.

# What changes are included in this PR?

See the individual commits. At a high level
* The methods in `VerificationBuilder` are made fallible so that the
verifier will catch incorrect proof sizes just in time.
* The use of counts is dropped.

# Are these changes tested?
Yes
  • Loading branch information
iajoiner authored Dec 12, 2024
2 parents 0bac0cb + 4aafb49 commit ea47dae
Show file tree
Hide file tree
Showing 43 changed files with 423 additions and 651 deletions.
19 changes: 19 additions & 0 deletions crates/proof-of-sql/src/base/bit/bit_distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ impl BitDistribution {
true
}

/// In order to avoid cases with large numbers where there can be both a positive and negative
/// representation, we restrict the range of bit distributions that we accept.
///
/// Currently this is set to be the minimal value that will include the sum of two signed 128-bit
/// integers. The range will likely be expanded in the future as we support additional expressions.
pub fn is_within_acceptable_range(&self) -> bool {
// handle the case of everything zero
if self.num_varying_bits() == 0 && self.constant_part() == [0; 4] {
return true;
}

// signed 128 bit numbers range from
// -2^127 to 2^127-1
// the maximum absolute value of the sum of two signed 128-integers is
// then
// 2 * (2^127) = 2^128
self.most_significant_abs_bit() <= 128
}

/// If `{b_i}` represents the non-varying 1-bits of the absolute values, return the value
/// `sum_i b_i 2 ^ i`
pub fn constant_part(&self) -> [u64; 4] {
Expand Down
23 changes: 23 additions & 0 deletions crates/proof-of-sql/src/base/bit/bit_distribution_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,26 @@ fn we_can_detect_invalid_bit_distributions() {
};
assert!(!dist.is_valid());
}

#[test]
fn zero_is_within_range() {
let data: Vec<TestScalar> = vec![TestScalar::from(0)];
let dist = BitDistribution::new::<TestScalar, _>(&data);
assert!(dist.is_within_acceptable_range());
}

#[test]
fn the_sum_of_two_signed_128_bit_numbers_is_within_range() {
let data: Vec<TestScalar> = vec![TestScalar::from(i128::MIN) + TestScalar::from(i128::MIN)];
let dist = BitDistribution::new::<TestScalar, _>(&data);
assert!(dist.is_within_acceptable_range());
}

#[test]
fn we_reject_distributions_that_are_outside_of_maximum_range() {
let data: Vec<TestScalar> = vec![
TestScalar::from(u128::MAX) + TestScalar::from(u128::MAX) + TestScalar::from(u128::MAX),
];
let dist = BitDistribution::new::<TestScalar, _>(&data);
assert!(!dist.is_within_acceptable_range());
}
25 changes: 25 additions & 0 deletions crates/proof-of-sql/src/base/proof/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,29 @@ pub enum ProofError {
/// This error occurs when the number of fields in the result table does not match the query.
#[snafu(display("Result does not match query: field count mismatch"))]
FieldCountMismatch,
#[snafu(transparent)]
ProofSizeMismatch { source: ProofSizeMismatch },
}

#[derive(Snafu, Debug)]
/// These errors occur when the proof size does not match the expected size.
pub enum ProofSizeMismatch {
/// This error occurs when the sumcheck proof doesn't have enough coefficients.
#[snafu(display("Sumcheck proof is too small"))]
SumcheckProofTooSmall,
/// This error occurs when the proof has too few MLE evaluations.
#[snafu(display("Proof has too few MLE evaluations"))]
TooFewMLEEvaluations,
/// This error occurs when the number of post result challenges in the proof plan doesn't match the number specified in the proof
#[snafu(display("Post result challenge count mismatch"))]
PostResultCountMismatch,
/// This error occurs when the number of constraints in the proof plan doesn't match the number specified in the proof
#[snafu(display("Constraint count mismatch"))]
ConstraintCountMismatch,
/// This error occurs when the proof has too few bit distributions.
#[snafu(display("Proof has too few bit distributions"))]
TooFewBitDistributions,
/// This error occurs when the proof has too few one lengths.
#[snafu(display("Proof has too few one lengths"))]
TooFewOneLengths,
}
2 changes: 1 addition & 1 deletion crates/proof-of-sql/src/base/proof/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Contains the transcript protocol used to construct a proof,
//! as well as an error type which can occur when verification fails.
mod error;
pub use error::ProofError;
pub use error::{ProofError, ProofSizeMismatch};

/// Contains an extension trait for `merlin::Transcript`, which is used to construct a proof.
#[cfg(any(test, feature = "blitzar"))]
Expand Down
13 changes: 8 additions & 5 deletions crates/proof-of-sql/src/proof_primitive/sumcheck/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct SumcheckProof<S: Scalar> {
pub struct Subclaim<S: Scalar> {
pub evaluation_point: Vec<S>,
pub expected_evaluation: S,
pub max_multiplicands: usize,
}

impl<S: Scalar> SumcheckProof<S> {
Expand Down Expand Up @@ -57,18 +58,19 @@ impl<S: Scalar> SumcheckProof<S> {
pub fn verify_without_evaluation(
&self,
transcript: &mut impl Transcript,
max_multiplicands: usize,
num_variables: usize,
claimed_sum: &S,
) -> Result<Subclaim<S>, ProofError> {
transcript.extend_as_be([max_multiplicands as u64, num_variables as u64]);
// This challenge is in order to keep transcript messages grouped. (This simplifies the Solidity implementation.)
transcript.scalar_challenge_as_be::<S>();
if self.coefficients.len() != num_variables * (max_multiplicands + 1) {
let coefficients_len = self.coefficients.len();
if coefficients_len % num_variables != 0 {
return Err(ProofError::VerificationError {
error: "invalid proof size",
});
}
let max_multiplicands = (coefficients_len / num_variables) - 1;
transcript.extend_as_be([max_multiplicands as u64, num_variables as u64]);
// This challenge is in order to keep transcript messages grouped. (This simplifies the Solidity implementation.)
transcript.scalar_challenge_as_be::<S>();
let mut evaluation_point = Vec::with_capacity(num_variables);

let mut expected_evaluation = *claimed_sum;
Expand Down Expand Up @@ -97,6 +99,7 @@ impl<S: Scalar> SumcheckProof<S> {
Ok(Subclaim {
evaluation_point,
expected_evaluation,
max_multiplicands,
})
}
}
34 changes: 5 additions & 29 deletions crates/proof-of-sql/src/proof_primitive/sumcheck/proof_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ fn test_create_verify_proof() {
let subclaim = proof
.verify_without_evaluation(
&mut transcript,
poly.max_multiplicands,
poly.num_variables,
&Curve25519Scalar::from(579u64),
)
Expand All @@ -59,7 +58,6 @@ fn test_create_verify_proof() {
let subclaim = proof
.verify_without_evaluation(
&mut transcript,
poly.max_multiplicands,
poly.num_variables,
&Curve25519Scalar::from(579u64),
)
Expand All @@ -70,7 +68,6 @@ fn test_create_verify_proof() {
let mut transcript = Transcript::new(b"sumchecktest");
let subclaim = proof.verify_without_evaluation(
&mut transcript,
poly.max_multiplicands,
poly.num_variables,
&Curve25519Scalar::from(123u64),
);
Expand All @@ -80,7 +77,6 @@ fn test_create_verify_proof() {
proof.coefficients[0] += Curve25519Scalar::from(3u64);
let subclaim = proof.verify_without_evaluation(
&mut transcript,
poly.max_multiplicands,
poly.num_variables,
&Curve25519Scalar::from(579u64),
);
Expand Down Expand Up @@ -148,12 +144,7 @@ fn test_polynomial(nv: usize, num_multiplicands_range: (usize, usize), num_produ
// verify proof
let mut transcript = Transcript::new(b"sumchecktest");
let subclaim = proof
.verify_without_evaluation(
&mut transcript,
poly.max_multiplicands,
poly.num_variables,
&asserted_sum,
)
.verify_without_evaluation(&mut transcript, poly.num_variables, &asserted_sum)
.expect("verify failed");
assert_eq!(subclaim.evaluation_point, evaluation_point);
assert_eq!(
Expand Down Expand Up @@ -195,12 +186,7 @@ fn we_can_verify_many_random_test_cases() {

let mut transcript = Transcript::new(b"sumchecktest");
let subclaim = proof
.verify_without_evaluation(
&mut transcript,
test_case.max_multiplicands,
test_case.num_vars,
&test_case.sum,
)
.verify_without_evaluation(&mut transcript, test_case.num_vars, &test_case.sum)
.expect("verification should succeed with the correct setup");
assert_eq!(
subclaim.evaluation_point, evaluation_point,
Expand All @@ -214,12 +200,8 @@ fn we_can_verify_many_random_test_cases() {

let mut transcript = Transcript::new(b"sumchecktest");
transcript.extend_serialize_as_le(&123u64);
let verify_result = proof.verify_without_evaluation(
&mut transcript,
test_case.max_multiplicands,
test_case.num_vars,
&test_case.sum,
);
let verify_result =
proof.verify_without_evaluation(&mut transcript, test_case.num_vars, &test_case.sum);
if let Ok(subclaim) = verify_result {
assert_ne!(
subclaim.evaluation_point, evaluation_point,
Expand All @@ -232,7 +214,6 @@ fn we_can_verify_many_random_test_cases() {
proof
.verify_without_evaluation(
&mut transcript,
test_case.max_multiplicands,
test_case.num_vars,
&(test_case.sum + TestScalar::ONE),
)
Expand All @@ -245,12 +226,7 @@ fn we_can_verify_many_random_test_cases() {
let mut transcript = Transcript::new(b"sumchecktest");
assert!(
modified_proof
.verify_without_evaluation(
&mut transcript,
test_case.max_multiplicands,
test_case.num_vars,
&test_case.sum,
)
.verify_without_evaluation(&mut transcript, test_case.num_vars, &test_case.sum,)
.is_err(),
"verification should fail when the proof is modified"
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use itertools::Itertools;
pub struct SumcheckTestCase<S: Scalar> {
pub polynomial: CompositePolynomial<S>,
pub num_vars: usize,
pub max_multiplicands: usize,
pub sum: S,
}

Expand Down Expand Up @@ -38,7 +37,6 @@ impl<S: Scalar> SumcheckTestCase<S> {
Self {
polynomial,
num_vars,
max_multiplicands,
sum,
}
}
Expand Down
74 changes: 0 additions & 74 deletions crates/proof-of-sql/src/sql/proof/count_builder.rs

This file was deleted.

2 changes: 0 additions & 2 deletions crates/proof-of-sql/src/sql/proof/first_round_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ impl FirstRoundBuilder {
/// Specifically, these are the challenges that the verifier sends to
/// the prover after the prover sends the result, but before the prover
/// send commitments to the intermediate witness columns.
///
/// Note: this must be matched with the same count in the [`CountBuilder`](crate::sql::proof::CountBuilder).
pub fn request_post_result_challenges(&mut self, cnt: usize) {
self.num_post_result_challenges += cnt;
}
Expand Down
5 changes: 0 additions & 5 deletions crates/proof-of-sql/src/sql/proof/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
//! TODO: add docs
mod count_builder;
pub(crate) use count_builder::CountBuilder;
mod final_round_builder;
pub(crate) use final_round_builder::FinalRoundBuilder;
Expand All @@ -12,9 +10,6 @@ pub(crate) use composite_polynomial_builder::CompositePolynomialBuilder;
#[cfg(test)]
mod composite_polynomial_builder_test;

mod proof_counts;
pub(crate) use proof_counts::ProofCounts;

mod verification_builder;
pub(crate) use verification_builder::VerificationBuilder;
#[cfg(test)]
Expand Down
36 changes: 0 additions & 36 deletions crates/proof-of-sql/src/sql/proof/proof_counts.rs

This file was deleted.

5 changes: 1 addition & 4 deletions crates/proof-of-sql/src/sql/proof/proof_plan.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{CountBuilder, FinalRoundBuilder, FirstRoundBuilder, VerificationBuilder};
use super::{FinalRoundBuilder, FirstRoundBuilder, VerificationBuilder};
use crate::base::{
database::{ColumnField, ColumnRef, OwnedTable, Table, TableEvaluation, TableRef},
map::{IndexMap, IndexSet},
Expand All @@ -12,9 +12,6 @@ use core::fmt::Debug;
/// Provable nodes in the provable AST.
#[enum_dispatch::enum_dispatch(DynProofPlan)]
pub trait ProofPlan: Debug + Send + Sync + ProverEvaluate {
/// Count terms used within the Query's proof
fn count(&self, builder: &mut CountBuilder) -> Result<(), ProofError>;

/// Form components needed to verify and proof store into `VerificationBuilder`
fn verifier_evaluate<S: Scalar>(
&self,
Expand Down
Loading

0 comments on commit ea47dae

Please sign in to comment.