From 447e447377fe473aa1dc3e11a4df6f0f36851724 Mon Sep 17 00:00:00 2001
From: STEVAN Antoine <antoine.stevan@isae-supaero.fr>
Date: Fri, 7 Jun 2024 10:54:21 +0000
Subject: [PATCH] add "long full recoding" test (dragoon/komodo!147)

this will
- recode for $\#steps \in [10, 20, 100]$
- at $t = 0$, $k$ random shards among the $n$ encoded will be selected at random
- at $t \geq 1$, all $k$ shards will be used to recode $k$ brand new shards
- make sure the last set of $k$ shards recoded $\#steps$ together can decode the data

## example with $(k, n) = (3, 5)$ and $\#steps = 3$
- $(s_i)_{1 \leq i \leq k}$ are the $k$ source shards
- $(e_j)_{1 \leq j \leq n}$ are the $n$ encoded shards
- $(m_i)_{1 \leq i \leq k}$ are the $k$ randomly selected shards
- $(n_i)_{1 \leq i \leq k}$ are the shards after step $1$
- $(o_i)_{1 \leq i \leq k}$ are the shards after step $2$
- $(p_i)_{1 \leq i \leq k}$ are the shards after step $3$
- the $(p_i)_{1 \leq i \leq k}$ will be used for decoding

```mermaid
graph TD;

    s1 --> e1; s1 --> e2; s1 --> e3; s1 --> e4; s1 --> e5;
    s2 --> e1; s2 --> e2; s2 --> e3; s2 --> e4; s2 --> e5;
    s3 --> e1; s3 --> e2; s3 --> e3; s3 --> e4; s3 --> e5;

    e1 --> m1;
    e3 --> m2;
    e4 --> m3;

    m1 --> n1; m1 --> n2; m1 --> n3;
    m2 --> n1; m2 --> n2; m2 --> n3;
    m3 --> n1; m3 --> n2; m3 --> n3;

    n1 --> o1; n1 --> o2; n1 --> o3;
    n2 --> o1; n2 --> o2; n2 --> o3;
    n3 --> o1; n3 --> o2; n3 --> o3;

    o1 --> p1; o1 --> p2; o1 --> p3;
    o2 --> p1; o2 --> p2; o2 --> p3;
    o3 --> p1; o3 --> p2; o3 --> p3;
```
---
 src/fec.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/src/fec.rs b/src/fec.rs
index a1fd2da6..cbbae67b 100644
--- a/src/fec.rs
+++ b/src/fec.rs
@@ -206,6 +206,7 @@ mod tests {
     };
 
     use itertools::Itertools;
+    use rand::seq::SliceRandom;
 
     use super::recode_with_coeffs;
 
@@ -441,6 +442,49 @@ mod tests {
         }
     }
 
+    //   (encode) | (select k) |     (recode)    | (decode)
+    //            *
+    // *          *            *     * ... *     * \
+    // *  ------> * ---------> * --> * ... * --> *  |--> ?
+    // *          *            *     * ... *     * /
+    //            *                  \__(#steps)_/
+    //
+    // k          n            k     k     k     k
+    fn long_full_end_to_end_with_recoding_template<F: PrimeField>(
+        data: &[u8],
+        k: usize,
+        n: usize,
+        nb_steps: usize,
+    ) {
+        let mut rng = ark_std::test_rng();
+        let test_case = format!("TEST | data: {} bytes, k: {}, n: {}", data.len(), k, n,);
+
+        let mut shards = encode::<F>(data, &Matrix::random(k, n, &mut rng))
+            .unwrap_or_else(|_| panic!("could not encode {test_case}"));
+        shards.shuffle(&mut rng);
+        shards.truncate(k);
+
+        for _ in 0..nb_steps {
+            shards = (0..k)
+                .map(|_| recode_random(&shards, &mut rng).unwrap().unwrap())
+                .collect();
+        }
+
+        let actual = decode::<F>(shards).unwrap_or_else(|_| panic!("could not decode {test_case}"));
+        assert_eq!(data, actual, "bad decoded data with {test_case}",);
+    }
+
+    #[test]
+    fn long_full_end_to_end_with_recoding() {
+        let bytes = bytes();
+
+        for (k, n) in [(3, 5), (5, 5), (8, 10)] {
+            for nb_steps in [10, 20, 100] {
+                long_full_end_to_end_with_recoding_template::<Fr>(&bytes, k, n, nb_steps);
+            }
+        }
+    }
+
     fn create_fake_shard<F: PrimeField>(linear_combination: &[F], bytes: &[u8]) -> Shard<F> {
         Shard {
             k: 2,
-- 
GitLab