1use std::marker::PhantomData;
2
3use crate::{
4 engine::{self, Engine, GF_MODULUS, GF_ORDER},
5 rate::{DecoderWork, EncoderWork, Rate, RateDecoder, RateEncoder},
6 DecoderResult, EncoderResult, Error,
7};
8
9pub struct HighRate<E: Engine>(PhantomData<E>);
14
15impl<E: Engine> Rate<E> for HighRate<E> {
16 type RateEncoder = HighRateEncoder<E>;
17 type RateDecoder = HighRateDecoder<E>;
18
19 fn supports(original_count: usize, recovery_count: usize) -> bool {
20 original_count > 0
21 && recovery_count > 0
22 && original_count < GF_ORDER
23 && recovery_count < GF_ORDER
24 && recovery_count.next_power_of_two() + original_count <= GF_ORDER
25 }
26}
27
28pub struct HighRateEncoder<E: Engine> {
33 engine: E,
34 work: EncoderWork,
35}
36
37impl<E: Engine> RateEncoder<E> for HighRateEncoder<E> {
38 type Rate = HighRate<E>;
39
40 fn add_original_shard<T: AsRef<[u8]>>(&mut self, original_shard: T) -> Result<(), Error> {
41 self.work.add_original_shard(original_shard)
42 }
43
44 fn encode(&mut self) -> Result<EncoderResult, Error> {
45 let (mut work, original_count, recovery_count) = self.work.encode_begin()?;
46 let chunk_size = recovery_count.next_power_of_two();
47 let engine = &self.engine;
48
49 let first_count = std::cmp::min(original_count, chunk_size);
52
53 work.zero(first_count..chunk_size);
54 engine.ifft_skew_end(&mut work, 0, chunk_size, first_count);
55
56 if original_count > chunk_size {
57 let mut chunk_start = chunk_size;
60 while chunk_start + chunk_size <= original_count {
61 engine.ifft_skew_end(&mut work, chunk_start, chunk_size, chunk_size);
62 E::xor_within(&mut work, 0, chunk_start, chunk_size);
63 chunk_start += chunk_size;
64 }
65
66 let last_count = original_count % chunk_size;
69 if last_count > 0 {
70 work.zero(chunk_start + last_count..);
71 engine.ifft_skew_end(&mut work, chunk_start, chunk_size, last_count);
72 E::xor_within(&mut work, 0, chunk_start, chunk_size);
73 }
74 }
75
76 engine.fft(&mut work, 0, chunk_size, recovery_count, 0);
79
80 Ok(EncoderResult::new(&mut self.work))
83 }
84
85 fn into_parts(self) -> (E, EncoderWork) {
86 (self.engine, self.work)
87 }
88
89 fn new(
90 original_count: usize,
91 recovery_count: usize,
92 shard_bytes: usize,
93 engine: E,
94 work: Option<EncoderWork>,
95 ) -> Result<Self, Error> {
96 let mut work = work.unwrap_or_default();
97 Self::reset_work(original_count, recovery_count, shard_bytes, &mut work)?;
98 Ok(Self { work, engine })
99 }
100
101 fn reset(
102 &mut self,
103 original_count: usize,
104 recovery_count: usize,
105 shard_bytes: usize,
106 ) -> Result<(), Error> {
107 Self::reset_work(original_count, recovery_count, shard_bytes, &mut self.work)
108 }
109}
110
111impl<E: Engine> HighRateEncoder<E> {
115 fn reset_work(
116 original_count: usize,
117 recovery_count: usize,
118 shard_bytes: usize,
119 work: &mut EncoderWork,
120 ) -> Result<(), Error> {
121 Self::validate(original_count, recovery_count, shard_bytes)?;
122 work.reset(
123 original_count,
124 recovery_count,
125 shard_bytes,
126 Self::work_count(original_count, recovery_count),
127 );
128 Ok(())
129 }
130
131 fn work_count(original_count: usize, recovery_count: usize) -> usize {
132 debug_assert!(Self::supports(original_count, recovery_count));
133
134 let chunk_size = recovery_count.next_power_of_two();
135
136 engine::checked_next_multiple_of(original_count, chunk_size).unwrap()
137 }
138}
139
140pub struct HighRateDecoder<E: Engine> {
145 engine: E,
146 work: DecoderWork,
147}
148
149impl<E: Engine> RateDecoder<E> for HighRateDecoder<E> {
150 type Rate = HighRate<E>;
151
152 fn add_original_shard<T: AsRef<[u8]>>(
153 &mut self,
154 index: usize,
155 original_shard: T,
156 ) -> Result<(), Error> {
157 self.work.add_original_shard(index, original_shard)
158 }
159
160 fn add_recovery_shard<T: AsRef<[u8]>>(
161 &mut self,
162 index: usize,
163 recovery_shard: T,
164 ) -> Result<(), Error> {
165 self.work.add_recovery_shard(index, recovery_shard)
166 }
167
168 fn decode(&mut self) -> Result<DecoderResult, Error> {
169 let (mut work, original_count, recovery_count, received) =
170 if let Some(stuff) = self.work.decode_begin()? {
171 stuff
172 } else {
173 return Ok(DecoderResult::new(&mut self.work));
175 };
176
177 let chunk_size = recovery_count.next_power_of_two();
178 let original_end = chunk_size + original_count;
179 let work_count = work.len();
180
181 let mut erasures = [0; GF_ORDER];
184
185 for i in 0..recovery_count {
186 if !received[i] {
187 erasures[i] = 1;
188 }
189 }
190
191 erasures[recovery_count..chunk_size].fill(1);
192
193 for i in chunk_size..original_end {
194 if !received[i] {
195 erasures[i] = 1;
196 }
197 }
198
199 E::eval_poly(&mut erasures, original_end);
202
203 for i in 0..recovery_count {
211 if received[i] {
212 self.engine.mul(&mut work[i], erasures[i]);
213 } else {
214 work[i].fill(0);
215 }
216 }
217
218 work.zero(recovery_count..chunk_size);
219
220 for i in chunk_size..original_end {
221 if received[i] {
222 self.engine.mul(&mut work[i], erasures[i]);
223 } else {
224 work[i].fill(0);
225 }
226 }
227
228 work.zero(original_end..);
229
230 self.engine.ifft(&mut work, 0, work_count, original_end, 0);
233 E::formal_derivative(&mut work);
234 self.engine.fft(&mut work, 0, work_count, original_end, 0);
235
236 for i in chunk_size..original_end {
239 if !received[i] {
240 self.engine.mul(&mut work[i], GF_MODULUS - erasures[i]);
241 }
242 }
243
244 Ok(DecoderResult::new(&mut self.work))
247 }
248
249 fn into_parts(self) -> (E, DecoderWork) {
250 (self.engine, self.work)
251 }
252
253 fn new(
254 original_count: usize,
255 recovery_count: usize,
256 shard_bytes: usize,
257 engine: E,
258 work: Option<DecoderWork>,
259 ) -> Result<Self, Error> {
260 let mut work = work.unwrap_or_default();
261 Self::reset_work(original_count, recovery_count, shard_bytes, &mut work)?;
262 Ok(Self { work, engine })
263 }
264
265 fn reset(
266 &mut self,
267 original_count: usize,
268 recovery_count: usize,
269 shard_bytes: usize,
270 ) -> Result<(), Error> {
271 Self::reset_work(original_count, recovery_count, shard_bytes, &mut self.work)
272 }
273}
274
275impl<E: Engine> HighRateDecoder<E> {
279 fn reset_work(
280 original_count: usize,
281 recovery_count: usize,
282 shard_bytes: usize,
283 work: &mut DecoderWork,
284 ) -> Result<(), Error> {
285 Self::validate(original_count, recovery_count, shard_bytes)?;
286
287 work.reset(
290 original_count,
291 recovery_count,
292 shard_bytes,
293 recovery_count.next_power_of_two(),
294 0,
295 Self::work_count(original_count, recovery_count),
296 );
297
298 Ok(())
299 }
300
301 fn work_count(original_count: usize, recovery_count: usize) -> usize {
302 debug_assert!(Self::supports(original_count, recovery_count));
303
304 (recovery_count.next_power_of_two() + original_count).next_power_of_two()
305 }
306}
307
308#[cfg(test)]
312mod tests {
313 use super::*;
314 use crate::test_util;
315
316 #[test]
320 fn roundtrip_all_originals_missing() {
321 roundtrip_single!(
322 HighRate,
323 3,
324 3,
325 1024,
326 test_util::EITHER_3_3,
327 &[],
328 &[0..3],
329 133,
330 );
331 }
332
333 #[test]
334 fn roundtrip_no_originals_missing() {
335 roundtrip_single!(HighRate, 3, 2, 1024, test_util::HIGH_3_2, &[0..3], &[], 132);
336 }
337
338 #[test]
339 fn roundtrips_tiny() {
340 for (original_count, recovery_count, seed, recovery_hash) in test_util::HIGH_TINY {
341 roundtrip_single!(
342 HighRate,
343 *original_count,
344 *recovery_count,
345 1024,
346 recovery_hash,
347 &[*recovery_count..*original_count],
348 &[0..std::cmp::min(*original_count, *recovery_count)],
349 *seed,
350 );
351 }
352 }
353
354 #[test]
355 #[ignore]
356 fn roundtrip_3000_30000() {
357 roundtrip_single!(
358 HighRate,
359 3000,
360 30000,
361 64,
362 test_util::HIGH_3000_30000_14,
363 &[],
364 &[0..3000],
365 14,
366 );
367 }
368
369 #[test]
370 #[ignore]
371 fn roundtrip_32768_32768() {
372 roundtrip_single!(
373 HighRate,
374 32768,
375 32768,
376 64,
377 test_util::EITHER_32768_32768_11,
378 &[],
379 &[0..32768],
380 11,
381 );
382 }
383
384 #[test]
385 #[ignore]
386 fn roundtrip_60000_3000() {
387 roundtrip_single!(
388 HighRate,
389 60000,
390 3000,
391 64,
392 test_util::HIGH_60000_3000_12,
393 &[3000..60000],
394 &[0..3000],
395 12,
396 );
397 }
398
399 #[test]
403 fn two_rounds_implicit_reset() {
404 roundtrip_two_rounds!(
405 HighRate,
406 false,
407 (3, 2, 1024, test_util::HIGH_3_2, &[1], &[0, 1], 132),
408 (3, 2, 1024, test_util::HIGH_3_2_232, &[0], &[0, 1], 232),
409 );
410 }
411
412 #[test]
413 fn two_rounds_explicit_reset() {
414 roundtrip_two_rounds!(
415 HighRate,
416 true,
417 (3, 2, 1024, test_util::HIGH_3_2, &[1], &[0, 1], 132),
418 (5, 2, 1024, test_util::HIGH_5_2, &[0, 2, 4], &[0, 1], 152),
419 );
420 }
421
422 mod high_rate {
426 use crate::{
427 engine::NoSimd,
428 rate::{HighRate, Rate},
429 Error,
430 };
431
432 #[test]
433 fn decoder() {
434 assert_eq!(
435 HighRate::<NoSimd>::decoder(4096, 61440, 64, NoSimd::new(), None).err(),
436 Some(Error::UnsupportedShardCount {
437 original_count: 4096,
438 recovery_count: 61440,
439 })
440 );
441
442 assert!(HighRate::<NoSimd>::decoder(61440, 4096, 64, NoSimd::new(), None).is_ok());
443 }
444
445 #[test]
446 fn encoder() {
447 assert_eq!(
448 HighRate::<NoSimd>::encoder(4096, 61440, 64, NoSimd::new(), None).err(),
449 Some(Error::UnsupportedShardCount {
450 original_count: 4096,
451 recovery_count: 61440,
452 })
453 );
454
455 assert!(HighRate::<NoSimd>::encoder(61440, 4096, 64, NoSimd::new(), None).is_ok());
456 }
457
458 #[test]
459 fn supports() {
460 assert!(!HighRate::<NoSimd>::supports(0, 1));
461 assert!(!HighRate::<NoSimd>::supports(1, 0));
462
463 assert!(!HighRate::<NoSimd>::supports(4096, 61440));
464
465 assert!(HighRate::<NoSimd>::supports(61440, 4096));
466 assert!(!HighRate::<NoSimd>::supports(61440, 4097));
467 assert!(!HighRate::<NoSimd>::supports(61441, 4096));
468
469 assert!(!HighRate::<NoSimd>::supports(usize::MAX, usize::MAX));
470 }
471
472 #[test]
473 fn validate() {
474 assert_eq!(
475 HighRate::<NoSimd>::validate(1, 1, 123).err(),
476 Some(Error::InvalidShardSize { shard_bytes: 123 })
477 );
478
479 assert_eq!(
480 HighRate::<NoSimd>::validate(4096, 61440, 64).err(),
481 Some(Error::UnsupportedShardCount {
482 original_count: 4096,
483 recovery_count: 61440,
484 })
485 );
486
487 assert!(HighRate::<NoSimd>::validate(61440, 4096, 64).is_ok());
488 }
489 }
490
491 mod high_rate_encoder {
495 use crate::{
496 engine::NoSimd,
497 rate::{HighRateEncoder, RateEncoder},
498 Error,
499 };
500
501 test_rate_encoder_errors! {HighRateEncoder}
505
506 #[test]
510 fn supports() {
511 assert!(!HighRateEncoder::<NoSimd>::supports(4096, 61440));
512 assert!(HighRateEncoder::<NoSimd>::supports(61440, 4096));
513 }
514
515 #[test]
519 fn validate() {
520 assert_eq!(
521 HighRateEncoder::<NoSimd>::validate(1, 1, 123).err(),
522 Some(Error::InvalidShardSize { shard_bytes: 123 })
523 );
524
525 assert_eq!(
526 HighRateEncoder::<NoSimd>::validate(4096, 61440, 64).err(),
527 Some(Error::UnsupportedShardCount {
528 original_count: 4096,
529 recovery_count: 61440,
530 })
531 );
532
533 assert!(HighRateEncoder::<NoSimd>::validate(61440, 4096, 64).is_ok());
534 }
535
536 #[test]
540 fn work_count() {
541 assert_eq!(HighRateEncoder::<NoSimd>::work_count(1, 1), 1);
542 assert_eq!(HighRateEncoder::<NoSimd>::work_count(4096, 1024), 4096);
543 assert_eq!(HighRateEncoder::<NoSimd>::work_count(4097, 1024), 5120);
544 assert_eq!(HighRateEncoder::<NoSimd>::work_count(4097, 1025), 6144);
545 assert_eq!(HighRateEncoder::<NoSimd>::work_count(32768, 32768), 32768);
546 }
547 }
548
549 mod high_rate_decoder {
553 use crate::{
554 engine::NoSimd,
555 rate::{HighRateDecoder, RateDecoder},
556 Error,
557 };
558
559 test_rate_decoder_errors! {HighRateDecoder}
563
564 #[test]
568 fn supports() {
569 assert!(!HighRateDecoder::<NoSimd>::supports(4096, 61440));
570 assert!(HighRateDecoder::<NoSimd>::supports(61440, 4096));
571 }
572
573 #[test]
577 fn validate() {
578 assert_eq!(
579 HighRateDecoder::<NoSimd>::validate(1, 1, 123).err(),
580 Some(Error::InvalidShardSize { shard_bytes: 123 })
581 );
582
583 assert_eq!(
584 HighRateDecoder::<NoSimd>::validate(4096, 61440, 64).err(),
585 Some(Error::UnsupportedShardCount {
586 original_count: 4096,
587 recovery_count: 61440,
588 })
589 );
590
591 assert!(HighRateDecoder::<NoSimd>::validate(61440, 4096, 64).is_ok());
592 }
593
594 #[test]
598 fn work_count() {
599 assert_eq!(HighRateDecoder::<NoSimd>::work_count(1, 1), 2);
600 assert_eq!(HighRateDecoder::<NoSimd>::work_count(2048, 1025), 4096);
601 assert_eq!(HighRateDecoder::<NoSimd>::work_count(2049, 1025), 8192);
602 assert_eq!(HighRateDecoder::<NoSimd>::work_count(3072, 1024), 4096);
603 assert_eq!(HighRateDecoder::<NoSimd>::work_count(3073, 1024), 8192);
604 assert_eq!(HighRateDecoder::<NoSimd>::work_count(32768, 32768), 65536);
605 }
606 }
607}