1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Noise formulas for the gsw-sample related operations
//! Those functions will be used in the gsw tests to check that
//! the noise behavior is consistent with the theory.

pub trait GSW: Sized {
    type STorus;
    fn external_product(
        dimension: usize,
        l_gadget: usize,
        base_log: usize,
        var_gsw: f64,
        var_lwe: f64,
    ) -> f64;

    fn cmux(
        var_lwe_0: f64,
        var_lwe_1: f64,
        var_gsw: f64,
        dimension: usize,
        base_log: usize,
        l_gadget: usize,
    ) -> f64;
}

macro_rules! impl_trait_npe_gsw {
    ($T:ty,$S:ty,$DOC:expr) => {
        impl GSW for $T {
            type STorus = $S;
            /// Return the variance of the external product given a set of parameters.
            /// To see how to use it, please refer to the test of the external product.
            /// Arguments
            /// * `dimension` - the size of the LWE mask
            /// * `l_gadget` - number of elements for the Torus decomposition
            /// * `base_log` - decomposition base of the gadget matrix
            /// * `var_gsw` - noise variance of the GSW
            /// * `var_lwe` - noise variance of the LWE
            /// # Output
            /// * Returns the variance of the output LWE
            /// # Warning
            /// * only correct for the external product inside a cmux
            /// # Example
            /// ```rust
            /// use concrete_npe::GSW ;
            #[doc = $DOC]
            /// // settings
            /// let dimension: usize = 256 ;
            /// let l_gadget: usize = 4 ;
            /// let base_log: usize = 7 ;
            /// let var_gsw: f64 = f64::powi(2., -38) ;
            /// let var_lwe: f64 = f64::powi(2., -40) ;
            /// // Computing the noise
            /// let var_external_product = <Torus as GSW>::external_product(dimension, l_gadget,
            /// base_log, var_gsw, var_lwe) ;
            /// ```
            fn external_product(
                dimension: usize,
                l_gadget: usize,
                base_log: usize,
                var_gsw: f64,
                var_lwe: f64,
            ) -> f64 {
                // norm 2 of the integer hidden in the GSW
                // for an external product inside a cmux,
                // the integer is equal to 0 or 1
                let norm_2_msg_gsw = 1.;
                let b_g = 1 << base_log;
                let q_square = f64::powi(2., (2 * std::mem::size_of::<$T>() * 8) as i32);
                let res_1: f64 =
                    ((dimension + 1) * l_gadget * (b_g * b_g + 2)) as f64 / 12. * var_gsw;

                let res_2: f64 = norm_2_msg_gsw
                    * ((dimension + 2) as f64
                        / (24. * f64::powi(b_g as f64, 2 * l_gadget as i32)) as f64
                        + (dimension / 48 - 1 / 12) as f64 / q_square);

                let res_3: f64 = norm_2_msg_gsw * var_lwe;
                let res: f64 = res_1 + res_2 + res_3;
                return res;
            }

            /// Return the variance of the cmux given a set of parameters.
            /// To see how to use it, please refer to the test of the cmux.
            /// Arguments
            /// * `var_lwe_0` - noise variance of the first LWE
            /// * `var_lwe_1` - noise variance of the second LWE
            /// * `var_gsw` - noise variance of the GSW
            /// * `dimension` - the size of the LWE mask
            /// * `base_log` - decomposition base of the gadget matrix
            /// * `l_gadget` - number of elements for the Torus decomposition
            /// # Output
            /// * Returns the variance of the output LWE
            /// # Example
            /// ```rust
            /// use concrete_npe::GSW ;
            #[doc = $DOC]
            /// // settings
            /// let dimension: usize = 256 ;
            /// let l_gadget: usize = 4 ;
            /// let base_log: usize = 7 ;
            /// let var_gsw: f64 = f64::powi(2., -38) ;
            /// let var_lwe_0: f64 = f64::powi(2., -40) ;
            /// let var_lwe_1: f64 = f64::powi(2., -40) ;
            /// // Computing the noise
            /// let var_cmux = <Torus as GSW>::cmux(var_lwe_0, var_lwe_1, var_gsw,
            /// dimension, base_log, l_gadget) ;
            /// ```
            fn cmux(
                var_lwe_0: f64,
                var_lwe_1: f64,
                var_gsw: f64,
                dimension: usize,
                base_log: usize,
                l_gadget: usize,
            ) -> f64 {
                let var_external_product = Self::external_product(
                    dimension,
                    l_gadget,
                    base_log,
                    var_gsw,
                    crate::add_ciphertexts(var_lwe_0, var_lwe_1),
                );
                let var_cmux = crate::add_ciphertexts(var_external_product, var_lwe_0);
                return var_cmux;
            }
        }
    };
}

impl_trait_npe_gsw!(u32, i32, "type Torus = u32;");
impl_trait_npe_gsw!(u64, i64, "type Torus = u64;");