| 
 | 1 | +//! arithmetic mod q  | 
 | 2 | +
  | 
 | 3 | +use crate::{  | 
 | 4 | +    const_time::i32_mod_u14,  | 
 | 5 | +    params::{NtruCommon, NtruLRPrime},  | 
 | 6 | +};  | 
 | 7 | +use core::marker::PhantomData;  | 
 | 8 | +use core::ops::Deref;  | 
 | 9 | + | 
 | 10 | +/// always represented as `-F::Q12...F::Q12`  | 
 | 11 | +#[derive(Copy, Clone)]  | 
 | 12 | +pub struct Inner<Params> {  | 
 | 13 | +    inner: i16,  | 
 | 14 | +    marker: PhantomData<Params>,  | 
 | 15 | +}  | 
 | 16 | + | 
 | 17 | +impl<P> Default for Inner<P> {  | 
 | 18 | +    fn default() -> Self {  | 
 | 19 | +        Self {  | 
 | 20 | +            inner: 0,  | 
 | 21 | +            marker: PhantomData,  | 
 | 22 | +        }  | 
 | 23 | +    }  | 
 | 24 | +}  | 
 | 25 | +/// we need this type for the following reason, there is an expressivity  | 
 | 26 | +/// problem, that is `FqInner<T>` implements only `Clone` and `Copy` if  | 
 | 27 | +/// `T: Clone + Copy`. In this case, we do not require `T:  Clone + Copy`  | 
 | 28 | +/// So to bypass this we can:  | 
 | 29 | +/// A- manually implment Clone + Copy  | 
 | 30 | +/// B - Add Clone+Copy  a trait bounds for T  | 
 | 31 | +/// C - This trick which is saying that we use static reference to T which is always Clone + Copy  | 
 | 32 | +/// D - Use third party crates like derivatives.  | 
 | 33 | +pub type Fq<Params> = Inner<&'static Params>;  | 
 | 34 | + | 
 | 35 | +/// the benefit is from outside, anyone can access the inner value as number,  | 
 | 36 | +/// but no one can modify it without refreezing  | 
 | 37 | +impl<Params> Deref for Fq<Params> {  | 
 | 38 | +    type Target = i16;  | 
 | 39 | + | 
 | 40 | +    fn deref(&self) -> &Self::Target {  | 
 | 41 | +        &self.inner  | 
 | 42 | +    }  | 
 | 43 | +}  | 
 | 44 | +// TODO should we have `T: Clone + Copy` or should we specify  | 
 | 45 | +// trait bounds for the derive (either by manual  | 
 | 46 | +// implementation or via derivative)  | 
 | 47 | +impl<Params: NtruCommon> Fq<Params> {  | 
 | 48 | +    const Q12: u16 = ((Params::Q - 1) / 2);  | 
 | 49 | +    pub(super) fn new_i32(n: i32) -> Self {  | 
 | 50 | +        debug_assert!(n < Self::Q12 as i32);  | 
 | 51 | +        debug_assert!(n > -(Self::Q12 as i32));  | 
 | 52 | +        Fq {  | 
 | 53 | +            inner: n as i16,  | 
 | 54 | +            marker: PhantomData,  | 
 | 55 | +        }  | 
 | 56 | +    }  | 
 | 57 | +    pub(super) fn new_i16(n: i16) -> Self {  | 
 | 58 | +        debug_assert!(n < Self::Q12 as i16);  | 
 | 59 | +        debug_assert!(n > -(Self::Q12 as i16));  | 
 | 60 | +        Fq {  | 
 | 61 | +            inner: n,  | 
 | 62 | +            marker: PhantomData,  | 
 | 63 | +        }  | 
 | 64 | +    }  | 
 | 65 | + | 
 | 66 | +    pub(super) fn new_i8(n: i8) -> Self {  | 
 | 67 | +        let n = n as i16;  | 
 | 68 | +        debug_assert!(n < Self::Q12 as i16);  | 
 | 69 | +        debug_assert!(n > -(Self::Q12 as i16));  | 
 | 70 | +        Fq {  | 
 | 71 | +            inner: n,  | 
 | 72 | +            marker: PhantomData,  | 
 | 73 | +        }  | 
 | 74 | +    }  | 
 | 75 | + | 
 | 76 | +    /// x must not be close to top int32  | 
 | 77 | +    #[must_use]  | 
 | 78 | +    pub const fn freeze(x: i32) -> Self {  | 
 | 79 | +        debug_assert!(x <= i32::MAX - Self::Q12 as i32);  | 
 | 80 | +        Fq {  | 
 | 81 | +            inner: i32_mod_u14(x + Self::Q12 as i32, Params::Q).wrapping_sub(Self::Q12) as i16,  | 
 | 82 | +            marker: PhantomData,  | 
 | 83 | +        }  | 
 | 84 | +    }  | 
 | 85 | +    /// caclucates the multiplicative inverse of a1  | 
 | 86 | +    /// a1 must not be zero  | 
 | 87 | +    #[must_use]  | 
 | 88 | +    pub const fn recip(a1: Self) -> Self {  | 
 | 89 | +        debug_assert!(a1.inner != 0);  | 
 | 90 | +        let mut i = 1;  | 
 | 91 | +        let mut ai = a1;  | 
 | 92 | +        while i < Params::Q - 2 {  | 
 | 93 | +            // we have to use `a1.0` instead of deref to maintian  | 
 | 94 | +            // the const status of the function  | 
 | 95 | +            ai = Fq::freeze(a1.inner as i32 * ai.inner as i32);  | 
 | 96 | +            i += 1;  | 
 | 97 | +        }  | 
 | 98 | +        ai  | 
 | 99 | +    }  | 
 | 100 | +}  | 
 | 101 | + | 
 | 102 | +///TODO tests for both funtions  | 
 | 103 | +impl<Params: NtruLRPrime + NtruCommon> Fq<Params> {  | 
 | 104 | +    #[must_use]  | 
 | 105 | +    pub const fn top(self) -> i8 {  | 
 | 106 | +        ((Params::TAU1 * (self.inner + Params::TAU0) as i32 + 16384) >> 15) as i8  | 
 | 107 | +    }  | 
 | 108 | +    #[must_use]  | 
 | 109 | +    pub const fn right(t: i8) -> Self {  | 
 | 110 | +        Fq::freeze(Params::TAU3 * t as i32 - Params::TAU2)  | 
 | 111 | +    }  | 
 | 112 | +}  | 
 | 113 | + | 
 | 114 | +#[cfg(test)]  | 
 | 115 | +mod test {  | 
 | 116 | +    use super::Fq;  | 
 | 117 | +    use crate::params::*;  | 
 | 118 | +    use rayon::prelude::*;  | 
 | 119 | +    use std::io::{stdout, Write};  | 
 | 120 | + | 
 | 121 | +    fn naive_freeze(x: i32, q: u16) -> i16 {  | 
 | 122 | +        let res = (x % (q as i32)) as i16;  | 
 | 123 | +        if res > ((q as i16 - 1) / 2) {  | 
 | 124 | +            return res - q as i16;  | 
 | 125 | +        }  | 
 | 126 | +        if res < -((q as i16 - 1) / 2) {  | 
 | 127 | +            return res + q as i16;  | 
 | 128 | +        }  | 
 | 129 | +        res  | 
 | 130 | +    }  | 
 | 131 | +    #[test]  | 
 | 132 | +    #[ignore = "Expected to take ~ 1 hour to finish on single core"]  | 
 | 133 | +    fn test_fq_freezer() {  | 
 | 134 | +        // if i is close to i32::Max we overflow and crash  | 
 | 135 | +        // we also need to chunk things a bit  | 
 | 136 | +        (i32::MIN..i32::MAX - S1277::Q as i32)  | 
 | 137 | +            .into_par_iter()  | 
 | 138 | +            .chunks(0xffffff)  | 
 | 139 | +            .for_each(|chunk| {  | 
 | 140 | +                print!(".");  | 
 | 141 | +                stdout().flush().unwrap();  | 
 | 142 | +                for i in chunk {  | 
 | 143 | +                    // all viable Q values from section 3.4 of NTRU NIST submission  | 
 | 144 | +                    assert_eq!(*Fq::<S653>::freeze(i), naive_freeze(i, S653::Q));  | 
 | 145 | +                    assert_eq!(*Fq::<S761>::freeze(i), naive_freeze(i, S761::Q));  | 
 | 146 | +                    assert_eq!(*Fq::<S857>::freeze(i), naive_freeze(i, S857::Q));  | 
 | 147 | +                    assert_eq!(*Fq::<S953>::freeze(i), naive_freeze(i, S953::Q));  | 
 | 148 | +                    assert_eq!(*Fq::<S1013>::freeze(i), naive_freeze(i, S1013::Q));  | 
 | 149 | +                    assert_eq!(*Fq::<S1277>::freeze(i), naive_freeze(i, S1277::Q));  | 
 | 150 | +                }  | 
 | 151 | +            })  | 
 | 152 | +    }  | 
 | 153 | +    #[test]  | 
 | 154 | +    fn test_f_s653_recip() {  | 
 | 155 | +        // note that zero has no recip, so we skip zero  | 
 | 156 | +        for i in (-(Fq::<S653>::Q12 as i32)..0).chain(1..Fq::<S653>::Q12 as i32) {  | 
 | 157 | +            assert_eq!(  | 
 | 158 | +                *Fq::<S653>::freeze(i * *Fq::<S653>::recip(Fq::<S653>::freeze(i)) as i32),  | 
 | 159 | +                1  | 
 | 160 | +            )  | 
 | 161 | +        }  | 
 | 162 | +    }  | 
 | 163 | +    #[test]  | 
 | 164 | +    fn test_f_s761_recip() {  | 
 | 165 | +        // note that zero has no recip, so we skip zero  | 
 | 166 | +        for i in (-(Fq::<S761>::Q12 as i32)..0).chain(1..Fq::<S761>::Q12 as i32) {  | 
 | 167 | +            assert_eq!(  | 
 | 168 | +                *Fq::<S761>::freeze(i * *Fq::<S761>::recip(Fq::<S761>::freeze(i)) as i32),  | 
 | 169 | +                1  | 
 | 170 | +            )  | 
 | 171 | +        }  | 
 | 172 | +    }  | 
 | 173 | +    #[test]  | 
 | 174 | +    fn test_f_s857_recip() {  | 
 | 175 | +        // note that zero has no recip, so we skip zero  | 
 | 176 | +        for i in (-(Fq::<S857>::Q12 as i32)..0).chain(1..Fq::<S857>::Q12 as i32) {  | 
 | 177 | +            assert_eq!(  | 
 | 178 | +                *Fq::<S857>::freeze(i * *Fq::<S857>::recip(Fq::<S857>::freeze(i)) as i32),  | 
 | 179 | +                1  | 
 | 180 | +            )  | 
 | 181 | +        }  | 
 | 182 | +    }  | 
 | 183 | +    #[test]  | 
 | 184 | +    fn test_f_s953_recip() {  | 
 | 185 | +        // note that zero has no recip, so we skip zero  | 
 | 186 | +        for i in (-(Fq::<S953>::Q12 as i32)..0).chain(1..Fq::<S953>::Q12 as i32) {  | 
 | 187 | +            assert_eq!(  | 
 | 188 | +                *Fq::<S953>::freeze(i * *Fq::<S953>::recip(Fq::<S953>::freeze(i)) as i32),  | 
 | 189 | +                1  | 
 | 190 | +            )  | 
 | 191 | +        }  | 
 | 192 | +    }  | 
 | 193 | +    #[test]  | 
 | 194 | +    fn test_f_s1013_recip() {  | 
 | 195 | +        // note that zero has no recip, so we skip zero  | 
 | 196 | +        for i in (-(Fq::<S1013>::Q12 as i32)..0).chain(1..Fq::<S1013>::Q12 as i32) {  | 
 | 197 | +            assert_eq!(  | 
 | 198 | +                *Fq::<S1013>::freeze(i * *Fq::<S1013>::recip(Fq::<S1013>::freeze(i)) as i32),  | 
 | 199 | +                1  | 
 | 200 | +            )  | 
 | 201 | +        }  | 
 | 202 | +    }  | 
 | 203 | +    #[test]  | 
 | 204 | +    fn test_f_s1277_recip() {  | 
 | 205 | +        // note that zero has no recip, so we skip zero  | 
 | 206 | +        for i in (-(Fq::<S1277>::Q12 as i32)..0).chain(1..Fq::<S1277>::Q12 as i32) {  | 
 | 207 | +            assert_eq!(  | 
 | 208 | +                *Fq::<S1277>::freeze(i * *Fq::<S1277>::recip(Fq::<S1277>::freeze(i)) as i32),  | 
 | 209 | +                1  | 
 | 210 | +            )  | 
 | 211 | +        }  | 
 | 212 | +    }  | 
 | 213 | +}  | 
0 commit comments