From bb75e9d4d225b4ab03f0db3c5003bfd456b2aed8 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Thu, 19 Sep 2024 17:18:10 +0200 Subject: [PATCH 1/5] add more information to some errors --- src/lib.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 17690c8..d8e2eb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,12 +32,18 @@ mod tests; pub enum VerifyError { BadFoldingFactor(usize), /// when $|D_i| \neq 2^\bullet$ or $|D_i| \leq k_i$ - BadDomainSize(usize), + BadDomainSize { + size: usize, + degree_bound: Option<usize>, + }, /// when $k_i \neq 2^\bullet$ BadDegreeBound(usize), /// when $|D_i| \neq 0 \quad\text{mod}\quad N$ or $k_i \neq 0 \quad\text{mod}\quad N$ DegreeTruncation { depth: usize, + size: usize, + degree_bound: usize, + folding_factor: usize, }, /// one of the commitment layers did not verify CommitmentMismatch { @@ -251,7 +257,10 @@ impl<F: FftField, H: Hasher> FriProof<F, H> { let () = AssertPowerOfTwo::<N>::OK; if !domain_size.is_power_of_two() || domain_size <= degree_bound { - return Err(VerifyError::BadDomainSize(domain_size)); + return Err(VerifyError::BadDomainSize { + size: domain_size, + degree_bound: Some(degree_bound), + }); } if !degree_bound.is_power_of_two() { return Err(VerifyError::BadDegreeBound(degree_bound)); @@ -260,7 +269,10 @@ impl<F: FftField, H: Hasher> FriProof<F, H> { return Err(VerifyError::BadFoldingFactor(N)); }; let Some(mut root) = F::get_root_of_unity(domain_size as u64) else { - return Err(VerifyError::BadDomainSize(domain_size)); + return Err(VerifyError::BadDomainSize { + size: domain_size, + degree_bound: None, + }); }; // Preparation @@ -317,7 +329,12 @@ impl<F: FftField, H: Hasher> FriProof<F, H> { } if domain_size % N != 0 || degree_bound % N != 0 { - return Err(VerifyError::DegreeTruncation { depth }); + return Err(VerifyError::DegreeTruncation { + depth, + size: domain_size, + degree_bound, + folding_factor: N, + }); } root = root.pow([N as u64]); domain_size /= N; -- GitLab From 5bcbc5752c0aea8e7bcbe2f841eb4a64066cb4d5 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Fri, 20 Sep 2024 09:29:30 +0200 Subject: [PATCH 2/5] add asserts and doc to `to_polynomial` and `to_evaluations` --- src/utils.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 4150646..f5b1dff 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -178,7 +178,9 @@ impl<H: Hasher> MerkleTreeExt for MerkleTree<H> { /// Converts `polynomial` from coefficient form to evaluations over roots of unity. /// -/// `domain_size` must be a power of two and strictly greater than the degree of the polynomial. +/// # Panics +/// - `domain_size` must be a power of two +/// - `domain_size` must be strictly greater than the degree of `polynomial` /// /// # Example /// ``` @@ -206,7 +208,14 @@ impl<H: Hasher> MerkleTreeExt for MerkleTree<H> { pub fn to_evaluations<F: FftField>(mut polynomial: Vec<F>, domain_size: usize) -> Vec<F> { debug_assert!( domain_size.is_power_of_two(), - "Domain size must be a power of two" + "Domain size must be a power of two, found {}", + domain_size, + ); + debug_assert!( + domain_size > polynomial.len() - 1, + "Domain size must be strictly greater than the degree of the polynomial, found |D| = {} and deg(P) = {}", + domain_size, + polynomial.len() - 1, ); let domain = GeneralEvaluationDomain::<F>::new(domain_size).unwrap(); @@ -217,13 +226,20 @@ pub fn to_evaluations<F: FftField>(mut polynomial: Vec<F>, domain_size: usize) - /// Interpolates the coefficient form from the evaluations over the roots of unity. /// This is the counterpart of [`to_evaluations`]. /// -/// `degree_bound` must be strictly greater than the degree of the polynomial. Otherwise, this -/// may either panic or truncate higher degree coefficients. +/// # Panics +/// - the domain size, i.e. the number of `evaluations`, must be a power of two +/// - `degree_bound` must be strictly greater than the degree of `polynomial` +/// +/// > **Note** +/// > +/// > if the degree bound condition is not met, this function may either panic or +/// > truncate higher degree coefficients. #[inline] pub fn to_polynomial<F: FftField>(mut evaluations: Vec<F>, degree_bound: usize) -> Vec<F> { debug_assert!( evaluations.len().is_power_of_two(), - "Domain size must be a power of two" + "Domain size must be a power of two, found {} evaluations", + evaluations.len(), ); let domain = GeneralEvaluationDomain::<F>::new(evaluations.len()).unwrap(); -- GitLab From 7d71a6465cbcb1488f1eb1ad1f3b17f6880067f4 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Fri, 20 Sep 2024 09:41:14 +0200 Subject: [PATCH 3/5] complete doc of `rng` --- src/rng.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/rng.rs b/src/rng.rs index ef4923c..5891bc4 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -23,10 +23,15 @@ pub trait ReseedableRng { /// Draws a pseudo-random number from field `F`. This does not need to be overriden. /// - /// # Panics - /// This panics if this object is not able to draw a random value from this field. + /// > **Note** + /// > + /// > because converting a random sequence of bytes to an element of `F` might fail, e.g. if + /// > the underlying binary representation is bigger than the modulus of `F`, this function + /// > uses rejection sampling and might have to resample random bytes until they fit in `F`. + /// > + /// > however, because the size of `F` will likely be very large, the probability of + /// > [`draw_alpha`] getting stuck for a long time is very slim. fn draw_alpha<F: Field>(&mut self) -> F { - // This has never failed during tests, but this should be tested with other fields. loop { if let Some(alpha) = self.next_bytes(|bytes| F::from_random_bytes(bytes)) { return alpha; @@ -37,12 +42,14 @@ pub trait ReseedableRng { /// Draws a [`Vec`] of `count` positions, each of them being strictly less than `domain_size`. /// This does not need to be overriden. /// - /// `domain_size` must be a power of two; otherwise, the result is unspecified - /// (the implementation may either return incorrect positions or panic). + /// # Panics + /// - `domain_size` must be a power of two (otherwise, the result is unspecified and the + /// implementation may either return incorrect positions or panic). fn draw_positions(&mut self, count: usize, domain_size: usize) -> Vec<usize> { debug_assert!( domain_size.is_power_of_two(), - "Domain size must be a power of two" + "Domain size must be a power of two, found {}", + domain_size, ); let mask = domain_size - 1; -- GitLab From 44f700561d4fccf52b046dbe4bc9c1becee6ea9e Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Fri, 20 Sep 2024 09:55:24 +0200 Subject: [PATCH 4/5] fix doc typo --- src/rng.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rng.rs b/src/rng.rs index 5891bc4..45876c3 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -30,7 +30,7 @@ pub trait ReseedableRng { /// > uses rejection sampling and might have to resample random bytes until they fit in `F`. /// > /// > however, because the size of `F` will likely be very large, the probability of - /// > [`draw_alpha`] getting stuck for a long time is very slim. + /// > getting stuck for a long time is very slim. fn draw_alpha<F: Field>(&mut self) -> F { loop { if let Some(alpha) = self.next_bytes(|bytes| F::from_random_bytes(bytes)) { -- GitLab From c21fee4444728156fc575285bc3353b4fede3179 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Fri, 20 Sep 2024 11:28:31 +0200 Subject: [PATCH 5/5] add missing panics doc --- src/commit.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commit.rs b/src/commit.rs index 750f1de..7f46fa6 100644 --- a/src/commit.rs +++ b/src/commit.rs @@ -53,7 +53,8 @@ impl<const N: usize, F: FftField, H: Hasher> FriCommitments<N, F, H> { /// See [`crate::commit_polynomial`] for information about the other parameters. /// /// # Panics - /// This may either panic or have unspecified behaviour if `remainder_degree_plus_one` is inconsistent with + /// - `N` must be a power of 2 + /// - This may either panic or have unspecified behaviour if `remainder_degree_plus_one` is inconsistent with /// the degree-bound of the polynomial and the folding factor, or if `F` does not contain a subgroup of size /// `evaluations.len()`. pub fn new<R>( -- GitLab