reed_solomon_simd/engine/
tables.rs1use std::sync::LazyLock;
23
24use crate::engine::{
25 fwht, utils, GfElement, CANTOR_BASIS, GF_BITS, GF_MODULUS, GF_ORDER, GF_POLYNOMIAL,
26};
27
28pub type Exp = [GfElement; GF_ORDER];
37
38pub type Log = [GfElement; GF_ORDER];
44
45pub type Mul128 = [Multiply128lutT; GF_ORDER];
50
51#[derive(Clone, Debug)]
53pub struct Multiply128lutT {
54 pub lo: [u128; 4],
56 pub hi: [u128; 4],
58}
59
60pub type LogWalsh = [GfElement; GF_ORDER];
65
66pub type Mul16 = [[[GfElement; 16]; 4]; GF_ORDER];
70
71pub type Skew = [GfElement; GF_MODULUS as usize];
75
76pub struct ExpLog {
81 pub exp: Box<Exp>,
83 pub log: Box<Log>,
85}
86
87pub static EXP_LOG: LazyLock<ExpLog> = LazyLock::new(initialize_exp_log);
92
93pub static LOG_WALSH: LazyLock<Box<LogWalsh>> = LazyLock::new(initialize_log_walsh);
95
96pub static MUL16: LazyLock<Box<Mul16>> = LazyLock::new(initialize_mul16);
98
99pub static MUL128: LazyLock<Box<Mul128>> = LazyLock::new(initialize_mul128);
101
102pub static SKEW: LazyLock<Box<Skew>> = LazyLock::new(initialize_skew);
104
105#[inline(always)]
110pub fn mul(x: GfElement, log_m: GfElement, exp: &Exp, log: &Log) -> GfElement {
111 if x == 0 {
112 0
113 } else {
114 exp[utils::add_mod(log[x as usize], log_m) as usize]
115 }
116}
117
118#[allow(clippy::needless_range_loop)]
122fn initialize_exp_log() -> ExpLog {
123 let mut exp = Box::new([0; GF_ORDER]);
124 let mut log = Box::new([0; GF_ORDER]);
125
126 let mut state = 1;
129 for i in 0..GF_MODULUS {
130 exp[state] = i;
131 state <<= 1;
132 if state >= GF_ORDER {
133 state ^= GF_POLYNOMIAL;
134 }
135 }
136 exp[0] = GF_MODULUS;
137
138 log[0] = 0;
141 for i in 0..GF_BITS {
142 let width = 1usize << i;
143 for j in 0..width {
144 log[j + width] = log[j] ^ CANTOR_BASIS[i];
145 }
146 }
147
148 for i in 0..GF_ORDER {
149 log[i] = exp[log[i] as usize];
150 }
151
152 for i in 0..GF_ORDER {
153 exp[log[i] as usize] = i as GfElement;
154 }
155
156 exp[GF_MODULUS as usize] = exp[0];
157
158 ExpLog { exp, log }
159}
160
161fn initialize_log_walsh() -> Box<LogWalsh> {
162 let log = *EXP_LOG.log;
163
164 let mut log_walsh: Box<LogWalsh> = Box::new([0; GF_ORDER]);
165
166 log_walsh.copy_from_slice(log.as_ref());
167 log_walsh[0] = 0;
168 fwht::fwht(log_walsh.as_mut(), GF_ORDER);
169
170 log_walsh
171}
172
173fn initialize_mul16() -> Box<Mul16> {
174 let exp = &*EXP_LOG.exp;
175 let log = &*EXP_LOG.log;
176 let mut mul16 = vec![[[0; 16]; 4]; GF_ORDER];
177
178 for log_m in 0..=GF_MODULUS {
179 let lut = &mut mul16[log_m as usize];
180 for i in 0..16 {
181 lut[0][i] = mul(i as GfElement, log_m, exp, log);
182 lut[1][i] = mul((i << 4) as GfElement, log_m, exp, log);
183 lut[2][i] = mul((i << 8) as GfElement, log_m, exp, log);
184 lut[3][i] = mul((i << 12) as GfElement, log_m, exp, log);
185 }
186 }
187
188 mul16.into_boxed_slice().try_into().unwrap()
189}
190
191fn initialize_mul128() -> Box<Mul128> {
192 let exp = &*EXP_LOG.exp;
195 let log = &*EXP_LOG.log;
196
197 let mut mul128 = vec![
198 Multiply128lutT {
199 lo: [0; 4],
200 hi: [0; 4],
201 };
202 GF_ORDER
203 ];
204
205 for log_m in 0..=GF_MODULUS {
206 for i in 0..=3 {
207 let mut prod_lo = [0u8; 16];
208 let mut prod_hi = [0u8; 16];
209 for x in 0..16 {
210 let prod = mul((x << (i * 4)) as GfElement, log_m, exp, log);
211 prod_lo[x] = prod as u8;
212 prod_hi[x] = (prod >> 8) as u8;
213 }
214 mul128[log_m as usize].lo[i] = u128::from_le_bytes(prod_lo);
215 mul128[log_m as usize].hi[i] = u128::from_le_bytes(prod_hi);
216 }
217 }
218
219 mul128.into_boxed_slice().try_into().unwrap()
220}
221
222#[allow(clippy::needless_range_loop)]
223fn initialize_skew() -> Box<Skew> {
224 let exp = &*EXP_LOG.exp;
225 let log = &*EXP_LOG.log;
226
227 let mut skew = Box::new([0; GF_MODULUS as usize]);
228
229 let mut temp = [0; GF_BITS - 1];
230
231 for i in 1..GF_BITS {
232 temp[i - 1] = 1 << i;
233 }
234
235 for m in 0..GF_BITS - 1 {
236 let step: usize = 1 << (m + 1);
237
238 skew[(1 << m) - 1] = 0;
239
240 for i in m..GF_BITS - 1 {
241 let s: usize = 1 << (i + 1);
242 let mut j = (1 << m) - 1;
243 while j < s {
244 skew[j + s] = skew[j] ^ temp[i];
245 j += step;
246 }
247 }
248
249 temp[m] = GF_MODULUS - log[mul(temp[m], log[(temp[m] ^ 1) as usize], exp, log) as usize];
250
251 for i in m + 1..GF_BITS - 1 {
252 let sum = utils::add_mod(log[(temp[i] ^ 1) as usize], temp[m]);
253 temp[i] = mul(temp[i], sum, exp, log);
254 }
255 }
256
257 for i in 0..GF_MODULUS as usize {
258 skew[i] = log[skew[i] as usize];
259 }
260
261 skew
262}