reed_solomon_16/engine/
tables.rs1use once_cell::sync::OnceCell;
18
19use crate::engine::{
20 self, Engine, GfElement, CANTOR_BASIS, GF_BITS, GF_MODULUS, GF_ORDER, GF_POLYNOMIAL,
21};
22
23pub type Exp = [GfElement; GF_ORDER];
31
32pub type Log = [GfElement; GF_ORDER];
37
38pub type LogWalsh = [GfElement; GF_ORDER];
40
41pub type Mul16 = [[[GfElement; 16]; 4]; GF_ORDER];
45
46pub type Skew = [GfElement; GF_MODULUS as usize];
48
49struct ExpLog {
53 exp: Box<Exp>,
54 log: Box<Log>,
55}
56
57static EXP_LOG: OnceCell<ExpLog> = OnceCell::new();
61static LOG_WALSH: OnceCell<Box<LogWalsh>> = OnceCell::new();
62static MUL16: OnceCell<Box<Mul16>> = OnceCell::new();
63static SKEW: OnceCell<Box<Skew>> = OnceCell::new();
64
65#[inline(always)]
70pub fn mul(x: GfElement, log_m: GfElement, exp: &Exp, log: &Log) -> GfElement {
71 if x == 0 {
72 0
73 } else {
74 exp[engine::add_mod(log[x as usize], log_m) as usize]
75 }
76}
77
78#[allow(clippy::needless_range_loop)]
83pub fn initialize_exp_log() -> (&'static Exp, &'static Log) {
84 let exp_log = EXP_LOG.get_or_init(|| {
85 let mut exp = Box::new([0; GF_ORDER]);
86 let mut log = Box::new([0; GF_ORDER]);
87
88 let mut state = 1;
91 for i in 0..GF_MODULUS {
92 exp[state] = i;
93 state <<= 1;
94 if state >= GF_ORDER {
95 state ^= GF_POLYNOMIAL;
96 }
97 }
98 exp[0] = GF_MODULUS;
99
100 log[0] = 0;
103 for i in 0..GF_BITS {
104 let width = 1usize << i;
105 for j in 0..width {
106 log[j + width] = log[j] ^ CANTOR_BASIS[i];
107 }
108 }
109
110 for i in 0..GF_ORDER {
111 log[i] = exp[log[i] as usize];
112 }
113
114 for i in 0..GF_ORDER {
115 exp[log[i] as usize] = i as GfElement;
116 }
117
118 exp[GF_MODULUS as usize] = exp[0];
119
120 ExpLog { exp, log }
121 });
122
123 (&exp_log.exp, &exp_log.log)
124}
125
126pub fn initialize_log_walsh<E: Engine>() -> &'static LogWalsh {
128 LOG_WALSH.get_or_init(|| {
129 let (_, log) = initialize_exp_log();
130
131 let mut log_walsh: Box<LogWalsh> = Box::new([0; GF_ORDER]);
132
133 log_walsh.copy_from_slice(log.as_ref());
134 log_walsh[0] = 0;
135 E::fwht(log_walsh.as_mut(), GF_ORDER);
136
137 log_walsh
138 })
139}
140
141pub fn initialize_mul16() -> &'static Mul16 {
143 MUL16.get_or_init(|| {
144 let (exp, log) = initialize_exp_log();
145
146 let mut mul16 = vec![[[0; 16]; 4]; GF_ORDER];
147
148 for log_m in 0..=GF_MODULUS {
149 let lut = &mut mul16[log_m as usize];
150 for i in 0..16 {
151 lut[0][i] = mul(i as GfElement, log_m, exp, log);
152 lut[1][i] = mul((i << 4) as GfElement, log_m, exp, log);
153 lut[2][i] = mul((i << 8) as GfElement, log_m, exp, log);
154 lut[3][i] = mul((i << 12) as GfElement, log_m, exp, log);
155 }
156 }
157
158 mul16.into_boxed_slice().try_into().unwrap()
159 })
160}
161
162#[allow(clippy::needless_range_loop)]
164pub fn initialize_skew() -> &'static Skew {
165 SKEW.get_or_init(|| {
166 let (exp, log) = initialize_exp_log();
167
168 let mut skew = Box::new([0; GF_MODULUS as usize]);
169
170 let mut temp = [0; GF_BITS - 1];
171
172 for i in 1..GF_BITS {
173 temp[i - 1] = 1 << i;
174 }
175
176 for m in 0..GF_BITS - 1 {
177 let step: usize = 1 << (m + 1);
178
179 skew[(1 << m) - 1] = 0;
180
181 for i in m..GF_BITS - 1 {
182 let s: usize = 1 << (i + 1);
183 let mut j = (1 << m) - 1;
184 while j < s {
185 skew[j + s] = skew[j] ^ temp[i];
186 j += step;
187 }
188 }
189
190 temp[m] =
191 GF_MODULUS - log[mul(temp[m], log[(temp[m] ^ 1) as usize], exp, log) as usize];
192
193 for i in m + 1..GF_BITS - 1 {
194 let sum = engine::add_mod(log[(temp[i] ^ 1) as usize], temp[m]);
195 temp[i] = mul(temp[i], sum, exp, log);
196 }
197 }
198
199 for i in 0..GF_MODULUS as usize {
200 skew[i] = log[skew[i] as usize];
201 }
202
203 skew
204 })
205}