1use crate::galois_8;
7use core::ops::{Add, Div, Mul, Sub};
8
9const EXT_POLY: [u8; 3] = [1, 2, 128];
15
16#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
18pub struct Field;
19
20impl crate::Field for Field {
21 const ORDER: usize = 65536;
22
23 type Elem = [u8; 2];
24
25 fn add(a: [u8; 2], b: [u8; 2]) -> [u8; 2] {
26 (Element(a) + Element(b)).0
27 }
28
29 fn mul(a: [u8; 2], b: [u8; 2]) -> [u8; 2] {
30 (Element(a) * Element(b)).0
31 }
32
33 fn div(a: [u8; 2], b: [u8; 2]) -> [u8; 2] {
34 (Element(a) / Element(b)).0
35 }
36
37 fn exp(elem: [u8; 2], n: usize) -> [u8; 2] {
38 Element(elem).exp(n).0
39 }
40
41 fn zero() -> [u8; 2] {
42 [0; 2]
43 }
44
45 fn one() -> [u8; 2] {
46 [0, 1]
47 }
48
49 fn nth_internal(n: usize) -> [u8; 2] {
50 [(n >> 8) as u8, n as u8]
51 }
52}
53
54pub type ReedSolomon = crate::ReedSolomon<Field>;
56
57pub type ShardByShard<'a> = crate::ShardByShard<'a, Field>;
59
60#[derive(Debug, Copy, Clone, PartialEq, Eq)]
62struct Element(pub [u8; 2]);
63
64impl Element {
65 fn zero() -> Self {
67 Element([0, 0])
68 }
69
70 fn constant(n: u8) -> Element {
72 Element([0, n])
73 }
74
75 fn is_zero(&self) -> bool {
77 self.0 == [0; 2]
78 }
79
80 fn exp(mut self, n: usize) -> Element {
81 if n == 0 {
82 Element::constant(1)
83 } else if self == Element::zero() {
84 Element::zero()
85 } else {
86 let x = self;
87 for _ in 1..n {
88 self = self * x;
89 }
90
91 self
92 }
93 }
94
95 #[inline]
97 fn reduce_from(mut x: [u8; 3]) -> Self {
98 if x[0] != 0 {
99 x[1] ^= galois_8::mul(EXT_POLY[1], x[0]);
103 x[2] ^= galois_8::mul(EXT_POLY[2], x[0]);
104 }
105
106 Element([x[1], x[2]])
107 }
108
109 fn degree(&self) -> usize {
110 if self.0[0] != 0 {
111 1
112 } else {
113 0
114 }
115 }
116}
117
118impl From<[u8; 2]> for Element {
119 fn from(c: [u8; 2]) -> Self {
120 Element(c)
121 }
122}
123
124impl Default for Element {
125 fn default() -> Self {
126 Element::zero()
127 }
128}
129
130impl Add for Element {
131 type Output = Element;
132
133 fn add(self, other: Self) -> Element {
134 Element([self.0[0] ^ other.0[0], self.0[1] ^ other.0[1]])
135 }
136}
137
138impl Sub for Element {
139 type Output = Element;
140
141 fn sub(self, other: Self) -> Element {
142 self.add(other)
143 }
144}
145
146impl Mul for Element {
147 type Output = Element;
148
149 fn mul(self, rhs: Self) -> Element {
150 let out: [u8; 3] = [
152 galois_8::mul(self.0[0], rhs.0[0]),
153 galois_8::add(
154 galois_8::mul(self.0[1], rhs.0[0]),
155 galois_8::mul(self.0[0], rhs.0[1]),
156 ),
157 galois_8::mul(self.0[1], rhs.0[1]),
158 ];
159
160 Element::reduce_from(out)
161 }
162}
163
164impl Mul<u8> for Element {
165 type Output = Element;
166
167 fn mul(self, rhs: u8) -> Element {
168 Element([galois_8::mul(rhs, self.0[0]), galois_8::mul(rhs, self.0[1])])
169 }
170}
171
172impl Div for Element {
173 type Output = Element;
174
175 fn div(self, rhs: Self) -> Element {
176 self * rhs.inverse()
177 }
178}
179
180#[derive(Debug)]
183enum EgcdRhs {
184 Element(Element),
185 ExtPoly,
186}
187
188impl Element {
189 fn const_egcd(self, rhs: EgcdRhs) -> (u8, Element, Element) {
192 if self.is_zero() {
193 let rhs = match rhs {
194 EgcdRhs::Element(elem) => elem,
195 EgcdRhs::ExtPoly => panic!("const_egcd invoked with divisible"),
196 };
197 (rhs.0[1], Element::constant(0), Element::constant(1))
198 } else {
199 let (cur_quotient, cur_remainder) = match rhs {
200 EgcdRhs::Element(rhs) => rhs.polynom_div(self),
201 EgcdRhs::ExtPoly => Element::div_ext_by(self),
202 };
203
204 let (g, x, y) = cur_remainder.const_egcd(EgcdRhs::Element(self));
206 (g, y + (cur_quotient * x), x)
207 }
208 }
209
210 fn div_ext_by(rhs: Self) -> (Element, Element) {
212 if rhs.degree() == 0 {
213 return (Element::zero(), Element::zero());
217 }
218
219 let leading_mul_inv = galois_8::div(1, rhs.0[0]);
222
223 let monictized = rhs * leading_mul_inv;
224 let mut poly = EXT_POLY;
225
226 for i in 0..2 {
227 let coef = poly[i];
228 for j in 1..2 {
229 if rhs.0[j] != 0 {
230 poly[i + j] ^= galois_8::mul(monictized.0[j], coef);
231 }
232 }
233 }
234
235 let remainder = Element::constant(poly[2]);
236 let quotient = Element([poly[0], poly[1]]) * leading_mul_inv;
237
238 (quotient, remainder)
239 }
240
241 fn polynom_div(self, rhs: Self) -> (Element, Element) {
242 let divisor_degree = rhs.degree();
243 if rhs.is_zero() {
244 panic!("divide by 0");
245 } else if self.degree() < divisor_degree {
246 (Element::zero(), self)
248 } else if divisor_degree == 0 {
249 let invert = galois_8::div(1, rhs.0[1]);
251 let quotient = Element([
252 galois_8::mul(invert, self.0[0]),
253 galois_8::mul(invert, self.0[1]),
254 ]);
255
256 (quotient, Element::zero())
257 } else {
258 debug_assert_eq!(self.degree(), divisor_degree);
261 debug_assert_eq!(self.degree(), 1);
262
263 let leading_mul_inv = galois_8::div(1, rhs.0[0]);
265 let monic = Element([
266 galois_8::mul(leading_mul_inv, rhs.0[0]),
267 galois_8::mul(leading_mul_inv, rhs.0[1]),
268 ]);
269
270 let leading_coeff = self.0[0];
271 let mut remainder = self.0[1];
272
273 if monic.0[1] != 0 {
274 remainder ^= galois_8::mul(monic.0[1], self.0[0]);
275 }
276
277 (
278 Element::constant(galois_8::mul(leading_mul_inv, leading_coeff)),
279 Element::constant(remainder),
280 )
281 }
282 }
283
284 fn inverse(self) -> Element {
286 if self.is_zero() {
287 panic!("Cannot invert 0");
288 }
289
290 let (gcd, y) = {
293 let remainder = self;
295
296 let (g, x, _) = remainder.const_egcd(EgcdRhs::ExtPoly);
298
299 (g, x)
300 };
301
302 if gcd != 0 {
304 let normalizer = galois_8::div(1, gcd);
310 y * normalizer
311 } else {
312 panic!("Cannot invert 0");
314 }
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321 use quickcheck::Arbitrary;
322
323 impl Arbitrary for Element {
324 fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
325 let a = u8::arbitrary(gen);
326 let b = u8::arbitrary(gen);
327
328 Element([a, b])
329 }
330 }
331
332 quickcheck! {
333 fn qc_add_associativity(a: Element, b: Element, c: Element) -> bool {
334 a + (b + c) == (a + b) + c
335 }
336
337 fn qc_mul_associativity(a: Element, b: Element, c: Element) -> bool {
338 a * (b * c) == (a * b) * c
339 }
340
341 fn qc_additive_identity(a: Element) -> bool {
342 let zero = Element::zero();
343 a - (zero - a) == zero
344 }
345
346 fn qc_multiplicative_identity(a: Element) -> bool {
347 a.is_zero() || {
348 let one = Element([0, 1]);
349 (one / a) * a == one
350 }
351 }
352
353 fn qc_add_commutativity(a: Element, b: Element) -> bool {
354 a + b == b + a
355 }
356
357 fn qc_mul_commutativity(a: Element, b: Element) -> bool {
358 a * b == b * a
359 }
360
361 fn qc_add_distributivity(a: Element, b: Element, c: Element) -> bool {
362 a * (b + c) == (a * b) + (a * c)
363 }
364
365 fn qc_inverse(a: Element) -> bool {
366 a.is_zero() || {
367 let inv = a.inverse();
368 a * inv == Element::constant(1)
369 }
370 }
371
372 fn qc_exponent_1(a: Element, n: u8) -> bool {
373 a.is_zero() || n == 0 || {
374 let mut b = a.exp(n as usize);
375 for _ in 1..n {
376 b = b / a;
377 }
378
379 a == b
380 }
381 }
382
383 fn qc_exponent_2(a: Element, n: u8) -> bool {
384 a.is_zero() || {
385 let mut res = true;
386 let mut b = Element::constant(1);
387
388 for i in 0..n {
389 res = res && b == a.exp(i as usize);
390 b = b * a;
391 }
392
393 res
394 }
395 }
396
397 fn qc_exp_zero_is_one(a: Element) -> bool {
398 a.exp(0) == Element::constant(1)
399 }
400 }
401
402 #[test]
403 #[should_panic]
404 fn test_div_b_is_0() {
405 let _ = Element([1, 0]) / Element::zero();
406 }
407
408 #[test]
409 fn zero_to_zero_is_one() {
410 assert_eq!(Element::zero().exp(0), Element::constant(1))
411 }
412}