rsmt2d_rs/
data_square.rs

1use std::vec;
2
3use crate::{
4    codec::{self, Codec},
5    Matrix2D, Matrix3D,
6};
7use eyre::{eyre, Result};
8
9/// Store all data for an original data square (ODS) or extended data square (EDS).
10/// Data is duplicated in both row-major and column-major order in order to be able to provide zero-allocation column slices.
11pub struct DataSquare {
12    pub square_row: Matrix3D,
13    pub square_col: Matrix3D,
14    pub width: usize,
15    pub original_width: usize,
16    pub chunk_size: usize,
17    pub row_roots: Matrix2D,
18    pub col_roots: Matrix2D,
19    pub codec: Box<dyn Codec>,
20}
21
22impl DataSquare {
23    /// Create a new data square.
24    /// Data must be a square matrix.
25    /// Data must not be empty.
26    ///
27    /// # Arguments
28    ///
29    /// * `original_data` - Original data.
30    /// * `merkle_tree` - `MerkleTree`.
31    ///
32    /// # Returns
33    ///
34    /// * `DataSquare` - Data square.
35    /// * `Result` - Error.
36    pub fn new(original_data: Matrix2D) -> Result<Self> {
37        // Check that data is not empty.
38        if original_data.is_empty() {
39            return Err(eyre!("Data must not be empty."));
40        }
41
42        // Check that data is a square matrix.
43        let data_len = f64::from(original_data.len() as u32);
44        let width = data_len.sqrt();
45        if width * width != data_len {
46            return Err(eyre!("Number of chunks must be a square number."));
47        }
48        let width: usize = width as usize;
49
50        // Check that chunks are all the same size.
51        let chunk_size = original_data[0].len();
52        for row in original_data.iter() {
53            if row.len() != chunk_size {
54                return Err(eyre!("All chunks must be of equal size."));
55            }
56        }
57
58        // Create row-major data squares.
59        let mut square_row: Matrix3D = vec![vec![]; width];
60        for i in 0..width {
61            square_row[i] = original_data[i * width..i * width + width].to_vec();
62        }
63
64        // Create column-major data squares.
65        let mut square_col: Matrix3D = vec![vec![]; width];
66        for j in 0..width {
67            for i in 0..width {
68                square_col[j].push(original_data[i * width + j].to_vec());
69            }
70        }
71
72        let codec = codec::new(original_data.len())?;
73
74        Ok(Self {
75            square_row,
76            square_col,
77            width,
78            original_width: width,
79            chunk_size,
80            row_roots: vec![],
81            col_roots: vec![],
82            codec,
83        })
84    }
85
86    /// Extend original square horizontally and vertically
87    ///  ------- -------
88    /// |       |       |
89    /// |   O → |   E   |
90    /// |   ↓   |       |
91    ///  ------- -------
92    /// |       |
93    /// |   E   |
94    /// |       |
95    ///  -------
96    pub fn erasure_extend_square(&mut self) -> Result<()> {
97        self.original_width = self.width;
98        // Extend data square.
99        self.extend_square()?;
100
101        for i in 0..self.original_width {
102            // Extend horizontally with Reed Solomon encoding.
103            self.erasure_extend_row(i)?;
104            // Extend vertically with Reed Solomon encoding.
105            self.erasure_extend_col(i)?;
106        }
107
108        Ok(())
109    }
110
111    /// Extend original square horizontally and vertically
112    ///
113    /// # Returns
114    /// * `Result` - Error.
115    fn extend_square(&mut self) -> Result<()> {
116        self.width *= 2;
117        let filler_chunk = vec![Default::default(); self.chunk_size];
118        let mut filler_row: Vec<Vec<u8>> = vec![];
119        for _ in 0..self.width {
120            filler_row.push(filler_chunk.clone());
121        }
122        // Extend rows.
123        for row in self.square_row.iter_mut() {
124            for _ in 0..self.original_width {
125                row.push(filler_chunk.clone());
126            }
127        }
128
129        for i in self.original_width..self.width {
130            self.square_row.insert(i, filler_row.clone());
131        }
132        // Extend cols.
133        self.square_col = vec![vec![]; self.width];
134        for (j, col) in self.square_col.iter_mut().enumerate().take(self.width) {
135            for i in 0..self.width {
136                col.push(self.square_row[i][j].to_vec());
137            }
138        }
139
140        Ok(())
141    }
142
143    /// Encode a given row.
144    ///
145    /// # Arguments
146    ///
147    /// * `row_index` - The row index.
148    ///
149    /// # Returns
150    ///
151    /// * `()` - Unit.
152    /// * `Result` - Error.
153    fn erasure_extend_row(&mut self, row_index: usize) -> Result<()> {
154        // Create a new codec.
155        // TODO: implement cache for codec.
156        let codec = codec::new(self.original_width)?;
157        // Apply Reed-Solomon encoding.
158        let shares = self.square_row[row_index][0..self.original_width].to_vec();
159        let encoded_shares = codec.encode(shares)?;
160        // Save encoded row in square row.
161        for (i, share) in encoded_shares.iter().enumerate() {
162            self.square_row[row_index][self.original_width + i] = share.clone();
163            self.square_col[self.original_width + i][row_index] = share.clone();
164        }
165        Ok(())
166    }
167
168    /// Encode a given col.
169    ///
170    /// # Arguments
171    ///
172    /// * `i` - The col index.
173    ///
174    /// # Returns
175    ///
176    /// * `()` - Unit.
177    /// * `Result` - Error.
178    fn erasure_extend_col(&mut self, col_index: usize) -> Result<()> {
179        // Create a new codec.
180        // TODO: implement cache for codec.
181        let codec = codec::new(self.original_width)?;
182        // Apply Reed-Solomon encoding.
183        let shares = self.square_col[col_index][0..self.original_width].to_vec();
184
185        let encoded_shares = codec.encode(shares)?;
186        // Save encoded row in square row.
187        for (i, share) in encoded_shares.iter().enumerate() {
188            self.square_row[self.original_width + i][col_index] = share.clone();
189            self.square_col[col_index][self.original_width + i] = share.clone();
190        }
191        Ok(())
192    }
193}
194
195/// Represent an extended piece of data.
196pub struct ExtendedDataSquare {
197    pub data_square: DataSquare,
198}