use super::keyswitch_one_bit::variance_keyswitch_one_bit;

/// Additional noise generated by the keyswitch step.
pub fn variance_keyswitch(
    input_lwe_dimension: u64, //n_big
    log2_base: u64,
    level: u64,
    ciphertext_modulus_log: u32,
    variance_ksk: f64,
) -> f64 {
    input_lwe_dimension as f64
        * variance_keyswitch_one_bit(log2_base, level, ciphertext_modulus_log, variance_ksk)
}

#[cfg(test)]
mod tests {

    use concrete_security_curves::gaussian::security::minimal_variance_lwe;

    use crate::gaussian_noise::conversion::variance_to_modular_variance;

    use super::*;

    #[test]
    fn golden_python_prototype_security_variance_keyswitch_1() {
        let golden_modular_variance = 5.997_880_135_602_194e68;
        let internal_ks_output_lwe_dimension = 1024;
        let ciphertext_modulus_log = 128;
        let security = 128;

        let actual = variance_keyswitch(
            4096,
            5,
            9,
            ciphertext_modulus_log,
            minimal_variance_lwe(
                internal_ks_output_lwe_dimension,
                ciphertext_modulus_log,
                security,
            ),
        );

        approx::assert_relative_eq!(
            variance_to_modular_variance(actual, ciphertext_modulus_log),
            golden_modular_variance,
            max_relative = 1e-8
        );
    }

    #[test]
    fn golden_python_prototype_security_variance_keyswitch_2() {
        // let golden_modular_variance = 8.580795457940938e+66;
        // the full npe implements a part of the full estimation
        let golden_modular_variance = 7.407_691_550_271_225e48; // full estimation
        let internal_ks_output_lwe_dimension = 512;
        let ciphertext_modulus_log = 64;
        let security = 128;

        let actual = variance_keyswitch(
            2048,
            24,
            2,
            ciphertext_modulus_log,
            minimal_variance_lwe(
                internal_ks_output_lwe_dimension,
                ciphertext_modulus_log,
                security,
            ),
        );

        approx::assert_relative_eq!(
            variance_to_modular_variance(actual, ciphertext_modulus_log),
            golden_modular_variance,
            max_relative = 1e-8
        );
    }
}
