arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/math/tests/rescaling_rns.rs
math/tests/rescaling_rns.rsRaw
  1use math::poly::PolyRNS;
  2use math::ring::RingRNS;
  3use num_bigint::BigInt;
  4use num_bigint::Sign;
  5use sampling::source::Source;
  6
  7#[test]
  8fn rescaling_rns_u64() {
  9    let n = 1 << 10;
 10    let moduli: Vec<u64> = vec![0x1fffffffffc80001u64, 0x1fffffffffe00001u64, 0x1fffffffffb40001, 0x1fffffffff500001];
 11    let ring_rns: RingRNS<u64> = RingRNS::new(n, moduli);
 12
 13    //test_div_floor_by_last_modulus::<false>(&ring_rns);
 14    //test_div_floor_by_last_modulus::<true>(&ring_rns);
 15    test_div_floor_by_last_modulus_inplace::<false>(&ring_rns);
 16    //test_div_floor_by_last_modulus_inplace::<true>(&ring_rns);
 17    //test_div_floor_by_last_moduli::<false>(&ring_rns);
 18    //test_div_floor_by_last_moduli::<true>(&ring_rns);
 19    //test_div_floor_by_last_moduli_inplace::<false>(&ring_rns);
 20    //test_div_floor_by_last_moduli_inplace::<true>(&ring_rns);
 21}
 22
 23fn test_div_floor_by_last_modulus<const NTT: bool>(ring_rns: &RingRNS<u64>) {
 24    let seed: [u8; 32] = [0; 32];
 25    let mut source: Source = Source::new(seed);
 26
 27    let mut a: PolyRNS<u64> = ring_rns.new_polyrns();
 28    let mut b: PolyRNS<u64> = ring_rns.new_polyrns();
 29    let mut c: PolyRNS<u64> = ring_rns.at_level(ring_rns.level() - 1).new_polyrns();
 30
 31    // Allocates a random PolyRNS
 32    ring_rns.fill_uniform(&mut source, &mut a);
 33
 34    // Maps PolyRNS to [BigInt]
 35    let mut coeffs_a: Vec<BigInt> = (0..a.n()).map(|i| BigInt::from(i)).collect();
 36    ring_rns
 37        .at_level(a.level())
 38        .to_bigint_inplace(&a, 1, &mut coeffs_a);
 39
 40    // Performs c = intt(ntt(a) / q_level)
 41    if NTT {
 42        ring_rns.ntt_inplace::<false>(&mut a);
 43    }
 44
 45    ring_rns.div_floor_by_last_modulus::<NTT>(&a, &mut b, &mut c);
 46
 47    if NTT {
 48        ring_rns.at_level(c.level()).intt_inplace::<false>(&mut c);
 49    }
 50
 51    // Exports c to coeffs_c
 52    let mut coeffs_c = vec![BigInt::from(0); c.n()];
 53    ring_rns
 54        .at_level(c.level())
 55        .to_bigint_inplace(&c, 1, &mut coeffs_c);
 56
 57    // Performs floor division on a
 58    let scalar_big = BigInt::from(ring_rns.0[ring_rns.level()].modulus.q);
 59    coeffs_a.iter_mut().for_each(|a| {
 60        // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1]
 61        *a /= &scalar_big;
 62        if a.sign() == Sign::Minus {
 63            *a -= 1;
 64        }
 65    });
 66
 67    assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_modulus");
 68}
 69
 70fn test_div_floor_by_last_modulus_inplace<const NTT: bool>(ring_rns: &RingRNS<u64>) {
 71    let seed: [u8; 32] = [0; 32];
 72    let mut source: Source = Source::new(seed);
 73
 74    let mut a: PolyRNS<u64> = ring_rns.new_polyrns();
 75    let mut b: PolyRNS<u64> = ring_rns.new_polyrns();
 76
 77    // Allocates a random PolyRNS
 78    ring_rns.fill_uniform(&mut source, &mut a);
 79
 80    // Maps PolyRNS to [BigInt]
 81    let mut coeffs_a: Vec<BigInt> = (0..a.n()).map(|i| BigInt::from(i)).collect();
 82    ring_rns
 83        .at_level(a.level())
 84        .to_bigint_inplace(&a, 1, &mut coeffs_a);
 85
 86        println!("{:?}", &coeffs_a[..8]);
 87
 88    // Performs c = intt(ntt(a) / q_level)
 89    if NTT {
 90        ring_rns.ntt_inplace::<false>(&mut a);
 91    }
 92
 93    ring_rns.div_floor_by_last_modulus_inplace::<NTT>(&mut b, &mut a);
 94
 95    if NTT {
 96        ring_rns.at_level(a.level()-1).intt_inplace::<false>(&mut a);
 97    }
 98
 99    // Exports c to coeffs_c
100    let mut coeffs_c = vec![BigInt::from(0); a.n()];
101    ring_rns
102        .at_level(a.level()-1)
103        .to_bigint_inplace(&a, 1, &mut coeffs_c);
104
105    // Performs floor division on a
106    let scalar_big = BigInt::from(ring_rns.0[ring_rns.level()].modulus.q);
107    coeffs_a.iter_mut().for_each(|a| {
108        // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1]
109        *a /= &scalar_big;
110        if a.sign() == Sign::Minus {
111            *a -= 1;
112        }
113    });
114
115    println!("{:?}", &coeffs_a[..8]);
116    println!("{:?}", &coeffs_c[..8]);
117
118    assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_modulus_inplace");
119}
120
121fn test_div_floor_by_last_moduli<const NTT: bool>(ring_rns: &RingRNS<u64>) {
122    let seed: [u8; 32] = [0; 32];
123    let mut source: Source = Source::new(seed);
124
125    let nb_moduli: usize = ring_rns.level()-1;
126
127    let mut a: PolyRNS<u64> = ring_rns.new_polyrns();
128    let mut b: PolyRNS<u64> = ring_rns.new_polyrns();
129    let mut c: PolyRNS<u64> = ring_rns.at_level(ring_rns.level() - 1).new_polyrns();
130
131    // Allocates a random PolyRNS
132    ring_rns.fill_uniform(&mut source, &mut a);
133
134    // Maps PolyRNS to [BigInt]
135    let mut coeffs_a: Vec<BigInt> = (0..a.n()).map(|i| BigInt::from(i)).collect();
136    ring_rns
137        .at_level(a.level())
138        .to_bigint_inplace(&a, 1, &mut coeffs_a);
139
140    // Performs c = intt(ntt(a) / q_level)
141    if NTT {
142        ring_rns.ntt_inplace::<false>(&mut a);
143    }
144
145    ring_rns.div_floor_by_last_moduli::<NTT>(nb_moduli, &a, &mut b, &mut c);
146
147    if NTT {
148        ring_rns.at_level(c.level()).intt_inplace::<false>(&mut c);
149    }
150
151    // Exports c to coeffs_c
152    let mut coeffs_c = vec![BigInt::from(0); c.n()];
153    ring_rns
154        .at_level(c.level())
155        .to_bigint_inplace(&c, 1, &mut coeffs_c);
156
157    // Performs floor division on a
158    let mut scalar_big = BigInt::from(1);
159    (0..nb_moduli).for_each(|i|{scalar_big *= BigInt::from(ring_rns.0[ring_rns.level()].modulus.q)});
160    coeffs_a.iter_mut().for_each(|a| {
161        // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1]
162        *a /= &scalar_big;
163        if a.sign() == Sign::Minus {
164            *a -= 1;
165        }
166    });
167
168    assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_moduli");
169}
170
171fn test_div_floor_by_last_moduli_inplace<const NTT: bool>(ring_rns: &RingRNS<u64>) {
172    let seed: [u8; 32] = [0; 32];
173    let mut source: Source = Source::new(seed);
174
175    let nb_moduli: usize = ring_rns.level()-1;
176
177    let mut a: PolyRNS<u64> = ring_rns.new_polyrns();
178    let mut b: PolyRNS<u64> = ring_rns.new_polyrns();
179
180    // Allocates a random PolyRNS
181    ring_rns.fill_uniform(&mut source, &mut a);
182
183    // Maps PolyRNS to [BigInt]
184    let mut coeffs_a: Vec<BigInt> = (0..a.n()).map(|i| BigInt::from(i)).collect();
185    ring_rns
186        .at_level(a.level())
187        .to_bigint_inplace(&a, 1, &mut coeffs_a);
188
189    // Performs c = intt(ntt(a) / q_level)
190    if NTT {
191        ring_rns.ntt_inplace::<false>(&mut a);
192    }
193
194    ring_rns.div_floor_by_last_moduli_inplace::<NTT>(nb_moduli, &mut b, &mut a);
195
196    if NTT {
197        ring_rns.at_level(a.level()-nb_moduli).intt_inplace::<false>(&mut a);
198    }
199
200    // Exports c to coeffs_c
201    let mut coeffs_c = vec![BigInt::from(0); a.n()];
202    ring_rns
203        .at_level(a.level()-nb_moduli)
204        .to_bigint_inplace(&a, 1, &mut coeffs_c);
205
206    // Performs floor division on a
207    let mut scalar_big = BigInt::from(1);
208    (0..nb_moduli).for_each(|i|{scalar_big *= BigInt::from(ring_rns.0[ring_rns.level()].modulus.q)});
209    coeffs_a.iter_mut().for_each(|a| {
210        // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1]
211        *a /= &scalar_big;
212        if a.sign() == Sign::Minus {
213            *a -= 1;
214        }
215    });
216
217    assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_moduli_inplace");
218}