1include!(concat!(env!("OUT_DIR"), "/table.rs"));
4
5#[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
50pub type ReedSolomon = crate::ReedSolomon<Field>;
52
53pub type ShardByShard<'a> = crate::ShardByShard<'a, Field>;
55
56pub fn add(a: u8, b: u8) -> u8 {
58 a ^ b
59}
60
61#[cfg(test)]
63pub fn sub(a: u8, b: u8) -> u8 {
64 a ^ b
65}
66
67pub fn mul(a: u8, b: u8) -> u8 {
69 MUL_TABLE[a as usize][b as usize]
70}
71
72pub 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
89pub 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 }
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 }
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 }
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 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}