commonware_cryptography/reed_solomon/
wrappers.rs1use crate::reed_solomon::{
2 engine::DefaultEngine,
3 rate::{DefaultRate, DefaultRateDecoder, DefaultRateEncoder, Rate, RateDecoder, RateEncoder},
4 DecoderResult, EncoderResult, Error, RecoveryDecoderResult,
5};
6
7pub struct Encoder(DefaultRateEncoder<DefaultEngine>);
14
15impl Encoder {
16 pub fn add_original_shard<T: AsRef<[u8]>>(&mut self, original_shard: T) -> Result<(), Error> {
23 self.0.add_original_shard(original_shard)
24 }
25
26 pub fn encode(&mut self) -> Result<EncoderResult<'_>, Error> {
36 self.0.encode()
37 }
38
39 pub fn new(
44 original_count: usize,
45 recovery_count: usize,
46 shard_bytes: usize,
47 ) -> Result<Self, Error> {
48 Ok(Self(DefaultRateEncoder::new(
49 original_count,
50 recovery_count,
51 shard_bytes,
52 DefaultEngine::new(),
53 None,
54 )?))
55 }
56
57 pub fn reset(
63 &mut self,
64 original_count: usize,
65 recovery_count: usize,
66 shard_bytes: usize,
67 ) -> Result<(), Error> {
68 self.0.reset(original_count, recovery_count, shard_bytes)
69 }
70
71 pub fn supports(original_count: usize, recovery_count: usize) -> bool {
83 DefaultRate::<DefaultEngine>::supports(original_count, recovery_count)
84 }
85}
86
87pub struct Decoder(DefaultRateDecoder<DefaultEngine>);
94
95impl Decoder {
96 pub fn add_original_shard<T: AsRef<[u8]>>(
103 &mut self,
104 index: usize,
105 original_shard: T,
106 ) -> Result<(), Error> {
107 self.0.add_original_shard(index, original_shard)
108 }
109
110 pub fn add_recovery_shard<T: AsRef<[u8]>>(
117 &mut self,
118 index: usize,
119 recovery_shard: T,
120 ) -> Result<(), Error> {
121 self.0.add_recovery_shard(index, recovery_shard)
122 }
123
124 pub fn decode(&mut self) -> Result<Option<DecoderResult<'_>>, Error> {
134 self.0.decode(false)
135 }
136
137 pub fn decode_with_recovery(&mut self) -> Result<Option<RecoveryDecoderResult<'_>>, Error> {
145 Ok(self.0.decode(true)?.map(RecoveryDecoderResult::new))
146 }
147
148 pub fn new(
153 original_count: usize,
154 recovery_count: usize,
155 shard_bytes: usize,
156 ) -> Result<Self, Error> {
157 Ok(Self(DefaultRateDecoder::new(
158 original_count,
159 recovery_count,
160 shard_bytes,
161 DefaultEngine::new(),
162 None,
163 )?))
164 }
165
166 pub fn reset(
172 &mut self,
173 original_count: usize,
174 recovery_count: usize,
175 shard_bytes: usize,
176 ) -> Result<(), Error> {
177 self.0.reset(original_count, recovery_count, shard_bytes)
178 }
179
180 pub fn supports(original_count: usize, recovery_count: usize) -> bool {
192 DefaultRate::<DefaultEngine>::supports(original_count, recovery_count)
193 }
194}
195
196#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::reed_solomon::test_util;
203 use fixedbitset::FixedBitSet;
204 use std::collections::BTreeMap;
205
206 fn roundtrip(
210 encoder: &mut Encoder,
211 decoder: &mut Decoder,
212 original_count: usize,
213 recovery_hash: &str,
214 decoder_original: &[usize],
215 decoder_recovery: &[usize],
216 seed: u8,
217 ) {
218 let original = test_util::generate_original(original_count, 1024, seed);
219
220 for original in &original {
221 encoder.add_original_shard(original).unwrap();
222 }
223
224 let result = encoder.encode().unwrap();
225 let recovery: Vec<_> = result.recovery_iter().collect();
226
227 test_util::assert_hash(&recovery, recovery_hash);
228
229 let mut original_received = FixedBitSet::with_capacity(original_count);
230
231 for i in decoder_original {
232 decoder.add_original_shard(*i, &original[*i]).unwrap();
233 original_received.set(*i, true);
234 }
235
236 for i in decoder_recovery {
237 decoder.add_recovery_shard(*i, recovery[*i]).unwrap();
238 }
239
240 let decoded = decoder.decode();
241 let restored: BTreeMap<_, _> = match &decoded {
242 Ok(Some(result)) => result.original_iter().collect(),
243 Ok(None) => BTreeMap::new(),
244 Err(e) => panic!("decode failed: {e:?}"),
245 };
246
247 for i in 0..original_count {
248 if !original_received[i] {
249 assert_eq!(restored[&i], original[i]);
250 }
251 }
252 }
253
254 #[test]
258 fn roundtrip_two_rounds_reset_low_to_high() {
259 let mut encoder = Encoder::new(2, 3, 1024).unwrap();
260 let mut decoder = Decoder::new(2, 3, 1024).unwrap();
261
262 roundtrip(
263 &mut encoder,
264 &mut decoder,
265 2,
266 test_util::LOW_2_3,
267 &[],
268 &[0, 1],
269 123,
270 );
271
272 encoder.reset(3, 2, 1024).unwrap();
273 decoder.reset(3, 2, 1024).unwrap();
274
275 roundtrip(
276 &mut encoder,
277 &mut decoder,
278 3,
279 test_util::HIGH_3_2,
280 &[1],
281 &[0, 1],
282 132,
283 );
284 }
285
286 #[test]
287 fn failed_encoder_reset_preserves_state() {
288 let original = test_util::generate_original(2, 1024, 123);
289 let mut encoder = Encoder::new(2, 3, 1024).unwrap();
290
291 assert_eq!(
292 encoder.reset(3, 2, 3),
293 Err(Error::InvalidShardSize { shard_bytes: 3 })
294 );
295
296 for shard in &original {
297 encoder.add_original_shard(shard).unwrap();
298 }
299 let result = encoder.encode().unwrap();
300 let recovery: Vec<_> = result.recovery_iter().collect();
301
302 test_util::assert_hash(&recovery, test_util::LOW_2_3);
303 }
304
305 #[test]
306 fn failed_decoder_reset_preserves_state() {
307 let original = test_util::generate_original(2, 1024, 123);
308 let mut encoder = Encoder::new(2, 3, 1024).unwrap();
309 for shard in &original {
310 encoder.add_original_shard(shard).unwrap();
311 }
312 let result = encoder.encode().unwrap();
313 let recovery: Vec<_> = result.recovery_iter().map(<[u8]>::to_vec).collect();
314
315 let mut decoder = Decoder::new(2, 3, 1024).unwrap();
316
317 assert_eq!(
318 decoder.reset(3, 2, 3),
319 Err(Error::InvalidShardSize { shard_bytes: 3 })
320 );
321
322 decoder.add_recovery_shard(0, &recovery[0]).unwrap();
323 decoder.add_recovery_shard(1, &recovery[1]).unwrap();
324 let decoded = decoder.decode();
325 let restored: BTreeMap<_, _> = match &decoded {
326 Ok(Some(result)) => result.original_iter().collect(),
327 Ok(None) => BTreeMap::new(),
328 Err(e) => panic!("decode failed: {e:?}"),
329 };
330
331 assert_eq!(restored[&0], original[0]);
332 assert_eq!(restored[&1], original[1]);
333 }
334
335 #[test]
339 fn supports() {
340 assert!(Encoder::supports(4096, 61440));
341 assert!(Encoder::supports(61440, 4096));
342
343 assert!(Decoder::supports(4096, 61440));
344 assert!(Decoder::supports(61440, 4096));
345 }
346}