libisal-sys 0.1.2

FFI Bindings to libisal, the Intel(R) Intelligent Storage Acceleration Library
#![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() {
        // Inverse of identity matrix is identity 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);

        // Cauchy bottom part
        #[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);
    }
}