From 010fcff5e28e85071ca9804f9726bbc5ed969fa9 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 16:37:55 +0100 Subject: [PATCH 01/15] more algebra tests --- src/algebra/mod.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/algebra/mod.rs b/src/algebra/mod.rs index 5a70b156..3ddf0219 100644 --- a/src/algebra/mod.rs +++ b/src/algebra/mod.rs @@ -246,13 +246,11 @@ mod tests { split_data_template::<Fr>(&[], 1, None); split_data_template::<Fr>(&[], 8, None); - let nb_bytes = 11 * (Fr::MODULUS_BIT_SIZE as usize / 8); - split_data_template::<Fr>(&bytes()[..nb_bytes], 1, Some(11)); - split_data_template::<Fr>(&bytes()[..nb_bytes], 8, Some(16)); - - let nb_bytes = 11 * (Fr::MODULUS_BIT_SIZE as usize / 8) - 10; - split_data_template::<Fr>(&bytes()[..nb_bytes], 1, Some(11)); - split_data_template::<Fr>(&bytes()[..nb_bytes], 8, Some(16)); + const MODULUS_BYTE_SIZE: usize = Fr::MODULUS_BIT_SIZE as usize / 8; + for n in (10 * MODULUS_BYTE_SIZE + 1)..(11 * MODULUS_BYTE_SIZE) { + split_data_template::<Fr>(&bytes()[..n], 1, Some(11)); + split_data_template::<Fr>(&bytes()[..n], 8, Some(16)); + } } fn split_and_merge_template<F: PrimeField>(bytes: &[u8], modulus: usize) { @@ -264,10 +262,9 @@ mod tests { #[test] fn split_and_merge() { - split_and_merge_template::<Fr>(&bytes(), 1); - split_and_merge_template::<Fr>(&bytes(), 8); - split_and_merge_template::<Fr>(&bytes(), 64); - split_and_merge_template::<Fr>(&bytes(), 4096); + for i in 0..12 { + split_and_merge_template::<Fr>(&bytes(), 1 << i); + } } #[cfg(any(feature = "kzg", feature = "aplonk"))] -- GitLab From e9741b5648ac39eb3414bdf9c9858938ef6de6d6 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 16:54:28 +0100 Subject: [PATCH 02/15] fix some typos in algebra::linalg --- src/algebra/linalg.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/algebra/linalg.rs b/src/algebra/linalg.rs index 5e6d6275..5293b2c2 100644 --- a/src/algebra/linalg.rs +++ b/src/algebra/linalg.rs @@ -10,7 +10,7 @@ use crate::error::KomodoError; /// a matrix defined over a finite field /// -/// internally, a matrix is just a vector of field elements that whose length is +/// internally, a matrix is just a vector of field elements whose length is /// exactly the width times the height and where elements are organized row by /// row. #[derive(Clone, PartialEq, Default, Debug, CanonicalSerialize, CanonicalDeserialize)] @@ -24,7 +24,7 @@ impl<T: Field> Matrix<T> { /// build a matrix from a diagonal of elements /// /// # Example - /// building a diagonal matrix from the diagonal $[1, 2, 3, 4]$ will give + /// building a diagonal matrix from the diagonal `[1, 2, 3, 4]` would give /// ```text /// [ /// [1, 0, 0, 0], @@ -66,12 +66,13 @@ impl<T: Field> Matrix<T> { /// build a Vandermonde matrix for some seed points /// - /// actually, this is the tranpose of the Vandermonde matrix defined in the + /// actually, this is the transpose of the Vandermonde matrix defined in the /// [Wikipedia article][article], i.e. there are as many columns as there /// are seed points and there are as many rows as there are powers of the /// seed points. /// - /// > **Note** + /// > **Note** + /// > /// > if you are sure the points are distinct and don't want to perform any /// > runtime check to ensure that condition, have a look at /// > [`Self::vandermonde_unchecked`]. @@ -153,7 +154,8 @@ impl<T: Field> Matrix<T> { /// build a matrix from a "_matrix_" of elements /// - /// > **Note** + /// > **Note** + /// > /// > if you are sure each row should have the same length and don't want to /// > perform any runtime check to ensure that condition, have a look at /// > [`Self::from_vec_vec_unchecked`]. @@ -249,6 +251,7 @@ impl<T: Field> Matrix<T> { /// extract a single column from the matrix /// /// > **Note** + /// > /// > returns `None` if the provided index is out of bounds pub(crate) fn get_col(&self, j: usize) -> Option<Vec<T>> { if j >= self.width { @@ -258,14 +261,14 @@ impl<T: Field> Matrix<T> { Some((0..self.height).map(|i| self.get(i, j)).collect()) } - // compute _row / value_ + /// compute _row = row / value_ fn divide_row_by(&mut self, row: usize, value: T) { for j in 0..self.width { self.set(row, j, self.get(row, j) / value); } } - // compute _destination = destination + source * value_ + /// compute _destination = destination + source * value_ fn multiply_row_by_and_add_to_row(&mut self, source: usize, value: T, destination: usize) { for j in 0..self.width { self.set( @@ -278,7 +281,8 @@ impl<T: Field> Matrix<T> { /// compute the inverse of the matrix /// - /// > **None** + /// > **Note** + /// > /// > the matrix should be /// > - square /// > - invertible @@ -314,6 +318,7 @@ impl<T: Field> Matrix<T> { /// swap rows `i` and `j`, inplace /// /// > **Note** + /// > /// > this function assumes both `i` and `j` are in bounds, unexpected /// > results are expected if `i` or `j` are out of bounds. fn swap_rows(&mut self, i: usize, j: usize) { @@ -324,7 +329,8 @@ impl<T: Field> Matrix<T> { /// compute the rank of the matrix /// - /// > **None** + /// > **Note** + /// > /// > see the [_Wikipedia article_](https://en.wikipedia.org/wiki/Rank_(linear_algebra)) /// > for more information /// > @@ -373,10 +379,11 @@ impl<T: Field> Matrix<T> { /// compute the matrix multiplication with another matrix /// - /// if `mat` represents a matrix $A$ and `rhs` is the representation of - /// another matrix $B$, then `mat.mul(rhs)` will compute $A \times B$ + /// if `lhs` represents a matrix $A$ and `rhs` is the representation of + /// another matrix $B$, then `lhs.mul(rhs)` will compute $A \times B$ /// /// > **Note** + /// > /// > both matrices should have compatible shapes, i.e. if `self` has shape /// > `(n, m)` and `rhs` has shape `(p, q)`, then `m == p`. pub fn mul(&self, rhs: &Self) -> Result<Self, KomodoError> { @@ -412,6 +419,7 @@ impl<T: Field> Matrix<T> { /// compute the transpose of the matrix /// /// > **Note** + /// > /// > see the [_Wikipedia article_](https://en.wikipedia.org/wiki/Transpose) pub fn transpose(&self) -> Self { let height = self.width; -- GitLab From 5daab7086175d205338ef74c69659f49f28ff528 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 16:56:22 +0100 Subject: [PATCH 03/15] fix typo in errors --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index dbcf8e49..a3f2b662 100644 --- a/src/error.rs +++ b/src/error.rs @@ -42,7 +42,7 @@ pub enum KomodoError { #[error("Degree is zero")] DegreeIsZero, /// `{0}` is the supported degree of the trusted setup and `{1}` is the actual requested - /// polynomnial degree + /// polynomial degree #[error("too many coefficients: max is {0}, found {0}")] TooFewPowersInTrustedSetup(usize, usize), /// `{0}` is a custom error message. -- GitLab From f85b9bf5e0e88648a6806d0174e092cce312b362 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 16:57:27 +0100 Subject: [PATCH 04/15] link to module --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index a3f2b662..cec1afd2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ //! Komodo-specific errors //! -//! there are a few linear algebra errors and some related to ZK. +//! there are a few linear algebra errors and some related to [crate::zk]. use thiserror::Error; /// An error that Komodo could end up producing. -- GitLab From 3a293a6ac6a27689bee7cf5479c1912f26cbbf7a Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 16:58:55 +0100 Subject: [PATCH 05/15] typo in main doc --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c4c0690e..abc68e21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! > modules marked with an `*`, e.g. [`kzg`]*, are hidden behind a _Cargo_ feature with the same //! > name //! -//! Other submodules define several fundamental building blocks to Komodo, but which are not +//! Other submodules define several fundamental building blocks to Komodo, but are not //! mandatory to explore to understand the protocols. //! //! # Example -- GitLab From e5029917d1ba04390aa760acde03578f984d8cac Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Mon, 27 Jan 2025 17:12:52 +0100 Subject: [PATCH 06/15] minor --- src/fec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fec.rs b/src/fec.rs index 0d6383b8..2329a21e 100644 --- a/src/fec.rs +++ b/src/fec.rs @@ -8,7 +8,7 @@ use rs_merkle::{algorithms::Sha256, Hasher}; use crate::{algebra, algebra::linalg::Matrix, error::KomodoError}; -/// representation of a FEC shard of data. +/// representation of a [FEC](https://en.wikipedia.org/wiki/Error_correction_code) shard of data. #[derive(Debug, Default, Clone, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Shard<F: PrimeField> { /// the code parameter, required to decode @@ -57,7 +57,7 @@ impl<F: PrimeField> Shard<F> { .iter() .zip(other.data.iter()) .map(|(es, eo)| es.mul(alpha) + eo.mul(beta)) - .collect::<Vec<_>>(), + .collect(), size: self.size, } } @@ -248,7 +248,7 @@ mod tests { /// `contains_one_of(x, set)` is true iif `x` fully contains one of the lists from `set` /// - /// > **Note** + /// > **Note** /// > /// > see [`containment`] for some example fn contains_one_of(x: &[usize], set: &[Vec<usize>]) -> bool { -- GitLab From ecd3f268c3fb6751386a74d28bba0b73e962981d Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 09:43:36 +0100 Subject: [PATCH 07/15] add assert for Semi-AVID tests --- src/semi_avid.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index fa844ed7..d42410ac 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -418,6 +418,12 @@ mod tests { let powers = setup::<F, G>(bytes.len(), rng)?; let blocks = full!(bytes, powers, encoding_mat); + assert!( + blocks.len() >= 6, + "not enough blocks, expected {}, found {}", + 6, + blocks.len() + ); assert!(verify( &recode(&blocks[2..=3], rng).unwrap().unwrap(), @@ -471,6 +477,12 @@ mod tests { let powers = setup::<F, G>(bytes.len(), rng)?; let blocks = full!(bytes, powers, encoding_mat); + assert!( + blocks.len() >= 5, + "not enough blocks, expected {}, found {}", + 5, + blocks.len() + ); let b_0_1 = recode(&blocks[0..=1], rng).unwrap().unwrap(); let shards = vec![ -- GitLab From ca90764b5093373e7b3f33b9a6d684c2a34e3df9 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 09:55:48 +0100 Subject: [PATCH 08/15] pass recodings and compute number of shards --- src/semi_avid.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index d42410ac..8c57729d 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -406,6 +406,7 @@ mod tests { fn verify_recoding_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, + recodings: Vec<Vec<usize>>, ) -> Result<(), KomodoError> where F: PrimeField, @@ -418,23 +419,28 @@ mod tests { let powers = setup::<F, G>(bytes.len(), rng)?; let blocks = full!(bytes, powers, encoding_mat); + + let min_nb_blocks = recodings.clone().into_iter().flatten().max().unwrap() + 1; assert!( - blocks.len() >= 6, + blocks.len() >= min_nb_blocks, "not enough blocks, expected {}, found {}", - 6, + min_nb_blocks, blocks.len() ); - assert!(verify( - &recode(&blocks[2..=3], rng).unwrap().unwrap(), - &powers - )?); - assert!(verify( - &recode(&[blocks[3].clone(), blocks[5].clone()], rng) + for bs in recodings { + assert!(verify( + &recode( + &bs.iter() + .map(|&i| blocks[i as usize].clone()) + .collect::<Vec<_>>(), + rng + ) .unwrap() .unwrap(), - &powers - )?); + &powers + )?); + } Ok(()) } @@ -568,9 +574,13 @@ mod tests { #[test] fn verify_recoding() { - run_template::<Fr, DensePolynomial<Fr>, _>( - verify_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>, - ); + run_template::<Fr, DensePolynomial<Fr>, _>(|b, m| { + verify_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>( + b, + m, + vec![vec![2, 3], vec![3, 5]], + ) + }); } #[test] -- GitLab From ff37eab62f736d5e11c4d5905b7a690007db0012 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 09:56:03 +0100 Subject: [PATCH 09/15] pass k and n as parameters to `run_template` --- src/semi_avid.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index 8c57729d..39de56c1 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -526,7 +526,7 @@ mod tests { // NOTE: this is part of an experiment, to be honest, to be able to see how // much these tests could be refactored and simplified - fn run_template<F, P, Fun>(test: Fun) + fn run_template<F, P, Fun>(k: usize, n: usize, test: Fun) where F: PrimeField, Fun: Fn(&[u8], &Matrix<F>) -> Result<(), KomodoError>, @@ -535,8 +535,6 @@ mod tests { { let mut rng = ark_std::test_rng(); - let (k, n) = (3, 6_usize); - let bytes = bytes(); let test_case = format!("TEST | data: {} bytes, k: {}, n: {}", bytes.len(), k, n); @@ -561,6 +559,8 @@ mod tests { #[test] fn verification() { run_template::<Fr, DensePolynomial<Fr>, _>( + 3, + 6, verify_template::<Fr, G1Projective, DensePolynomial<Fr>>, ); } @@ -568,13 +568,15 @@ mod tests { #[test] fn verify_with_errors() { run_template::<Fr, DensePolynomial<Fr>, _>( + 3, + 6, verify_with_errors_template::<Fr, G1Projective, DensePolynomial<Fr>>, ); } #[test] fn verify_recoding() { - run_template::<Fr, DensePolynomial<Fr>, _>(|b, m| { + run_template::<Fr, DensePolynomial<Fr>, _>(3, 6, |b, m| { verify_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>( b, m, @@ -586,6 +588,8 @@ mod tests { #[test] fn end_to_end() { run_template::<Fr, DensePolynomial<Fr>, _>( + 3, + 6, end_to_end_template::<Fr, G1Projective, DensePolynomial<Fr>>, ); } @@ -593,6 +597,8 @@ mod tests { #[test] fn end_to_end_with_recoding() { run_template::<Fr, DensePolynomial<Fr>, _>( + 3, + 6, end_to_end_with_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>, ); } -- GitLab From 42224b844cc5bde3568b6f0812f2b178ec33a093 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 10:00:49 +0100 Subject: [PATCH 10/15] refactor attack --- src/semi_avid.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index 39de56c1..6254024f 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -339,7 +339,7 @@ mod tests { zk::{setup, Commitment}, }; - use super::{build, prove, recode, verify}; + use super::{build, prove, recode, verify, Block}; fn bytes() -> Vec<u8> { include_bytes!("../assets/dragoon_133x133.png").to_vec() @@ -371,6 +371,21 @@ mod tests { Ok(()) } + fn attack<F, G>(block: Block<F, G>, c: usize, base: u128, pow: u64) -> Block<F, G> + where + F: PrimeField, + G: CurveGroup<ScalarField = F>, + { + let mut block = block; + // modify a field in the struct b to corrupt the block proof without corrupting the data serialization + let a = F::from_le_bytes_mod_order(&base.to_le_bytes()); + let mut commits: Vec<G> = block.proof.iter().map(|c| c.0.into()).collect(); + commits[c] = commits[c].mul(a.pow([pow])); + block.proof = commits.iter().map(|&c| Commitment(c.into())).collect(); + + return block; + } + fn verify_with_errors_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, @@ -391,14 +406,10 @@ mod tests { assert!(verify(block, &powers)?); } - let mut corrupted_block = blocks[0].clone(); - // modify a field in the struct b to corrupt the block proof without corrupting the data serialization - let a = F::from_le_bytes_mod_order(&123u128.to_le_bytes()); - let mut commits: Vec<G> = corrupted_block.proof.iter().map(|c| c.0.into()).collect(); - commits[0] = commits[0].mul(a.pow([4321_u64])); - corrupted_block.proof = commits.iter().map(|&c| Commitment(c.into())).collect(); - - assert!(!verify(&corrupted_block, &powers)?); + assert!(!verify( + &attack(blocks[0].clone(), 0, 123u128, 4321u64), + &powers + )?); Ok(()) } -- GitLab From 10423338c9083fdce7e36674b30ae9477631d411 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 10:04:17 +0100 Subject: [PATCH 11/15] refactor attacks --- src/semi_avid.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index 6254024f..133ab570 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -389,6 +389,7 @@ mod tests { fn verify_with_errors_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, + attacks: Vec<(usize, usize, u128, u64)>, ) -> Result<(), KomodoError> where F: PrimeField, @@ -406,10 +407,9 @@ mod tests { assert!(verify(block, &powers)?); } - assert!(!verify( - &attack(blocks[0].clone(), 0, 123u128, 4321u64), - &powers - )?); + for (b, c, base, pow) in attacks { + assert!(!verify(&attack(blocks[b].clone(), c, base, pow), &powers)?); + } Ok(()) } @@ -578,11 +578,13 @@ mod tests { #[test] fn verify_with_errors() { - run_template::<Fr, DensePolynomial<Fr>, _>( - 3, - 6, - verify_with_errors_template::<Fr, G1Projective, DensePolynomial<Fr>>, - ); + run_template::<Fr, DensePolynomial<Fr>, _>(3, 6, |b, m| { + verify_with_errors_template::<Fr, G1Projective, DensePolynomial<Fr>>( + b, + m, + vec![(0, 0, 123u128, 4321u64)], + ) + }); } #[test] -- GitLab From 2c83a11ea84b8531077828af9b075f46eff9b26f Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 10:25:09 +0100 Subject: [PATCH 12/15] refactor last tests --- src/semi_avid.rs | 102 ++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 37 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index 133ab570..53701022 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -482,6 +482,7 @@ mod tests { fn end_to_end_with_recoding_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, + recodings: Vec<(Vec<Vec<usize>>, bool)>, ) -> Result<(), KomodoError> where F: PrimeField, @@ -491,46 +492,66 @@ mod tests { { let rng = &mut test_rng(); + let max_k = recodings.iter().map(|(rs, _)| rs.len()).min().unwrap(); + assert!( + encoding_mat.height <= max_k, + "too many source shards, expected at most {}, found {}", + max_k, + encoding_mat.height + ); + let powers = setup::<F, G>(bytes.len(), rng)?; let blocks = full!(bytes, powers, encoding_mat); + + let min_n = recodings + .iter() + .map(|(rs, _)| rs.iter().flatten()) + .flatten() + .max() + .unwrap() + + 1; assert!( - blocks.len() >= 5, + blocks.len() >= min_n, "not enough blocks, expected {}, found {}", - 5, + min_n, blocks.len() ); - let b_0_1 = recode(&blocks[0..=1], rng).unwrap().unwrap(); - let shards = vec![ - b_0_1.shard, - blocks[2].shard.clone(), - blocks[3].shard.clone(), - ]; - assert_eq!(bytes, decode(shards).unwrap()); - - let b_0_1 = recode(&[blocks[0].clone(), blocks[1].clone()], rng) - .unwrap() - .unwrap(); - let shards = vec![ - blocks[0].shard.clone(), - blocks[1].shard.clone(), - b_0_1.shard, - ]; - assert!(decode(shards).is_err()); - - let b_0_1 = recode(&blocks[0..=1], rng).unwrap().unwrap(); - let b_2_3 = recode(&blocks[2..=3], rng).unwrap().unwrap(); - let b_1_4 = recode(&[blocks[1].clone(), blocks[4].clone()], rng) - .unwrap() - .unwrap(); - let shards = vec![b_0_1.shard, b_2_3.shard, b_1_4.shard]; - assert_eq!(bytes, decode(shards).unwrap()); - - let fully_recoded_shards = (0..3) - .map(|_| recode(&blocks[0..=2], rng).unwrap().unwrap().shard) - .collect(); - assert_eq!(bytes, decode(fully_recoded_shards).unwrap()); + for (rs, pass) in recodings { + let recoded_shards = rs + .iter() + .map(|bs| { + if bs.len() == 1 { + blocks[bs[0] as usize].clone().shard + } else { + recode( + &bs.iter() + .map(|&i| blocks[i as usize].clone()) + .collect::<Vec<_>>(), + rng, + ) + .unwrap() + .unwrap() + .shard + } + }) + .collect(); + if pass { + assert_eq!( + bytes, + decode(recoded_shards).unwrap(), + "should decode with {:?}", + rs + ); + } else { + assert!( + decode(recoded_shards).is_err(), + "should not decode with {:?}", + rs + ); + } + } Ok(()) } @@ -609,10 +630,17 @@ mod tests { #[test] fn end_to_end_with_recoding() { - run_template::<Fr, DensePolynomial<Fr>, _>( - 3, - 6, - end_to_end_with_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>, - ); + run_template::<Fr, DensePolynomial<Fr>, _>(3, 6, |b, m| { + end_to_end_with_recoding_template::<Fr, G1Projective, DensePolynomial<Fr>>( + b, + m, + vec![ + (vec![vec![0, 1], vec![2], vec![3]], true), + (vec![vec![0, 1], vec![0], vec![1]], false), + (vec![vec![0, 1], vec![2, 3], vec![1, 4]], true), + (vec![vec![0, 1, 2], vec![0, 1, 2], vec![0, 1, 2]], true), + ], + ) + }); } } -- GitLab From cff80947630ef88e7eb9a856ceb0b38b7ea9f49a Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 10:27:46 +0100 Subject: [PATCH 13/15] refactor "curver name" --- src/semi_avid.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index 53701022..e5b192fe 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -327,6 +327,7 @@ where #[cfg(test)] mod tests { use ark_bls12_381::{Fr, G1Projective}; + const CURVE_NAME: &str = "bls12-381"; use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial}; @@ -572,7 +573,7 @@ mod tests { let test_case = format!("TEST | data: {} bytes, k: {}, n: {}", bytes.len(), k, n); test(&bytes, &Matrix::random(k, n, &mut rng)).unwrap_or_else(|_| { - panic!("verification failed for bls12-381 and random encoding matrix\n{test_case}") + panic!("verification failed for {CURVE_NAME} and random encoding matrix\n{test_case}") }); test( &bytes, @@ -584,7 +585,9 @@ mod tests { ), ) .unwrap_or_else(|_| { - panic!("verification failed for bls12-381 and Vandermonde encoding matrix\n{test_case}") + panic!( + "verification failed for {CURVE_NAME} and Vandermonde encoding matrix\n{test_case}" + ) }); } -- GitLab From f5db76ee61598636bdf7e9491d764d86904b2722 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 10:42:34 +0100 Subject: [PATCH 14/15] make Clippy happy --- src/semi_avid.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index e5b192fe..be7d8154 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -384,7 +384,7 @@ mod tests { commits[c] = commits[c].mul(a.pow([pow])); block.proof = commits.iter().map(|&c| Commitment(c.into())).collect(); - return block; + block } fn verify_with_errors_template<F, G, P>( @@ -443,9 +443,7 @@ mod tests { for bs in recodings { assert!(verify( &recode( - &bs.iter() - .map(|&i| blocks[i as usize].clone()) - .collect::<Vec<_>>(), + &bs.iter().map(|&i| blocks[i].clone()).collect::<Vec<_>>(), rng ) .unwrap() @@ -507,8 +505,7 @@ mod tests { let min_n = recodings .iter() - .map(|(rs, _)| rs.iter().flatten()) - .flatten() + .flat_map(|(rs, _)| rs.iter().flatten()) .max() .unwrap() + 1; @@ -524,12 +521,10 @@ mod tests { .iter() .map(|bs| { if bs.len() == 1 { - blocks[bs[0] as usize].clone().shard + blocks[bs[0]].clone().shard } else { recode( - &bs.iter() - .map(|&i| blocks[i as usize].clone()) - .collect::<Vec<_>>(), + &bs.iter().map(|&i| blocks[i].clone()).collect::<Vec<_>>(), rng, ) .unwrap() -- GitLab From 93e36c271ef2e55314c4159447571b11daa30716 Mon Sep 17 00:00:00 2001 From: "a.stevan" <antoine.stevan@isae-supaero.fr> Date: Tue, 28 Jan 2025 11:34:25 +0100 Subject: [PATCH 15/15] add small docs to test functions --- src/semi_avid.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/semi_avid.rs b/src/semi_avid.rs index be7d8154..59638ed8 100644 --- a/src/semi_avid.rs +++ b/src/semi_avid.rs @@ -352,6 +352,7 @@ mod tests { }; } + /// verify all `n` blocks fn verify_template<F, G, P>(bytes: &[u8], encoding_mat: &Matrix<F>) -> Result<(), KomodoError> where F: PrimeField, @@ -372,6 +373,7 @@ mod tests { Ok(()) } + /// attack a block by alterring one part of its proof fn attack<F, G>(block: Block<F, G>, c: usize, base: u128, pow: u64) -> Block<F, G> where F: PrimeField, @@ -387,6 +389,7 @@ mod tests { block } + /// verify all `n` blocks and then make sure an attacked block does not verify fn verify_with_errors_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, @@ -415,6 +418,7 @@ mod tests { Ok(()) } + /// make sure recoded blocks still verify correctly fn verify_recoding_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, @@ -455,6 +459,7 @@ mod tests { Ok(()) } + /// encode and decode with all `n` shards fn end_to_end_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, @@ -478,6 +483,7 @@ mod tests { Ok(()) } + /// encode and try to decode with recoded shards fn end_to_end_with_recoding_template<F, G, P>( bytes: &[u8], encoding_mat: &Matrix<F>, @@ -552,8 +558,10 @@ mod tests { Ok(()) } - // NOTE: this is part of an experiment, to be honest, to be able to see how - // much these tests could be refactored and simplified + /// run the `test` with a _(k, n)_ encoding and on both a random and a Vandermonde encoding + /// + /// NOTE: this is part of an experiment, to be honest, to be able to see how + /// much these tests could be refactored and simplified fn run_template<F, P, Fun>(k: usize, n: usize, test: Fun) where F: PrimeField, -- GitLab