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