arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/math/tests/automorphism.rs
math/tests/automorphism.rsRaw
  1use itertools::izip;
  2use math::modulus::WordOps;
  3use math::poly::Poly;
  4use math::ring::impl_u64::packing::StreamRepacker;
  5use math::ring::Ring;
  6
  7#[test]
  8fn automorphism_u64() {
  9    let n: usize = 1 << 4;
 10    let nth_root: usize = n << 1;
 11    let q_base: u64 = 65537u64;
 12    let q_power: usize = 1usize;
 13    let ring: Ring<u64> = Ring::new(n, q_base, q_power);
 14
 15    sub_test("test_automorphism_u64::<NTT:false>", || {
 16        test_automorphism_u64::<false>(&ring, nth_root)
 17    });
 18    sub_test("test_automorphism_u64::<NTT:true>", || {
 19        test_automorphism_u64::<true>(&ring, nth_root)
 20    });
 21}
 22
 23fn sub_test<F: FnOnce()>(name: &str, f: F) {
 24    println!("Running {}", name);
 25    f();
 26}
 27
 28fn test_automorphism_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
 29    let n: usize = ring.n();
 30    let q: u64 = ring.modulus.q;
 31
 32    let mut p0: Poly<u64> = ring.new_poly();
 33    let mut p1: Poly<u64> = ring.new_poly();
 34
 35    for i in 0..p0.n() {
 36        p0.0[i] = i as u64
 37    }
 38
 39    if NTT {
 40        ring.ntt_inplace::<false>(&mut p0);
 41    }
 42
 43    ring.a_apply_automorphism_into_b::<NTT>(&p0, 2 * n - 1, nth_root, &mut p1);
 44
 45    if NTT {
 46        ring.intt_inplace::<false>(&mut p1);
 47    }
 48
 49    p0.0[0] = 0;
 50    for i in 1..p0.n() {
 51        p0.0[i] = q - (n - i) as u64
 52    }
 53
 54    izip!(p0.0, p1.0).for_each(|(a, b)| assert_eq!(a, b));
 55}
 56
 57#[test]
 58fn packing_u64() {
 59    let n: usize = 1 << 5;
 60    let q_base: u64 = 65537u64;
 61    let q_power: usize = 1usize;
 62    let ring: Ring<u64> = Ring::new(n, q_base, q_power);
 63
 64    sub_test("test_packing_u64::<NTT:false>", || {
 65        test_packing_full_u64::<false>(&ring)
 66    });
 67    sub_test("test_packing_u64::<NTT:true>", || {
 68        test_packing_full_u64::<true>(&ring)
 69    });
 70    sub_test("test_packing_sparse_u64::<NTT:false>", || {
 71        test_packing_sparse_u64::<false>(&ring)
 72    });
 73    sub_test("test_packing_sparse_u64::<NTT:true>", || {
 74        test_packing_sparse_u64::<true>(&ring)
 75    });
 76}
 77
 78fn test_packing_full_u64<const NTT: bool>(ring: &Ring<u64>) {
 79    let n: usize = ring.n();
 80
 81    let mut result: Vec<Option<Poly<u64>>> = vec![None; n];
 82
 83    for i in 0..n {
 84        let mut poly: Poly<u64> = ring.new_poly();
 85        poly.fill(&(1 + i as u64));
 86        if NTT {
 87            ring.ntt_inplace::<false>(&mut poly);
 88        }
 89
 90        result[i] = Some(poly);
 91    }
 92
 93    ring.pack::<true, NTT>(&mut result, ring.log_n());
 94
 95    if let Some(poly) = result[0].as_mut() {
 96        if NTT {
 97            ring.intt_inplace::<false>(poly);
 98        }
 99
100        poly.0
101            .iter()
102            .enumerate()
103            .for_each(|(i, x)| assert_eq!(*x, 1 + i as u64));
104    }
105}
106
107fn test_packing_sparse_u64<const NTT: bool>(ring: &Ring<u64>) {
108    let n: usize = ring.n();
109
110    let mut result: Vec<Option<Poly<u64>>> = vec![None; n];
111
112    let gap: usize = 3;
113
114    for i in (0..n).step_by(gap) {
115        let mut poly: Poly<u64> = ring.new_poly();
116        poly.fill(&(1 + i as u64));
117        if NTT {
118            ring.ntt_inplace::<false>(&mut poly);
119        }
120        result[i] = Some(poly);
121    }
122
123    ring.pack::<true, NTT>(&mut result, ring.log_n());
124
125    if let Some(poly) = result[0].as_mut() {
126        if NTT {
127            ring.intt_inplace::<false>(poly);
128        }
129
130        poly.0.iter().enumerate().for_each(|(i, x)| {
131            if i % gap == 0 {
132                assert_eq!(*x, 1 + i as u64)
133            } else {
134                assert_eq!(*x, 0u64)
135            }
136        });
137    }
138}
139
140#[test]
141fn packing_streaming_u64() {
142    let n: usize = 1 << 5;
143    let q_base: u64 = 65537u64;
144    let q_power: usize = 1usize;
145    let ring: Ring<u64> = Ring::new(n, q_base, q_power);
146
147    sub_test("test_packing_streaming_dense_u64::<NTT:true>", || {
148        test_packing_streaming_dense_u64::<true>(&ring)
149    });
150}
151
152fn test_packing_streaming_dense_u64<const NTT: bool>(ring: &Ring<u64>) {
153    let n: usize = ring.n();
154
155    let mut values: Vec<u64> = vec![0; n];
156    values
157        .iter_mut()
158        .enumerate()
159        .for_each(|(i, x)| *x = (i + 1) as u64);
160
161    let gap: usize = 3;
162
163    let mut packer = StreamRepacker::new(ring);
164
165    let mut poly: Poly<u64> = ring.new_poly();
166    for i in 0..n {
167        let i_rev: usize = i.reverse_bits_msb(ring.log_n() as u32);
168
169        if i_rev % gap == 0 {
170            poly.fill(&values[i_rev]);
171            if NTT {
172                ring.ntt_inplace::<false>(&mut poly);
173            }
174            packer.add::<NTT>(ring, Some(&poly))
175        } else {
176            packer.add::<NTT>(ring, None)
177        }
178    }
179
180    packer.flush::<NTT>(ring);
181
182    let result: &mut Poly<u64> = &mut packer.results[0];
183
184    if NTT {
185        ring.intt_inplace::<false>(result);
186    }
187
188    result.0.iter().enumerate().for_each(|(i, x)| {
189        if i % gap == 0 {
190            assert_eq!(*x, values[i] as u64)
191        } else {
192            assert_eq!(*x, 0u64)
193        }
194    });
195}
196
197#[test]
198fn trace_u64() {
199    let n: usize = 1 << 5;
200    let q_base: u64 = 65537u64;
201    let q_power: usize = 1usize;
202    let ring: Ring<u64> = Ring::new(n, q_base, q_power);
203
204    sub_test("test_trace::<NTT:false>", || test_trace_u64::<false>(&ring));
205    sub_test("test_trace::<NTT:true>", || test_trace_u64::<true>(&ring));
206}
207
208fn test_trace_u64<const NTT: bool>(ring: &Ring<u64>) {
209    let n: usize = ring.n();
210
211    let mut poly: Poly<u64> = ring.new_poly();
212
213    poly.0
214        .iter_mut()
215        .enumerate()
216        .for_each(|(i, x)| *x = (i + 1) as u64);
217
218    if NTT {
219        ring.ntt_inplace::<false>(&mut poly);
220    }
221
222    let step_start: usize = 2;
223
224    ring.trace_inplace::<NTT>(step_start, &mut poly);
225
226    if NTT {
227        ring.intt_inplace::<false>(&mut poly);
228    }
229
230    let gap: usize = 1 << (ring.log_n() - step_start);
231
232    poly.0.iter().enumerate().for_each(|(i, x)| {
233        if i % gap == 0 {
234            assert_eq!(*x, 1 + i as u64)
235        } else {
236            assert_eq!(*x, 0u64)
237        }
238    });
239}