round5 0.1.2

Implementation of Round5 post-quantum PKE and KEM algorithms
Documentation
static XE1: [[u8; 2]; 3] = [
                [ 11, 13 ], // XE1-24
                [ 13, 15 ], // XE1-28
                [ 16, 16 ]  // XE1-32
             ];
static XE2: [[u8; 4]; 3] = [
                [ 11, 13, 14, 15 ], // XE2-53
                [ 13, 15, 16, 17 ], // XE2-61
                [ 16, 16, 17, 19 ]  // XE2-68
             ];
static XE3: [[u8; 6]; 3] = [
                [ 11, 13, 15, 16, 17, 19 ], // XE3-91
                [ 13, 15, 16, 17, 19, 23 ], // XE3-103
                [ 16, 16, 17, 19, 21, 23 ]  // XE3-112
             ];
static XE4: [[u8; 8]; 3] = [
                [ 11, 13, 16, 17, 19, 21, 23, 29 ], // XE4-149
                [ 13, 15, 16, 17, 19, 23, 29, 31 ], // XE4-163
                [ 16, 16, 17, 19, 21, 23, 25, 29 ]  // XE4-166
             ];
static XE5: [[u8; 10]; 3] = [
                [ 16, 11, 13, 16, 17, 19, 21, 23, 25, 29 ], // XE5-190
                [ 24, 13, 16, 17, 19, 21, 23, 25, 29, 31 ], // XE5-218
                [ 16, 16, 17, 19, 21, 23, 25, 29, 31, 37 ]  // XE5-234
             ];


fn xef_reg(index: usize, array: usize, el: usize) -> u8 {
    match index {
        1 => XE1[array][el], 
        2 => XE2[array][el],
        3 => XE3[array][el],
        4 => XE4[array][el],
        5 => XE5[array][el],
        _ => {
            panic!();
        }
    }
}

//  Computes the parity code, XORs it at the end of payload
//  len = payload (bytes). Returns (payload | xef) length in *bits*.
#[allow(clippy::many_single_char_names)]
pub fn xef_compute(v: &mut [u8], len: usize, f: u8) {
    let mut j: usize;
    let mut l: usize;
    let mut bit: usize;
    let pl: u16;
    let mut x: u64;
    let mut t: u64;
    let mut r = [0u64; 10];
    if f == 0 || f > 5 {
        panic!();
    }

    if len <= 16 {
        pl = 0;
    } else if len <= 24 {
        pl = 1;
    } else if len <= 32 {
        pl = 2;
    } else {
        panic!();
    }
   
    // reduce the polynomials
    bit = 0;
    for (i, v_el) in v.iter().take(len).enumerate() {
        x = *v_el as u64;

        // special parity
        if pl == 2 || f == 5 {
            t = x;
            t ^= t >> 4;
            t ^= t >> 2;
            t ^= t >> 1;

            if pl == 2 {
                r[0] ^= (t & 1) << (i >> 1);
            } else {
                r[0] ^= (t & 1) << i;
            }
            j = 1;
        } else {
            j = 0;
        }

        // cyclic polynomial case
        for (c, r_el) in r.iter_mut().enumerate().take(2 * f as usize).skip(j) {
            *r_el ^= x << (bit % xef_reg(f as usize - 1, pl as usize, c) as usize);
        }
        bit += 8;
    }

    // pack the result (or rather, XOR over the original)
    for i in 0..2 * f {
        l = xef_reg(f as usize - 1, pl as usize, i as usize) as usize;  // len
        x = r[i as usize];
        x ^= x >> l;

        for j in 0..l {
            v[bit >> 3] = (v[bit >> 3] as u64 ^ (((x >> j) & 1) << (bit & 7))) as u8;
            bit += 1;
        }
    }
}

//  Fixes errors based on parity code. Call xef_compute() first to get delta.
//  len = payload (bytes). Returns (payload | xef) length in *bits*.
#[allow(clippy::many_single_char_names)]
pub fn xef_fixerr(v: &mut [u8], len: usize, f: u8) {
    let mut j: usize;
    let mut l: usize;
    let mut bit: usize;
    let pl: u16;
    let mut th: u16;
    let mut r = [0u64; 10];

    if f == 0 || f > 5 {
        panic!();
    }

    if len <= 16 {
        pl = 0;
    } else if len <= 24 {
        pl = 1;
    } else if len <= 32 {
        pl = 2;
    } else {
        panic!();
    }

    bit = len << 3;
    for (i, el) in r.iter_mut().enumerate() {
        l = xef_reg(f as usize - 1, pl as usize, i as usize) as usize;      // len
        for j in 0..l {
            *el ^= (((v[bit >> 3] >> (bit & 7)) & 1) << j) as u64;
            bit += 1;
        }
    }

    // fix errors
    for i in 0..len << 3 {
        th = (7 - f) as u16;
        if pl == 2 {
            th += ((r[0] >> (i >> 4)) & 1) as u16;
            j = 1;
        } else if f == 5 {
            th += ((r[0] >> (i >> 3)) & 1) as u16;
            j = 1;
        } else {
            j = 0;
        }
        for el in r.iter() {
            th += ((el >> (i %  xef_reg(f as usize - 1, pl as usize, j) as usize)) & 1) as u16;
        }
        // if th > f
        v[i >> 3] ^= ((th >> 3) << (i & 7)) as u8;
    }
}