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}