round5 0.1.2

Implementation of Round5 post-quantum PKE and KEM algorithms
Documentation
pub mod r5_parameter_sets;

pub use crate::parameters::r5_parameter_sets::{R5_PARAMETERS_SETS, R5_PARAMETERS_NAMES};


pub struct Parameters {
    pub name: &'static str,
    pub c_sk: usize,
    pub c_pk: usize,
    pub c_b: usize,
    pub c_ct: usize,
    pub tau: u8,
    pub tau2_len: u32,
    pub d: u16, 
    pub n: u16, 
    pub h: u16, 
    pub q_bits: u8, 
    pub p_bits: u8, 
    pub t_bits: u8, 
    pub n_bar: u16, 
    pub m_bar: u16, 
    pub b_bits: u8, 
    pub kappa_bytes: u8, 
    pub f: u8, 
    pub xe: u8, 
    pub kappa: u16, 
    pub k: u16, 
    pub q: u32, 
    pub p: u16, 
    pub mu: u16, 
    pub z_bits: u16, 
    pub h1: u16, 
    pub h2: u16, 
    pub h3: u16, 
    pub pk_size: u32, 
    pub ct_size: u16, 
}

impl Parameters {
    pub fn r5n1_1_pke_0d() -> Parameters {
        Parameters::from_api(15)
    }

    pub fn r5n1_1_kem_0d() -> Parameters {
        Parameters::from_api(12)
    }

    pub fn from_api(api_set: usize) -> Parameters {
        let params_set = R5_PARAMETERS_SETS[api_set];
        let name = R5_PARAMETERS_NAMES[api_set];
        let c_sk = params_set[r5_parameter_sets::API_SECRET] as usize;
        let c_pk = params_set[r5_parameter_sets::API_PUBLIC] as usize;
        let c_b = params_set[r5_parameter_sets::API_BYTES] as usize;
        let c_ct = params_set[r5_parameter_sets::API_CIPHER] as usize;
        let kappa_bytes = params_set[r5_parameter_sets::POS_KAPPA_BYTES] as u8;
        let d = params_set[r5_parameter_sets::POS_D] as u16;
        let n = params_set[r5_parameter_sets::POS_N] as u16;
        let h = params_set[r5_parameter_sets::POS_H] as u16;
        let q_bits = params_set[r5_parameter_sets::POS_Q_BITS] as u8;
        let p_bits = params_set[r5_parameter_sets::POS_P_BITS] as u8;
        let t_bits = params_set[r5_parameter_sets::POS_T_BITS] as u8;
        let n_bar = params_set[r5_parameter_sets::POS_N_BAR] as u16;
        let m_bar = params_set[r5_parameter_sets::POS_M_BAR] as u16;
        let b_bits = params_set[r5_parameter_sets::POS_B_BITS] as u8;
        let f = params_set[r5_parameter_sets::POS_F] as u8;
        let xe = params_set[r5_parameter_sets::POS_XE] as u8;

        Parameters::build_parameters(name, c_sk, c_pk, c_b, c_ct,
                                     r5_parameter_sets::ROUND5_API_TAU,
                                     r5_parameter_sets::ROUND5_API_TAU2_LEN,
                                     kappa_bytes, d, n, h, q_bits, p_bits,
                                     t_bits, b_bits, n_bar, m_bar, f, xe)
    }

    #[allow(clippy::many_single_char_names)]
    #[allow(clippy::too_many_arguments)]
    fn build_parameters(name: &'static str, c_sk: usize, c_pk: usize, c_b: usize, c_ct: usize,
                        tau: u8, tau2_len: u32, kappa_bytes: u8, d: u16, n: u16,
                        h: u16, q_bits: u8, p_bits: u8, t_bits: u8, b_bits: u8,
                        n_bar: u16, m_bar: u16, f: u8, xe: u8) -> Parameters {
        // Derived parameters
        let kappa = 8 * kappa_bytes as u16;
        let k: u16 = safe_div!(d, n);
        let mu: u16 = if b_bits > 0 { ceil_div!((kappa + xe as u16), b_bits as u16) } else { 0 };
        let q: u32 = 1 << q_bits;
        let p: u16 = 1 << p_bits;
        
        // Message sizes
        let pk_size = (kappa_bytes as u16 + bits_to_bytes!(d * n_bar * p_bits as u16)) as u32;
        let ct_size: u16 = bits_to_bytes!(d * m_bar * p_bits as u16) + bits_to_bytes!(mu * t_bits as u16);

        // Rounding constants
        let z_bits = std::cmp::max(q_bits - p_bits + t_bits, p_bits) as u16;
        let h1: u16 = (1 as u16) << (q_bits - p_bits - 1);
        let h2: u16 = (1 as u16) << (q_bits - z_bits as u8 - 1);
        let h3: u16 = (1 << (p_bits - t_bits - 1)) as u16
                      + (1 << (p_bits - b_bits - 1)) as u16
                      - (1 << (q_bits - z_bits as u8 - 1)) as u16;
        
        //Tau
        let tau = if k == 1 { 0 } else { tau };
        let tau2_len = if tau2_len == 0 { 1 << 11 } else { tau2_len };

        let params = Parameters {
            name,
            c_sk, c_pk, c_b, c_ct,
            tau, tau2_len,
            d, n, h,
            q_bits, p_bits, t_bits, b_bits, z_bits,
            n_bar, m_bar,
            kappa_bytes,
            f, xe, kappa,
            k, q, p, mu,
            h1, h2, h3,
            pk_size, ct_size,
        };

        // n must be either d or 1 and both must be > 0
        assert!(params.n != 0 && params.d != 0 && (params.n == params.d || params.n == 1));
        // Hamming weight must be even, > 0, and < d
        assert!(params.h != 0 && params.h <= params.d && params.h & 1 == 0);
        // p, q, and t must be > 0 and power of 2
        // p must be < q
        // t must be < p
        assert!(params.q_bits > 0 && params.p_bits > 0 && params.t_bits > 0 && params.p_bits < params.q_bits && params.t_bits < params.p_bits);
        /* Dimensions must be > 0 */
        assert!(params.n_bar > 0 && params.m_bar > 0);
        // b must be > 0, < p
        assert!(params.b_bits > 0 && params.b_bits < params.p_bits);
        // Seed size must be > 0
        assert!(params.kappa_bytes > 0);
        // tau must be 0, 1, or 2 for non-ring, 0 for ring (but this is actually already enforced)
        assert!(params.tau <= 2 && (params.k != 1 || params.tau == 0));
        // For non-ring, tau2_len must be a power of two and larger than or equal to d
        assert!(params.k == 1 || (params.tau2_len >= params.d as u32 && (params.tau2_len & (params.tau2_len - 1)) == 0));

        params
    }
}