#![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<u8> = 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<u8> = 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<u8> = 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<u8>> = 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<u8>> = 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<u8>> = 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() {
#[rustfmt::skip]
let mut input: Vec<u8> = vec![
0x01, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01,
];
let expected: Vec<u8> = input.clone();
let mut actual: Vec<u8> = 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);
#[rustfmt::skip]
let mut input: Vec<u8> = vec![
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01,
0x47, 0xA7, 0x7A, 0xBA,
0xA7, 0x47, 0xBA, 0x7A,
];
#[rustfmt::skip]
let expected: Vec<u8> = vec![
0xD0, 0x6B, 0x44, 0x50,
0x6B, 0xD0, 0x50, 0x44,
0x01, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
];
let mut actual: Vec<u8> = 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);
}
}