#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] #![allow(clippy::cargo_common_metadata)] extern "C" { #[doc = "Initialize tables for fast Erasure Code encode and decode."] #[doc = ""] #[doc = "Generates the expanded tables needed for fast encode or decode for erasure"] #[doc = "codes on blocks of data. 32 bytes is generated for each input coefficient."] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `k`: The number of vector sources or rows in the generator matrix"] #[doc = " for coding."] #[doc = "* `rows`: The number of output vectors to concurrently encode/decode."] #[doc = "* `a`: Pointer to sets of arrays of input coefficients used to encode"] #[doc = " or decode data."] #[doc = "* `gftbls`: Pointer to start of space for concatenated output tables"] #[doc = " generated from input coefficients. Must be of size `32 * k * rows`."] pub fn ec_init_tables( k: ::std::os::raw::c_int, rows: ::std::os::raw::c_int, a: *const ::std::os::raw::c_uchar, gftbls: *mut ::std::os::raw::c_uchar, ); } extern "C" { #[doc = "Generate or decode erasure codes on blocks of data, runs appropriate version."] #[doc = ""] #[doc = "Given a list of source data blocks, generate one or multiple blocks of"] #[doc = "encoded data as specified by a matrix of `GF(2^8)` coefficients. When given a"] #[doc = "suitable set of coefficients, this function will perform the fast generation"] #[doc = "or decoding of Reed-Solomon type erasure codes."] #[doc = ""] #[doc = "This function determines what instruction sets are enabled and"] #[doc = "selects the appropriate version at runtime."] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `len`: Length of each block of data (vector) of source or dest data."] #[doc = "* `k`: The number of vector sources or rows in the generator matrix"] #[doc = " for coding."] #[doc = "* `rows`: The number of output vectors to concurrently encode/decode."] #[doc = "* `gftbls`: Pointer to array of input tables generated from coding"] #[doc = " coefficients in `ec_init_tables()`. Must be of size `32 * k * rows`"] #[doc = "* `data`: Array of pointers to source input buffers."] #[doc = "* `coding`: Array of pointers to coded output buffers."] pub fn ec_encode_data( len: ::std::os::raw::c_int, k: ::std::os::raw::c_int, rows: ::std::os::raw::c_int, gftbls: *const ::std::os::raw::c_uchar, data: *const *const ::std::os::raw::c_uchar, coding: *mut *mut ::std::os::raw::c_uchar, ); } extern "C" { #[doc = "Single element `GF(2^8)` multiply."] #[doc = ""] #[doc = "Returns the product of a and b in `GF(2^8)`."] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `a`: Multiplicand a"] #[doc = "* `b`: Multiplicand b"] pub fn gf_mul( a: ::std::os::raw::c_uchar, b: ::std::os::raw::c_uchar, ) -> ::std::os::raw::c_uchar; } extern "C" { #[doc = "Single element `GF(2^8)` inverse."] #[doc = ""] #[doc = "Returns field element `b` such that `a x b = {1}`"] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `a`: Input element"] pub fn gf_inv(a: ::std::os::raw::c_uchar) -> ::std::os::raw::c_uchar; } extern "C" { #[doc = "Generate a matrix of coefficients to be used for encoding."] #[doc = ""] #[doc = "Vandermonde matrix example of encoding coefficients where high portion of"] #[doc = "matrix is identity matrix `I` and lower portion is constructed as `2^{i*(j-k+1)}`"] #[doc = "`i:{0,k-1} j:{k,m-1}`. Commonly used method for choosing coefficients in"] #[doc = "erasure encoding but does not guarantee invertable for every sub matrix. For"] #[doc = "large pairs of `m` and `k` it is possible to find cases where the decode matrix"] #[doc = "chosen from sources and parity is not invertable. Users may want to adjust"] #[doc = "for certain pairs `m` and `k`. If `m` and `k` satisfy one of the following"] #[doc = "inequalities, no adjustment is required:"] #[doc = ""] #[doc = "* `k <= 3`"] #[doc = "* `k = 4, m <= 25`"] #[doc = "* `k = 5, m <= 10`"] #[doc = "* `k <= 21, m-k = 4`"] #[doc = "* `m - k <= 3`"] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `a`: `[m x k]` array to hold coefficients"] #[doc = "* `m`: number of rows in matrix corresponding to srcs + parity."] #[doc = "* `k`: number of columns in matrix corresponding to srcs."] pub fn gf_gen_rs_matrix( a: *mut ::std::os::raw::c_uchar, m: ::std::os::raw::c_int, k: ::std::os::raw::c_int, ); } extern "C" { #[doc = "Generate a Cauchy matrix of coefficients to be used for encoding."] #[doc = ""] #[doc = "Cauchy matrix example of encoding coefficients where high portion of matrix"] #[doc = "is identity matrix `I` and lower portion is constructed as `1/(i + j) | i != j,"] #[doc = "i:{0,k-1} j:{k,m-1}`. Any sub-matrix of a Cauchy matrix should be invertable."] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `a`: `[m x k]` array to hold coefficients"] #[doc = "* `m`: number of rows in matrix corresponding to srcs + parity."] #[doc = "* `k`: number of columns in matrix corresponding to srcs."] pub fn gf_gen_cauchy1_matrix( a: *mut ::std::os::raw::c_uchar, m: ::std::os::raw::c_int, k: ::std::os::raw::c_int, ); } extern "C" { #[doc = "Invert a matrix in `GF(2^8)`."] #[doc = ""] #[doc = "Returns `0` successful, other fail on singular input matrix."] #[doc = ""] #[doc = "# Arguments:"] #[doc = ""] #[doc = "* `in`: input matrix"] #[doc = "* `out`: output matrix such that `[in] x [out] = [I] - identity matrix`"] #[doc = "* `n`: size of matrix `[n x n]`"] pub fn gf_invert_matrix( in_: *mut ::std::os::raw::c_uchar, out: *mut ::std::os::raw::c_uchar, n: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } #[cfg(test)] mod tests { use crate::{ ec_encode_data, ec_init_tables, gf_gen_cauchy1_matrix, gf_gen_rs_matrix, gf_inv, gf_invert_matrix, gf_mul, }; use std::convert::TryInto; #[test] fn test_ec_init_tables() { let k = 4; let p = 2; #[rustfmt::skip] let encode_matrix: Vec = vec![ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0xA7, 0x7A, 0xBA, 0xA7, 0x47, 0xBA, 0x7A, ]; let mut actual_gftbls = vec![0_u8; k * p * 32]; unsafe { ec_init_tables( k.try_into().unwrap(), p.try_into().unwrap(), encode_matrix[k * k..].as_ptr(), actual_gftbls.as_mut_ptr(), ); } #[rustfmt::skip] let expected_gftbls: Vec = vec![ 0x00, 0x47, 0x8E, 0xC9, 0x01, 0x46, 0x8F, 0xC8, 0x02, 0x45, 0x8C, 0xCB, 0x03, 0x44, 0x8D, 0xCA, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, 0x00, 0xA7, 0x53, 0xF4, 0xA6, 0x01, 0xF5, 0x52, 0x51, 0xF6, 0x02, 0xA5, 0xF7, 0x50, 0xA4, 0x03, 0x00, 0xA2, 0x59, 0xFB, 0xB2, 0x10, 0xEB, 0x49, 0x79, 0xDB, 0x20, 0x82, 0xCB, 0x69, 0x92, 0x30, 0x00, 0x7A, 0xF4, 0x8E, 0xF5, 0x8F, 0x01, 0x7B, 0xF7, 0x8D, 0x03, 0x79, 0x02, 0x78, 0xF6, 0x8C, 0x00, 0xF3, 0xFB, 0x08, 0xEB, 0x18, 0x10, 0xE3, 0xCB, 0x38, 0x30, 0xC3, 0x20, 0xD3, 0xDB, 0x28, 0x00, 0xBA, 0x69, 0xD3, 0xD2, 0x68, 0xBB, 0x01, 0xB9, 0x03, 0xD0, 0x6A, 0x6B, 0xD1, 0x02, 0xB8, 0x00, 0x6F, 0xDE, 0xB1, 0xA1, 0xCE, 0x7F, 0x10, 0x5F, 0x30, 0x81, 0xEE, 0xFE, 0x91, 0x20, 0x4F, 0x00, 0xA7, 0x53, 0xF4, 0xA6, 0x01, 0xF5, 0x52, 0x51, 0xF6, 0x02, 0xA5, 0xF7, 0x50, 0xA4, 0x03, 0x00, 0xA2, 0x59, 0xFB, 0xB2, 0x10, 0xEB, 0x49, 0x79, 0xDB, 0x20, 0x82, 0xCB, 0x69, 0x92, 0x30, 0x00, 0x47, 0x8E, 0xC9, 0x01, 0x46, 0x8F, 0xC8, 0x02, 0x45, 0x8C, 0xCB, 0x03, 0x44, 0x8D, 0xCA, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, 0x00, 0xBA, 0x69, 0xD3, 0xD2, 0x68, 0xBB, 0x01, 0xB9, 0x03, 0xD0, 0x6A, 0x6B, 0xD1, 0x02, 0xB8, 0x00, 0x6F, 0xDE, 0xB1, 0xA1, 0xCE, 0x7F, 0x10, 0x5F, 0x30, 0x81, 0xEE, 0xFE, 0x91, 0x20, 0x4F, 0x00, 0x7A, 0xF4, 0x8E, 0xF5, 0x8F, 0x01, 0x7B, 0xF7, 0x8D, 0x03, 0x79, 0x02, 0x78, 0xF6, 0x8C, 0x00, 0xF3, 0xFB, 0x08, 0xEB, 0x18, 0x10, 0xE3, 0xCB, 0x38, 0x30, 0xC3, 0x20, 0xD3, 0xDB, 0x28, ]; assert_eq!(actual_gftbls, expected_gftbls); } #[test] fn test_ec_encode_data() { let len = 1; let k = 4; let nerrs = 2; #[rustfmt::skip] let gftbls: Vec = vec![ 0x00, 0x47, 0x8E, 0xC9, 0x01, 0x46, 0x8F, 0xC8, 0x02, 0x45, 0x8C, 0xCB, 0x03, 0x44, 0x8D, 0xCA, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, 0x00, 0xA7, 0x53, 0xF4, 0xA6, 0x01, 0xF5, 0x52, 0x51, 0xF6, 0x02, 0xA5, 0xF7, 0x50, 0xA4, 0x03, 0x00, 0xA2, 0x59, 0xFB, 0xB2, 0x10, 0xEB, 0x49, 0x79, 0xDB, 0x20, 0x82, 0xCB, 0x69, 0x92, 0x30, 0x00, 0x7A, 0xF4, 0x8E, 0xF5, 0x8F, 0x01, 0x7B, 0xF7, 0x8D, 0x03, 0x79, 0x02, 0x78, 0xF6, 0x8C, 0x00, 0xF3, 0xFB, 0x08, 0xEB, 0x18, 0x10, 0xE3, 0xCB, 0x38, 0x30, 0xC3, 0x20, 0xD3, 0xDB, 0x28, 0x00, 0xBA, 0x69, 0xD3, 0xD2, 0x68, 0xBB, 0x01, 0xB9, 0x03, 0xD0, 0x6A, 0x6B, 0xD1, 0x02, 0xB8, 0x00, 0x6F, 0xDE, 0xB1, 0xA1, 0xCE, 0x7F, 0x10, 0x5F, 0x30, 0x81, 0xEE, 0xFE, 0x91, 0x20, 0x4F, 0x00, 0xA7, 0x53, 0xF4, 0xA6, 0x01, 0xF5, 0x52, 0x51, 0xF6, 0x02, 0xA5, 0xF7, 0x50, 0xA4, 0x03, 0x00, 0xA2, 0x59, 0xFB, 0xB2, 0x10, 0xEB, 0x49, 0x79, 0xDB, 0x20, 0x82, 0xCB, 0x69, 0x92, 0x30, 0x00, 0x47, 0x8E, 0xC9, 0x01, 0x46, 0x8F, 0xC8, 0x02, 0x45, 0x8C, 0xCB, 0x03, 0x44, 0x8D, 0xCA, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, 0x00, 0xBA, 0x69, 0xD3, 0xD2, 0x68, 0xBB, 0x01, 0xB9, 0x03, 0xD0, 0x6A, 0x6B, 0xD1, 0x02, 0xB8, 0x00, 0x6F, 0xDE, 0xB1, 0xA1, 0xCE, 0x7F, 0x10, 0x5F, 0x30, 0x81, 0xEE, 0xFE, 0x91, 0x20, 0x4F, 0x00, 0x7A, 0xF4, 0x8E, 0xF5, 0x8F, 0x01, 0x7B, 0xF7, 0x8D, 0x03, 0x79, 0x02, 0x78, 0xF6, 0x8C, 0x00, 0xF3, 0xFB, 0x08, 0xEB, 0x18, 0x10, 0xE3, 0xCB, 0x38, 0x30, 0xC3, 0x20, 0xD3, 0xDB, 0x28, ]; let data: Vec> = vec![vec![1; len], vec![2; len], vec![3; len], vec![4; len]]; let data_ptrs: Vec<*const u8> = data.iter().map(Vec::as_ptr).collect(); let mut actual_coding: Vec> = vec![vec![0; len], vec![0; len]]; let mut actual_coding_ptrs: Vec<*mut u8> = actual_coding.iter_mut().map(Vec::as_mut_ptr).collect(); unsafe { ec_encode_data( len.try_into().unwrap(), k, nerrs, gftbls.as_ptr(), data_ptrs.as_ptr(), actual_coding_ptrs.as_mut_ptr(), ); } let expected_coding: Vec> = vec![vec![0x48], vec![0x0F]]; for (actual, expected) in actual_coding.iter().zip(expected_coding.iter()) { assert_eq!(actual, expected); } } #[test] fn test_gf_mul() { let a = 0xBE; let b = 0xEF; let expected = 0x03; let actual = unsafe { gf_mul(a, b) }; assert_eq!(actual, expected); } #[test] fn test_gf_inv() { let a = 0x42; let expected = 0xF8; let actual = unsafe { gf_inv(a) }; assert_eq!(actual, expected); } #[test] fn test_gf_gen_rs_matrix() { let k = 4; let p = 2; let m = k + p; let mut actual_encode_matrix = vec![0u8; m * k]; unsafe { gf_gen_rs_matrix( actual_encode_matrix.as_mut_ptr(), m.try_into().unwrap(), k.try_into().unwrap(), ); } #[rustfmt::skip] let expected_encode_matrix = vec![ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x08 ]; assert_eq!(actual_encode_matrix, expected_encode_matrix); } #[test] fn test_gf_gen_cauchy1_matrix() { let k = 4; let p = 2; let m = k + p; let mut actual_encode_matrix = vec![0u8; m * k]; unsafe { gf_gen_cauchy1_matrix( actual_encode_matrix.as_mut_ptr(), m.try_into().unwrap(), k.try_into().unwrap(), ); } #[rustfmt::skip] let expected_encode_matrix = vec![ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0xA7, 0x7A, 0xBA, 0xA7, 0x47, 0xBA, 0x7A, ]; assert_eq!(actual_encode_matrix, expected_encode_matrix); } #[test] fn test_gf_invert_matrix() { // Inverse of identity matrix is identity matrix #[rustfmt::skip] let mut input: Vec = vec![ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ]; let expected: Vec = input.clone(); let mut actual: Vec = vec![0; input.len()]; unsafe { assert_eq!( gf_invert_matrix( input.as_mut_ptr(), actual.as_mut_ptr(), ((input.len() as f64).sqrt()) as i32, ), 0 ); } assert_eq!(actual, expected); // Cauchy bottom part #[rustfmt::skip] let mut input: Vec = vec![ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0xA7, 0x7A, 0xBA, 0xA7, 0x47, 0xBA, 0x7A, ]; #[rustfmt::skip] let expected: Vec = vec![ 0xD0, 0x6B, 0x44, 0x50, 0x6B, 0xD0, 0x50, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ]; let mut actual: Vec = vec![0; input.len()]; unsafe { assert_eq!( gf_invert_matrix( input.as_mut_ptr(), actual.as_mut_ptr(), ((input.len() as f64).sqrt()) as i32, ), 0 ); } assert_eq!(actual, expected); } }