commonware_cryptography/reed_solomon/engine/
tables.rs1use crate::reed_solomon::engine::{
21 fwht, utils, GfElement, CANTOR_BASIS, GF_BITS, GF_MODULUS, GF_ORDER, GF_POLYNOMIAL,
22};
23#[cfg(not(feature = "std"))]
24use alloc::boxed::Box;
25#[cfg(not(feature = "std"))]
26use alloc::vec;
27#[cfg(not(feature = "std"))]
28use once_cell::race::OnceBox;
29#[cfg(feature = "std")]
30use std::sync::LazyLock;
31
32pub type Exp = [GfElement; GF_ORDER];
41
42pub type Log = [GfElement; GF_ORDER];
48
49pub type Mul128 = [Multiply128lutT; GF_ORDER];
51
52#[derive(Clone, Debug)]
54pub struct Multiply128lutT {
55 pub lo: [u128; 4],
57 pub hi: [u128; 4],
59}
60
61pub type LogWalsh = [GfElement; GF_ORDER];
66
67pub type Mul16 = [[[GfElement; 16]; 4]; GF_ORDER];
71
72pub type Skew = [GfElement; GF_MODULUS as usize];
76
77pub struct ExpLog {
82 pub exp: Box<Exp>,
84 pub log: Box<Log>,
86}
87
88pub fn get_exp_log() -> &'static ExpLog {
93 #[cfg(feature = "std")]
94 {
95 static EXP_LOG: LazyLock<ExpLog> = LazyLock::new(initialize_exp_log);
96 &EXP_LOG
97 }
98 #[cfg(not(feature = "std"))]
99 {
100 static EXP_LOG: OnceBox<ExpLog> = OnceBox::new();
101 EXP_LOG.get_or_init(|| Box::new(initialize_exp_log()))
102 }
103}
104
105pub fn get_log_walsh() -> &'static LogWalsh {
107 #[cfg(feature = "std")]
108 {
109 static LOG_WALSH: LazyLock<Box<LogWalsh>> = LazyLock::new(initialize_log_walsh);
110 &LOG_WALSH
111 }
112 #[cfg(not(feature = "std"))]
113 {
114 static LOG_WALSH: OnceBox<LogWalsh> = OnceBox::new();
115 LOG_WALSH.get_or_init(initialize_log_walsh)
116 }
117}
118
119pub fn get_mul16() -> &'static Mul16 {
121 #[cfg(feature = "std")]
122 {
123 static MUL16: LazyLock<Box<Mul16>> = LazyLock::new(initialize_mul16);
124 &MUL16
125 }
126 #[cfg(not(feature = "std"))]
127 {
128 static MUL16: OnceBox<Mul16> = OnceBox::new();
129 MUL16.get_or_init(initialize_mul16)
130 }
131}
132
133pub fn get_mul128() -> &'static Mul128 {
135 #[cfg(feature = "std")]
136 {
137 static MUL128: LazyLock<Box<Mul128>> = LazyLock::new(initialize_mul128);
138 &MUL128
139 }
140 #[cfg(not(feature = "std"))]
141 {
142 static MUL128: OnceBox<Mul128> = OnceBox::new();
143 MUL128.get_or_init(initialize_mul128)
144 }
145}
146
147pub fn get_skew() -> &'static Skew {
149 #[cfg(feature = "std")]
150 {
151 static SKEW: LazyLock<Box<Skew>> = LazyLock::new(initialize_skew);
152 &SKEW
153 }
154 #[cfg(not(feature = "std"))]
155 {
156 static SKEW: OnceBox<Skew> = OnceBox::new();
157 SKEW.get_or_init(initialize_skew)
158 }
159}
160
161#[inline(always)]
166pub fn mul(x: GfElement, log_m: GfElement, exp: &Exp, log: &Log) -> GfElement {
167 if x == 0 {
168 0
169 } else {
170 exp[utils::add_mod(log[x as usize], log_m) as usize]
171 }
172}
173
174fn initialize_exp_log() -> ExpLog {
178 let mut exp = Box::new([0; GF_ORDER]);
179 let mut log = Box::new([0; GF_ORDER]);
180
181 let mut state = 1;
184 for i in 0..GF_MODULUS {
185 exp[state] = i;
186 state <<= 1;
187 if state >= GF_ORDER {
188 state ^= GF_POLYNOMIAL;
189 }
190 }
191 exp[0] = GF_MODULUS;
192
193 log[0] = 0;
196 for (i, basis) in CANTOR_BASIS.iter().copied().enumerate().take(GF_BITS) {
197 let width = 1usize << i;
198 for j in 0..width {
199 log[j + width] = log[j] ^ basis;
200 }
201 }
202
203 for value in log.iter_mut() {
204 *value = exp[*value as usize];
205 }
206
207 for (i, value) in log.iter().copied().enumerate() {
208 exp[value as usize] = i as GfElement;
209 }
210
211 exp[GF_MODULUS as usize] = exp[0];
212
213 ExpLog { exp, log }
214}
215
216fn initialize_log_walsh() -> Box<LogWalsh> {
217 let log = get_exp_log().log.as_slice();
218
219 let mut log_walsh: Box<LogWalsh> = Box::new([0; GF_ORDER]);
220
221 log_walsh.copy_from_slice(log);
222 log_walsh[0] = 0;
223 fwht::fwht(log_walsh.as_mut(), GF_ORDER);
224
225 log_walsh
226}
227
228fn initialize_mul16() -> Box<Mul16> {
229 let exp = &get_exp_log().exp;
230 let log = &get_exp_log().log;
231 let mut mul16 = vec![[[0; 16]; 4]; GF_ORDER];
232
233 for log_m in 0..=GF_MODULUS {
234 let lut = &mut mul16[log_m as usize];
235 let [row0, row1, row2, row3] = lut;
236 for (i, (((x0, x1), x2), x3)) in row0
237 .iter_mut()
238 .zip(row1.iter_mut())
239 .zip(row2.iter_mut())
240 .zip(row3.iter_mut())
241 .enumerate()
242 {
243 *x0 = mul(i as GfElement, log_m, exp, log);
244 *x1 = mul((i << 4) as GfElement, log_m, exp, log);
245 *x2 = mul((i << 8) as GfElement, log_m, exp, log);
246 *x3 = mul((i << 12) as GfElement, log_m, exp, log);
247 }
248 }
249
250 mul16.into_boxed_slice().try_into().unwrap()
251}
252
253fn initialize_mul128() -> Box<Mul128> {
254 let exp = &get_exp_log().exp;
257 let log = &get_exp_log().log;
258
259 let mut mul128 = vec![
260 Multiply128lutT {
261 lo: [0; 4],
262 hi: [0; 4],
263 };
264 GF_ORDER
265 ];
266
267 for log_m in 0..=GF_MODULUS {
268 for i in 0..=3 {
269 let mut prod_lo = [0u8; 16];
270 let mut prod_hi = [0u8; 16];
271 for x in 0..16 {
272 let prod = mul((x << (i * 4)) as GfElement, log_m, exp, log);
273 prod_lo[x] = prod as u8;
274 prod_hi[x] = (prod >> 8) as u8;
275 }
276 mul128[log_m as usize].lo[i] = u128::from_le_bytes(prod_lo);
277 mul128[log_m as usize].hi[i] = u128::from_le_bytes(prod_hi);
278 }
279 }
280
281 mul128.into_boxed_slice().try_into().unwrap()
282}
283
284fn initialize_skew() -> Box<Skew> {
285 let exp = &get_exp_log().exp;
286 let log = &get_exp_log().log;
287
288 let mut skew = Box::new([0; GF_MODULUS as usize]);
289
290 let mut temp = [0; GF_BITS - 1];
291
292 for (i, value) in temp.iter_mut().enumerate() {
293 *value = 1 << (i + 1);
294 }
295
296 for m in 0..GF_BITS - 1 {
297 let step: usize = 1 << (m + 1);
298
299 skew[(1 << m) - 1] = 0;
300
301 for (i, temp_i) in temp.iter().copied().enumerate().skip(m) {
302 let s: usize = 1 << (i + 1);
303 let mut j = (1 << m) - 1;
304 while j < s {
305 skew[j + s] = skew[j] ^ temp_i;
306 j += step;
307 }
308 }
309
310 temp[m] = GF_MODULUS - log[mul(temp[m], log[(temp[m] ^ 1) as usize], exp, log) as usize];
311
312 for i in m + 1..GF_BITS - 1 {
313 let sum = utils::add_mod(log[(temp[i] ^ 1) as usize], temp[m]);
314 temp[i] = mul(temp[i], sum, exp, log);
315 }
316 }
317
318 for value in skew.iter_mut() {
319 *value = log[*value as usize];
320 }
321
322 skew
323}