Skip to main content

commonware_cryptography/reed_solomon/
rate.rs

1//! Advanced encoding/decoding using chosen [`Engine`] and [`Rate`].
2//!
3//! **This is an advanced module which is not needed for [simple usage] or [basic usage].**
4//!
5//! This module is relevant if you want to
6//! - encode/decode using other [`Engine`] than [`DefaultEngine`].
7//! - re-use working space of one encoder/decoder in another.
8//! - understand/benchmark/test high or low rate directly.
9//!
10//! # Rates
11//!
12//! See [algorithm > Rate] for details about high/low rate.
13//!
14//! - [`DefaultRate`], [`DefaultRateEncoder`], [`DefaultRateDecoder`]
15//!     - Encoding/decoding using high or low rate as appropriate.
16//!     - These are basically same as [`Encoder`]
17//!       and [`Decoder`] except with slightly different API
18//!       which allows specifying [`Engine`] and working space.
19//! - [`HighRate`], [`HighRateEncoder`], [`HighRateDecoder`]
20//!     - Encoding/decoding using only high rate.
21//! - [`LowRate`], [`LowRateEncoder`], [`LowRateDecoder`]
22//!     - Encoding/decoding using only low rate.
23//!
24//! [simple usage]: crate::reed_solomon#simple-usage
25//! [basic usage]: crate::reed_solomon#basic-usage
26//! [algorithm > Rate]: crate::reed_solomon::algorithm#rate
27//! [`Encoder`]: crate::reed_solomon::Encoder
28//! [`Decoder`]: crate::reed_solomon::Decoder
29//! [`DefaultEngine`]: crate::reed_solomon::engine::DefaultEngine
30
31pub use self::{
32    decoder_work::DecoderWork,
33    encoder_work::EncoderWork,
34    rate_default::{DefaultRate, DefaultRateDecoder, DefaultRateEncoder},
35    rate_high::{HighRate, HighRateDecoder, HighRateEncoder},
36    rate_low::{LowRate, LowRateDecoder, LowRateEncoder},
37};
38use crate::reed_solomon::{engine::Engine, DecoderResult, EncoderResult, Error};
39
40mod decoder_work;
41mod encoder_work;
42mod rate_default;
43mod rate_high;
44mod rate_low;
45
46// ======================================================================
47// Rate - PUBLIC
48
49/// Reed-Solomon encoder/decoder generator using specific rate.
50pub trait Rate<E: Engine> {
51    // ============================================================
52    // REQUIRED
53
54    /// Encoder of this rate.
55    type RateEncoder: RateEncoder<E>;
56    /// Decoder of this rate.
57    type RateDecoder: RateDecoder<E>;
58
59    /// Returns `true` if given `original_count` / `recovery_count`
60    /// combination is supported.
61    fn supports(original_count: usize, recovery_count: usize) -> bool;
62
63    // ============================================================
64    // PROVIDED
65
66    /// Creates new encoder. This is same as [`RateEncoder::new`].
67    fn encoder(
68        original_count: usize,
69        recovery_count: usize,
70        shard_bytes: usize,
71        engine: E,
72        work: Option<EncoderWork>,
73    ) -> Result<Self::RateEncoder, Error> {
74        Self::RateEncoder::new(original_count, recovery_count, shard_bytes, engine, work)
75    }
76
77    /// Creates new decoder. This is same as [`RateDecoder::new`].
78    fn decoder(
79        original_count: usize,
80        recovery_count: usize,
81        shard_bytes: usize,
82        engine: E,
83        work: Option<DecoderWork>,
84    ) -> Result<Self::RateDecoder, Error> {
85        Self::RateDecoder::new(original_count, recovery_count, shard_bytes, engine, work)
86    }
87
88    /// Returns `Ok(())` if given `original_count` / `recovery_count`
89    /// combination is supported and given `shard_bytes` is valid.
90    fn validate(
91        original_count: usize,
92        recovery_count: usize,
93        shard_bytes: usize,
94    ) -> Result<(), Error> {
95        if !Self::supports(original_count, recovery_count) {
96            Err(Error::UnsupportedShardCount {
97                original_count,
98                recovery_count,
99            })
100        } else if shard_bytes == 0 || shard_bytes & 1 != 0 {
101            Err(Error::InvalidShardSize { shard_bytes })
102        } else {
103            Ok(())
104        }
105    }
106}
107
108// ======================================================================
109// RateEncoder - PUBLIC
110
111/// Reed-Solomon encoder using specific rate.
112pub trait RateEncoder<E: Engine>
113where
114    Self: Sized,
115{
116    // ============================================================
117    // REQUIRED
118
119    /// Rate of this encoder.
120    type Rate: Rate<E>;
121
122    /// Like [`Encoder::add_original_shard`](crate::reed_solomon::Encoder::add_original_shard).
123    fn add_original_shard<T: AsRef<[u8]>>(&mut self, original_shard: T) -> Result<(), Error>;
124
125    /// Like [`Encoder::encode`](crate::reed_solomon::Encoder::encode).
126    fn encode(&mut self) -> Result<EncoderResult<'_>, Error>;
127
128    /// Consumes this encoder returning its [`Engine`] and [`EncoderWork`]
129    /// so that they can be re-used by another encoder.
130    fn into_parts(self) -> (E, EncoderWork);
131
132    /// Like [`Encoder::new`](crate::reed_solomon::Encoder::new)
133    /// with [`Engine`] to use and optional working space to be re-used.
134    fn new(
135        original_count: usize,
136        recovery_count: usize,
137        shard_bytes: usize,
138        engine: E,
139        work: Option<EncoderWork>,
140    ) -> Result<Self, Error>;
141
142    /// Like [`Encoder::reset`](crate::reed_solomon::Encoder::reset).
143    fn reset(
144        &mut self,
145        original_count: usize,
146        recovery_count: usize,
147        shard_bytes: usize,
148    ) -> Result<(), Error>;
149
150    // ============================================================
151    // PROVIDED
152
153    /// Returns `true` if given `original_count` / `recovery_count`
154    /// combination is supported.
155    ///
156    /// This is same as [`Rate::supports`].
157    fn supports(original_count: usize, recovery_count: usize) -> bool {
158        Self::Rate::supports(original_count, recovery_count)
159    }
160
161    /// Returns `Ok(())` if given `original_count` / `recovery_count`
162    /// combination is supported and given `shard_bytes` is valid.
163    ///
164    /// This is same as [`Rate::validate`].
165    fn validate(
166        original_count: usize,
167        recovery_count: usize,
168        shard_bytes: usize,
169    ) -> Result<(), Error> {
170        Self::Rate::validate(original_count, recovery_count, shard_bytes)
171    }
172}
173
174// ======================================================================
175// RateDecoder - PUBLIC
176
177/// Reed-Solomon decoder using specific rate.
178pub trait RateDecoder<E: Engine>
179where
180    Self: Sized,
181{
182    // ============================================================
183    // REQUIRED
184
185    /// Rate of this decoder.
186    type Rate: Rate<E>;
187
188    /// Like [`Decoder::add_original_shard`](crate::reed_solomon::Decoder::add_original_shard).
189    fn add_original_shard<T: AsRef<[u8]>>(
190        &mut self,
191        index: usize,
192        original_shard: T,
193    ) -> Result<(), Error>;
194
195    /// Like [`Decoder::add_recovery_shard`](crate::reed_solomon::Decoder::add_recovery_shard).
196    fn add_recovery_shard<T: AsRef<[u8]>>(
197        &mut self,
198        index: usize,
199        recovery_shard: T,
200    ) -> Result<(), Error>;
201
202    /// Like [`Decoder::decode`](crate::reed_solomon::Decoder::decode): reconstructs the missing
203    /// shards, or returns `Ok(None)` if every original was already provided (nothing to reconstruct).
204    /// When `compute_recovery` is set, the missing recovery shards are also reconstructed.
205    fn decode(&mut self, compute_recovery: bool) -> Result<Option<DecoderResult<'_>>, Error>;
206
207    /// Consumes this decoder returning its [`Engine`] and [`DecoderWork`]
208    /// so that they can be re-used by another decoder.
209    fn into_parts(self) -> (E, DecoderWork);
210
211    /// Like [`Decoder::new`](crate::reed_solomon::Decoder::new)
212    /// with [`Engine`] to use and optional working space to be re-used.
213    fn new(
214        original_count: usize,
215        recovery_count: usize,
216        shard_bytes: usize,
217        engine: E,
218        work: Option<DecoderWork>,
219    ) -> Result<Self, Error>;
220
221    /// Like [`Decoder::reset`](crate::reed_solomon::Decoder::reset).
222    fn reset(
223        &mut self,
224        original_count: usize,
225        recovery_count: usize,
226        shard_bytes: usize,
227    ) -> Result<(), Error>;
228
229    // ============================================================
230    // PROVIDED
231
232    /// Returns `true` if given `original_count` / `recovery_count`
233    /// combination is supported.
234    ///
235    /// This is same as [`Rate::supports`].
236    fn supports(original_count: usize, recovery_count: usize) -> bool {
237        Self::Rate::supports(original_count, recovery_count)
238    }
239
240    /// Returns `Ok(())` if given `original_count` / `recovery_count`
241    /// combination is supported and given `shard_bytes` is valid.
242    ///
243    /// This is same as [`Rate::validate`].
244    fn validate(
245        original_count: usize,
246        recovery_count: usize,
247        shard_bytes: usize,
248    ) -> Result<(), Error> {
249        Self::Rate::validate(original_count, recovery_count, shard_bytes)
250    }
251}