raptor_code/
encoder.rs

1use alloc::vec::Vec;
2
3use crate::partition::Partition;
4use crate::{common, raptor};
5
6/// A struct that represents a source block encoder that uses Raptor codes.
7pub struct SourceBlockEncoder {
8    intermediate: Vec<Vec<u8>>,
9    k: u32,
10    l: u32,
11    l_prime: u32,
12}
13
14impl SourceBlockEncoder {
15    /// Create a source block encoder, passing the list of source symbols
16    ///
17    /// # Parameters
18    ///
19    /// * `source_block`: A slice of vectors containing the source symbols.
20    /// * `max_source_symbols`: Max number of source symbols inside the source
21    ///   block
22    ///
23    /// # Returns
24    ///
25    /// A new `SourceBlockEncoder` instance.
26    pub fn new(source_block: &[u8], max_source_symbols: usize) -> Self {
27        let partition = Partition::new(source_block.len(), max_source_symbols);
28        let source_block = partition.create_source_block(source_block);
29        let k = source_block.len() as u32;
30        let mut raptor = raptor::Raptor::new(k);
31        raptor.add_encoding_symbols(&source_block);
32        raptor.reduce();
33
34        SourceBlockEncoder {
35            intermediate: raptor.intermediate_symbols().to_vec(),
36            k,
37            l: raptor.get_l(),
38            l_prime: raptor.get_l_prime(),
39        }
40    }
41
42    /// Return the number of source symbols (k) inside the block
43    pub fn nb_source_symbols(&self) -> u32 {
44        self.k
45    }
46
47    /// Generates an encoding symbol with the specified Encoding Symbol
48    /// Identifier (ESI).
49    ///
50    /// This method generates a encoding symbol using the Raptor code and the
51    /// intermediate symbols generated during the initialization of the encoder.
52    ///
53    /// # Parameters
54    ///
55    /// * `esi`: The Encoding Symbol Identifier (ESI) of the desired encoding
56    ///   symbol.
57    ///
58    /// # Returns
59    ///
60    /// A tuple containing:
61    /// * `Vec<u8>` : The generated encoding symbol
62    pub fn fountain(&mut self, esi: u32) -> Vec<u8> {
63        let mut block = Vec::new();
64        let indices = common::find_lt_indices(self.k, esi, self.l, self.l_prime);
65        for indice in indices {
66            if indice < self.intermediate.len() as u32 {
67                common::xor(&mut block, &self.intermediate[indice as usize]);
68            }
69        }
70
71        block
72    }
73}
74
75/// Encodes a source block into encoding symbols using Raptor codes.
76///
77/// # Parameters
78///
79/// * `source_block`: A slice of vectors containing the source symbols.
80/// * `max_source_symbols`: Max number of source symbols inside the source block
81/// * `nb_repair`: The number of repair symbols to be generated.
82///
83/// # Returns
84///
85/// a Tuple
86/// * `Vec<Vec<u8>>` : A vector of vectors of bytes representing the encoding
87///   symbols (source symbols + repair symbol).
88/// * `u32` : Number of source symbols (k)
89///
90///
91/// The function uses Raptor codes to generate the specified number of repair
92/// symbols from the source block.
93pub fn encode_source_block(
94    source_block: &[u8],
95    max_source_symbols: usize,
96    nb_repair: usize,
97) -> (Vec<Vec<u8>>, u32) {
98    let mut encoder = SourceBlockEncoder::new(source_block, max_source_symbols);
99    let mut output: Vec<Vec<u8>> = Vec::new();
100    let n = encoder.nb_source_symbols() as usize + nb_repair;
101    for esi in 0..n as u32 {
102        output.push(encoder.fountain(esi));
103    }
104    (output, encoder.nb_source_symbols())
105}
106
107#[cfg(test)]
108mod tests {
109    use alloc::vec;
110    use alloc::vec::Vec;
111
112    #[test]
113    fn test_source_block_encoder() {
114        crate::tests::init();
115
116        let input: Vec<u8> = vec![1, 2, 7, 4, 0, 2, 54, 4, 1, 1, 10, 200, 1, 21, 3, 80];
117        let max_source_symbols = 4;
118        let nb_repair = 3;
119
120        let (encoded_block, k) = super::encode_source_block(&input, max_source_symbols, nb_repair);
121        log::debug!("Encoded with {} blocks", k);
122
123        // Try to decode the source block
124
125        let mut encoded_block: Vec<Option<Vec<u8>>> = encoded_block
126            .into_iter()
127            .map(|symbols| Some(symbols))
128            .collect();
129
130        // Simulate loss
131        encoded_block[0] = None;
132        encoded_block[1] = None;
133
134        let output =
135            crate::decoder::decode_source_block(&encoded_block, k as usize, input.len()).unwrap();
136        log::debug!("{:?} / {:?}", output, input);
137        assert!(output.len() == input.len());
138        assert!(output == input);
139    }
140}