reed_solomon_erasure/
galois_8.rs

1//! Implementation of GF(2^8): the finite field with 2^8 elements.
2
3include!(concat!(env!("OUT_DIR"), "/table.rs"));
4
5/// The field GF(2^8).
6#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
7pub struct Field;
8
9impl crate::Field for Field {
10    const ORDER: usize = 256;
11    type Elem = u8;
12
13    fn add(a: u8, b: u8) -> u8 {
14        add(a, b)
15    }
16
17    fn mul(a: u8, b: u8) -> u8 {
18        mul(a, b)
19    }
20
21    fn div(a: u8, b: u8) -> u8 {
22        div(a, b)
23    }
24
25    fn exp(elem: u8, n: usize) -> u8 {
26        exp(elem, n)
27    }
28
29    fn zero() -> u8 {
30        0
31    }
32
33    fn one() -> u8 {
34        1
35    }
36
37    fn nth_internal(n: usize) -> u8 {
38        n as u8
39    }
40
41    fn mul_slice(c: u8, input: &[u8], out: &mut [u8]) {
42        mul_slice(c, input, out)
43    }
44
45    fn mul_slice_add(c: u8, input: &[u8], out: &mut [u8]) {
46        mul_slice_xor(c, input, out)
47    }
48}
49
50/// Type alias of ReedSolomon over GF(2^8).
51pub type ReedSolomon = crate::ReedSolomon<Field>;
52
53/// Type alias of ShardByShard over GF(2^8).
54pub type ShardByShard<'a> = crate::ShardByShard<'a, Field>;
55
56/// Add two elements.
57pub fn add(a: u8, b: u8) -> u8 {
58    a ^ b
59}
60
61/// Subtract `b` from `a`.
62#[cfg(test)]
63pub fn sub(a: u8, b: u8) -> u8 {
64    a ^ b
65}
66
67/// Multiply two elements.
68pub fn mul(a: u8, b: u8) -> u8 {
69    MUL_TABLE[a as usize][b as usize]
70}
71
72/// Divide one element by another. `b`, the divisor, may not be 0.
73pub fn div(a: u8, b: u8) -> u8 {
74    if a == 0 {
75        0
76    } else if b == 0 {
77        panic!("Divisor is 0")
78    } else {
79        let log_a = LOG_TABLE[a as usize];
80        let log_b = LOG_TABLE[b as usize];
81        let mut log_result = log_a as isize - log_b as isize;
82        if log_result < 0 {
83            log_result += 255;
84        }
85        EXP_TABLE[log_result as usize]
86    }
87}
88
89/// Compute a^n.
90pub fn exp(a: u8, n: usize) -> u8 {
91    if n == 0 {
92        1
93    } else if a == 0 {
94        0
95    } else {
96        let log_a = LOG_TABLE[a as usize];
97        let mut log_result = log_a as usize * n;
98        while 255 <= log_result {
99            log_result -= 255;
100        }
101        EXP_TABLE[log_result]
102    }
103}
104
105const PURE_RUST_UNROLL: isize = 4;
106
107macro_rules! return_if_empty {
108    (
109        $len:expr
110    ) => {
111        if $len == 0 {
112            return;
113        }
114    };
115}
116
117#[cfg(not(all(
118    feature = "simd-accel",
119    any(target_arch = "x86_64", target_arch = "aarch64"),
120    not(target_env = "msvc"),
121    not(any(target_os = "android", target_os = "ios"))
122)))]
123pub fn mul_slice(c: u8, input: &[u8], out: &mut [u8]) {
124    mul_slice_pure_rust(c, input, out);
125}
126
127#[cfg(not(all(
128    feature = "simd-accel",
129    any(target_arch = "x86_64", target_arch = "aarch64"),
130    not(target_env = "msvc"),
131    not(any(target_os = "android", target_os = "ios"))
132)))]
133pub fn mul_slice_xor(c: u8, input: &[u8], out: &mut [u8]) {
134    mul_slice_xor_pure_rust(c, input, out);
135}
136
137fn mul_slice_pure_rust(c: u8, input: &[u8], out: &mut [u8]) {
138    let mt = &MUL_TABLE[c as usize];
139    let mt_ptr: *const u8 = &mt[0];
140
141    assert_eq!(input.len(), out.len());
142
143    let len: isize = input.len() as isize;
144    return_if_empty!(len);
145
146    let mut input_ptr: *const u8 = &input[0];
147    let mut out_ptr: *mut u8 = &mut out[0];
148
149    let mut n: isize = 0;
150    unsafe {
151        assert_eq!(4, PURE_RUST_UNROLL);
152        if len > PURE_RUST_UNROLL {
153            let len_minus_unroll = len - PURE_RUST_UNROLL;
154            while n < len_minus_unroll {
155                *out_ptr = *mt_ptr.offset(*input_ptr as isize);
156                *out_ptr.offset(1) = *mt_ptr.offset(*input_ptr.offset(1) as isize);
157                *out_ptr.offset(2) = *mt_ptr.offset(*input_ptr.offset(2) as isize);
158                *out_ptr.offset(3) = *mt_ptr.offset(*input_ptr.offset(3) as isize);
159
160                input_ptr = input_ptr.offset(PURE_RUST_UNROLL);
161                out_ptr = out_ptr.offset(PURE_RUST_UNROLL);
162                n += PURE_RUST_UNROLL;
163            }
164        }
165        while n < len {
166            *out_ptr = *mt_ptr.offset(*input_ptr as isize);
167
168            input_ptr = input_ptr.offset(1);
169            out_ptr = out_ptr.offset(1);
170            n += 1;
171        }
172    }
173    /* for n in 0..input.len() {
174     *   out[n] = mt[input[n] as usize]
175     * }
176     */
177}
178
179fn mul_slice_xor_pure_rust(c: u8, input: &[u8], out: &mut [u8]) {
180    let mt = &MUL_TABLE[c as usize];
181    let mt_ptr: *const u8 = &mt[0];
182
183    assert_eq!(input.len(), out.len());
184
185    let len: isize = input.len() as isize;
186    return_if_empty!(len);
187
188    let mut input_ptr: *const u8 = &input[0];
189    let mut out_ptr: *mut u8 = &mut out[0];
190
191    let mut n: isize = 0;
192    unsafe {
193        assert_eq!(4, PURE_RUST_UNROLL);
194        if len > PURE_RUST_UNROLL {
195            let len_minus_unroll = len - PURE_RUST_UNROLL;
196            while n < len_minus_unroll {
197                *out_ptr ^= *mt_ptr.offset(*input_ptr as isize);
198                *out_ptr.offset(1) ^= *mt_ptr.offset(*input_ptr.offset(1) as isize);
199                *out_ptr.offset(2) ^= *mt_ptr.offset(*input_ptr.offset(2) as isize);
200                *out_ptr.offset(3) ^= *mt_ptr.offset(*input_ptr.offset(3) as isize);
201
202                input_ptr = input_ptr.offset(PURE_RUST_UNROLL);
203                out_ptr = out_ptr.offset(PURE_RUST_UNROLL);
204                n += PURE_RUST_UNROLL;
205            }
206        }
207        while n < len {
208            *out_ptr ^= *mt_ptr.offset(*input_ptr as isize);
209
210            input_ptr = input_ptr.offset(1);
211            out_ptr = out_ptr.offset(1);
212            n += 1;
213        }
214    }
215    /* for n in 0..input.len() {
216     *   out[n] ^= mt[input[n] as usize];
217     * }
218     */
219}
220
221#[cfg(test)]
222fn slice_xor(input: &[u8], out: &mut [u8]) {
223    assert_eq!(input.len(), out.len());
224
225    let len: isize = input.len() as isize;
226    return_if_empty!(len);
227
228    let mut input_ptr: *const u8 = &input[0];
229    let mut out_ptr: *mut u8 = &mut out[0];
230
231    let mut n: isize = 0;
232    unsafe {
233        assert_eq!(4, PURE_RUST_UNROLL);
234        if len > PURE_RUST_UNROLL {
235            let len_minus_unroll = len - PURE_RUST_UNROLL;
236            while n < len_minus_unroll {
237                *out_ptr ^= *input_ptr;
238                *out_ptr.offset(1) ^= *input_ptr.offset(1);
239                *out_ptr.offset(2) ^= *input_ptr.offset(2);
240                *out_ptr.offset(3) ^= *input_ptr.offset(3);
241
242                input_ptr = input_ptr.offset(PURE_RUST_UNROLL);
243                out_ptr = out_ptr.offset(PURE_RUST_UNROLL);
244                n += PURE_RUST_UNROLL;
245            }
246        }
247        while n < len {
248            *out_ptr ^= *input_ptr;
249
250            input_ptr = input_ptr.offset(1);
251            out_ptr = out_ptr.offset(1);
252            n += 1;
253        }
254    }
255    /* for n in 0..input.len() {
256     *   out[n] ^= input[n]
257     * }
258     */
259}
260
261#[cfg(all(
262    feature = "simd-accel",
263    any(target_arch = "x86_64", target_arch = "aarch64"),
264    not(target_env = "msvc"),
265    not(any(target_os = "android", target_os = "ios"))
266))]
267extern "C" {
268    fn reedsolomon_gal_mul(
269        low: *const u8,
270        high: *const u8,
271        input: *const u8,
272        out: *mut u8,
273        len: libc::size_t,
274    ) -> libc::size_t;
275
276    fn reedsolomon_gal_mul_xor(
277        low: *const u8,
278        high: *const u8,
279        input: *const u8,
280        out: *mut u8,
281        len: libc::size_t,
282    ) -> libc::size_t;
283}
284
285#[cfg(all(
286    feature = "simd-accel",
287    any(target_arch = "x86_64", target_arch = "aarch64"),
288    not(target_env = "msvc"),
289    not(any(target_os = "android", target_os = "ios"))
290))]
291pub fn mul_slice(c: u8, input: &[u8], out: &mut [u8]) {
292    let low: *const u8 = &MUL_TABLE_LOW[c as usize][0];
293    let high: *const u8 = &MUL_TABLE_HIGH[c as usize][0];
294
295    assert_eq!(input.len(), out.len());
296
297    let input_ptr: *const u8 = &input[0];
298    let out_ptr: *mut u8 = &mut out[0];
299    let size: libc::size_t = input.len();
300
301    let bytes_done: usize =
302        unsafe { reedsolomon_gal_mul(low, high, input_ptr, out_ptr, size) as usize };
303
304    mul_slice_pure_rust(c, &input[bytes_done..], &mut out[bytes_done..]);
305}
306
307#[cfg(all(
308    feature = "simd-accel",
309    any(target_arch = "x86_64", target_arch = "aarch64"),
310    not(target_env = "msvc"),
311    not(any(target_os = "android", target_os = "ios"))
312))]
313pub fn mul_slice_xor(c: u8, input: &[u8], out: &mut [u8]) {
314    let low: *const u8 = &MUL_TABLE_LOW[c as usize][0];
315    let high: *const u8 = &MUL_TABLE_HIGH[c as usize][0];
316
317    assert_eq!(input.len(), out.len());
318
319    let input_ptr: *const u8 = &input[0];
320    let out_ptr: *mut u8 = &mut out[0];
321    let size: libc::size_t = input.len();
322
323    let bytes_done: usize =
324        unsafe { reedsolomon_gal_mul_xor(low, high, input_ptr, out_ptr, size) as usize };
325
326    mul_slice_xor_pure_rust(c, &input[bytes_done..], &mut out[bytes_done..]);
327}
328
329#[cfg(test)]
330mod tests {
331    extern crate alloc;
332
333    use alloc::vec;
334
335    use super::*;
336    use crate::tests::fill_random;
337    use rand;
338
339    static BACKBLAZE_LOG_TABLE: [u8; 256] = [
340        //-1,    0,    1,   25,    2,   50,   26,  198,
341        // first value is changed from -1 to 0
342        0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141,
343        239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147,
344        142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77,
345        228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54,
346        208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163,
347        195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43,
348        78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222,
349        237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32,
350        137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242,
351        86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183,
352        123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170,
353        251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235,
354        122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88,
355        175,
356    ];
357
358    #[test]
359    fn log_table_same_as_backblaze() {
360        for i in 0..256 {
361            assert_eq!(LOG_TABLE[i], BACKBLAZE_LOG_TABLE[i]);
362        }
363    }
364
365    #[test]
366    fn test_associativity() {
367        for a in 0..256 {
368            let a = a as u8;
369            for b in 0..256 {
370                let b = b as u8;
371                for c in 0..256 {
372                    let c = c as u8;
373                    let x = add(a, add(b, c));
374                    let y = add(add(a, b), c);
375                    assert_eq!(x, y);
376                    let x = mul(a, mul(b, c));
377                    let y = mul(mul(a, b), c);
378                    assert_eq!(x, y);
379                }
380            }
381        }
382    }
383
384    quickcheck! {
385        fn qc_add_associativity(a: u8, b: u8, c: u8) -> bool {
386            add(a, add(b, c)) == add(add(a, b), c)
387        }
388
389        fn qc_mul_associativity(a: u8, b: u8, c: u8) -> bool {
390            mul(a, mul(b, c)) == mul(mul(a, b), c)
391        }
392    }
393
394    #[test]
395    fn test_identity() {
396        for a in 0..256 {
397            let a = a as u8;
398            let b = sub(0, a);
399            let c = sub(a, b);
400            assert_eq!(c, 0);
401            if a != 0 {
402                let b = div(1, a);
403                let c = mul(a, b);
404                assert_eq!(c, 1);
405            }
406        }
407    }
408
409    quickcheck! {
410        fn qc_additive_identity(a: u8) -> bool {
411            sub(a, sub(0, a)) == 0
412        }
413
414        fn qc_multiplicative_identity(a: u8) -> bool {
415            if a == 0 { true }
416            else      { mul(a, div(1, a)) == 1 }
417        }
418    }
419
420    #[test]
421    fn test_commutativity() {
422        for a in 0..256 {
423            let a = a as u8;
424            for b in 0..256 {
425                let b = b as u8;
426                let x = add(a, b);
427                let y = add(b, a);
428                assert_eq!(x, y);
429                let x = mul(a, b);
430                let y = mul(b, a);
431                assert_eq!(x, y);
432            }
433        }
434    }
435
436    quickcheck! {
437        fn qc_add_commutativity(a: u8, b: u8) -> bool {
438            add(a, b) == add(b, a)
439        }
440
441        fn qc_mul_commutativity(a: u8, b: u8) -> bool {
442            mul(a, b) == mul(b, a)
443        }
444    }
445
446    #[test]
447    fn test_distributivity() {
448        for a in 0..256 {
449            let a = a as u8;
450            for b in 0..256 {
451                let b = b as u8;
452                for c in 0..256 {
453                    let c = c as u8;
454                    let x = mul(a, add(b, c));
455                    let y = add(mul(a, b), mul(a, c));
456                    assert_eq!(x, y);
457                }
458            }
459        }
460    }
461
462    quickcheck! {
463        fn qc_add_distributivity(a: u8, b: u8, c: u8) -> bool {
464            mul(a, add(b, c)) == add(mul(a, b), mul(a, c))
465        }
466    }
467
468    #[test]
469    fn test_exp() {
470        for a in 0..256 {
471            let a = a as u8;
472            let mut power = 1u8;
473            for j in 0..256 {
474                let x = exp(a, j);
475                assert_eq!(x, power);
476                power = mul(power, a);
477            }
478        }
479    }
480
481    #[test]
482    fn test_galois() {
483        assert_eq!(mul(3, 4), 12);
484        assert_eq!(mul(7, 7), 21);
485        assert_eq!(mul(23, 45), 41);
486
487        let input = [
488            0, 1, 2, 3, 4, 5, 6, 10, 50, 100, 150, 174, 201, 255, 99, 32, 67, 85, 200, 199, 198,
489            197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185,
490        ];
491        let mut output1 = vec![0; input.len()];
492        let mut output2 = vec![0; input.len()];
493        mul_slice(25, &input, &mut output1);
494        let expect = [
495            0x0, 0x19, 0x32, 0x2b, 0x64, 0x7d, 0x56, 0xfa, 0xb8, 0x6d, 0xc7, 0x85, 0xc3, 0x1f,
496            0x22, 0x7, 0x25, 0xfe, 0xda, 0x5d, 0x44, 0x6f, 0x76, 0x39, 0x20, 0xb, 0x12, 0x11, 0x8,
497            0x23, 0x3a, 0x75, 0x6c, 0x47,
498        ];
499        for i in 0..input.len() {
500            assert_eq!(expect[i], output1[i]);
501        }
502        mul_slice(25, &input, &mut output2);
503        for i in 0..input.len() {
504            assert_eq!(expect[i], output2[i]);
505        }
506
507        let expect_xor = [
508            0x0, 0x2d, 0x5a, 0x77, 0xb4, 0x99, 0xee, 0x2f, 0x79, 0xf2, 0x7, 0x51, 0xd4, 0x19, 0x31,
509            0xc9, 0xf8, 0xfc, 0xf9, 0x4f, 0x62, 0x15, 0x38, 0xfb, 0xd6, 0xa1, 0x8c, 0x96, 0xbb,
510            0xcc, 0xe1, 0x22, 0xf, 0x78,
511        ];
512        mul_slice_xor(52, &input, &mut output1);
513        for i in 0..input.len() {
514            assert_eq!(expect_xor[i], output1[i]);
515        }
516        mul_slice_xor(52, &input, &mut output2);
517        for i in 0..input.len() {
518            assert_eq!(expect_xor[i], output2[i]);
519        }
520
521        let expect = [
522            0x0, 0xb1, 0x7f, 0xce, 0xfe, 0x4f, 0x81, 0x9e, 0x3, 0x6, 0xe8, 0x75, 0xbd, 0x40, 0x36,
523            0xa3, 0x95, 0xcb, 0xc, 0xdd, 0x6c, 0xa2, 0x13, 0x23, 0x92, 0x5c, 0xed, 0x1b, 0xaa,
524            0x64, 0xd5, 0xe5, 0x54, 0x9a,
525        ];
526        mul_slice(177, &input, &mut output1);
527        for i in 0..input.len() {
528            assert_eq!(expect[i], output1[i]);
529        }
530        mul_slice(177, &input, &mut output2);
531        for i in 0..input.len() {
532            assert_eq!(expect[i], output2[i]);
533        }
534
535        let expect_xor = [
536            0x0, 0xc4, 0x95, 0x51, 0x37, 0xf3, 0xa2, 0xfb, 0xec, 0xc5, 0xd0, 0xc7, 0x53, 0x88,
537            0xa3, 0xa5, 0x6, 0x78, 0x97, 0x9f, 0x5b, 0xa, 0xce, 0xa8, 0x6c, 0x3d, 0xf9, 0xdf, 0x1b,
538            0x4a, 0x8e, 0xe8, 0x2c, 0x7d,
539        ];
540        mul_slice_xor(117, &input, &mut output1);
541        for i in 0..input.len() {
542            assert_eq!(expect_xor[i], output1[i]);
543        }
544        mul_slice_xor(117, &input, &mut output2);
545        for i in 0..input.len() {
546            assert_eq!(expect_xor[i], output2[i]);
547        }
548
549        assert_eq!(exp(2, 2), 4);
550        assert_eq!(exp(5, 20), 235);
551        assert_eq!(exp(13, 7), 43);
552    }
553
554    #[test]
555    fn test_slice_add() {
556        let length_list = [16, 32, 34];
557        for len in length_list.iter() {
558            let mut input = vec![0; *len];
559            fill_random(&mut input);
560            let mut output = vec![0; *len];
561            fill_random(&mut output);
562            let mut expect = vec![0; *len];
563            for i in 0..expect.len() {
564                expect[i] = input[i] ^ output[i];
565            }
566            slice_xor(&input, &mut output);
567            for i in 0..expect.len() {
568                assert_eq!(expect[i], output[i]);
569            }
570            fill_random(&mut output);
571            for i in 0..expect.len() {
572                expect[i] = input[i] ^ output[i];
573            }
574            slice_xor(&input, &mut output);
575            for i in 0..expect.len() {
576                assert_eq!(expect[i], output[i]);
577            }
578        }
579    }
580
581    #[test]
582    fn test_div_a_is_0() {
583        assert_eq!(0, div(0, 100));
584    }
585
586    #[test]
587    #[should_panic]
588    fn test_div_b_is_0() {
589        div(1, 0);
590    }
591
592    #[test]
593    fn test_same_as_maybe_ffi() {
594        let len = 10_003;
595        for _ in 0..100 {
596            let c = rand::random::<u8>();
597            let mut input = vec![0; len];
598            fill_random(&mut input);
599            {
600                let mut output = vec![0; len];
601                fill_random(&mut output);
602                let mut output_copy = output.clone();
603
604                mul_slice(c, &input, &mut output);
605                mul_slice(c, &input, &mut output_copy);
606
607                assert_eq!(output, output_copy);
608            }
609            {
610                let mut output = vec![0; len];
611                fill_random(&mut output);
612                let mut output_copy = output.clone();
613
614                mul_slice_xor(c, &input, &mut output);
615                mul_slice_xor(c, &input, &mut output_copy);
616
617                assert_eq!(output, output_copy);
618            }
619        }
620    }
621}