arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/test_fft64/automorphism_key.rs
core/src/test_fft64/automorphism_key.rsRaw
  1use backend::{FFT64, Module, ScalarZnxOps, ScratchOwned, Stats, VecZnxOps};
  2use sampling::source::Source;
  3
  4use crate::{
  5    automorphism::AutomorphismKey,
  6    elem::{GetRow, Infos},
  7    glwe_ciphertext_fourier::GLWECiphertextFourier,
  8    glwe_plaintext::GLWEPlaintext,
  9    keys::{SecretKey, SecretKeyFourier},
 10    test_fft64::gglwe::log2_std_noise_gglwe_product,
 11};
 12
 13#[test]
 14fn automorphism() {
 15    (1..4).for_each(|rank| {
 16        println!("test automorphism rank: {}", rank);
 17        test_automorphism(-1, 5, 12, 12, 60, 3.2, rank);
 18    });
 19}
 20
 21#[test]
 22fn automorphism_inplace() {
 23    (1..4).for_each(|rank| {
 24        println!("test automorphism_inplace rank: {}", rank);
 25        test_automorphism_inplace(-1, 5, 12, 12, 60, 3.2, rank);
 26    });
 27}
 28
 29fn test_automorphism(p0: i64, p1: i64, log_n: usize, basek: usize, k_ksk: usize, sigma: f64, rank: usize) {
 30    let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
 31    let rows = (k_ksk + basek - 1) / basek;
 32
 33    let mut auto_key_in: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, rank);
 34    let mut auto_key_out: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, rank);
 35    let mut auto_key_apply: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, rank);
 36
 37    let mut source_xs: Source = Source::new([0u8; 32]);
 38    let mut source_xe: Source = Source::new([0u8; 32]);
 39    let mut source_xa: Source = Source::new([0u8; 32]);
 40
 41    let mut scratch: ScratchOwned = ScratchOwned::new(
 42        AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank)
 43            | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ksk)
 44            | AutomorphismKey::automorphism_scratch_space(&module, basek, k_ksk, k_ksk, k_ksk, rank),
 45    );
 46
 47    let mut sk: SecretKey<Vec<u8>> = SecretKey::alloc(&module, rank);
 48    sk.fill_ternary_prob(0.5, &mut source_xs);
 49
 50    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::alloc(&module, rank);
 51    sk_dft.dft(&module, &sk);
 52
 53    // gglwe_{s1}(s0) = s0 -> s1
 54    auto_key_in.generate_from_sk(
 55        &module,
 56        p0,
 57        &sk,
 58        &mut source_xa,
 59        &mut source_xe,
 60        sigma,
 61        scratch.borrow(),
 62    );
 63
 64    // gglwe_{s2}(s1) -> s1 -> s2
 65    auto_key_apply.generate_from_sk(
 66        &module,
 67        p1,
 68        &sk,
 69        &mut source_xa,
 70        &mut source_xe,
 71        sigma,
 72        scratch.borrow(),
 73    );
 74
 75    // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
 76    auto_key_out.automorphism(&module, &auto_key_in, &auto_key_apply, scratch.borrow());
 77
 78    let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ksk, rank);
 79    let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ksk);
 80
 81    let mut sk_auto: SecretKey<Vec<u8>> = SecretKey::alloc(&module, rank);
 82    sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
 83    (0..rank).for_each(|i| {
 84        module.scalar_znx_automorphism(
 85            module.galois_element_inv(p0 * p1),
 86            &mut sk_auto.data,
 87            i,
 88            &sk.data,
 89            i,
 90        );
 91    });
 92
 93    let mut sk_auto_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::alloc(&module, rank);
 94    sk_auto_dft.dft(&module, &sk_auto);
 95
 96    (0..auto_key_out.rank_in()).for_each(|col_i| {
 97        (0..auto_key_out.rows()).for_each(|row_i| {
 98            auto_key_out.get_row(&module, row_i, col_i, &mut ct_glwe_dft);
 99
100            ct_glwe_dft.decrypt(&module, &mut pt, &sk_auto_dft, scratch.borrow());
101            module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk.data, col_i);
102
103            let noise_have: f64 = pt.data.std(0, basek).log2();
104            let noise_want: f64 = log2_std_noise_gglwe_product(
105                module.n() as f64,
106                basek,
107                0.5,
108                0.5,
109                0f64,
110                sigma * sigma,
111                0f64,
112                rank as f64,
113                k_ksk,
114                k_ksk,
115            );
116
117            assert!(
118                (noise_have - noise_want).abs() <= 0.1,
119                "{} {}",
120                noise_have,
121                noise_want
122            );
123        });
124    });
125}
126
127fn test_automorphism_inplace(p0: i64, p1: i64, log_n: usize, basek: usize, k_ksk: usize, sigma: f64, rank: usize) {
128    let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
129    let rows: usize = (k_ksk + basek - 1) / basek;
130
131    let mut auto_key: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, rank);
132    let mut auto_key_apply: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, rank);
133
134    let mut source_xs: Source = Source::new([0u8; 32]);
135    let mut source_xe: Source = Source::new([0u8; 32]);
136    let mut source_xa: Source = Source::new([0u8; 32]);
137
138    let mut scratch: ScratchOwned = ScratchOwned::new(
139        AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank)
140            | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ksk)
141            | AutomorphismKey::automorphism_inplace_scratch_space(&module, basek, k_ksk, k_ksk, rank),
142    );
143
144    let mut sk: SecretKey<Vec<u8>> = SecretKey::alloc(&module, rank);
145    sk.fill_ternary_prob(0.5, &mut source_xs);
146
147    let mut sk_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::alloc(&module, rank);
148    sk_dft.dft(&module, &sk);
149
150    // gglwe_{s1}(s0) = s0 -> s1
151    auto_key.generate_from_sk(
152        &module,
153        p0,
154        &sk,
155        &mut source_xa,
156        &mut source_xe,
157        sigma,
158        scratch.borrow(),
159    );
160
161    // gglwe_{s2}(s1) -> s1 -> s2
162    auto_key_apply.generate_from_sk(
163        &module,
164        p1,
165        &sk,
166        &mut source_xa,
167        &mut source_xe,
168        sigma,
169        scratch.borrow(),
170    );
171
172    // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
173    auto_key.automorphism_inplace(&module, &auto_key_apply, scratch.borrow());
174
175    let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ksk, rank);
176    let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ksk);
177
178    let mut sk_auto: SecretKey<Vec<u8>> = SecretKey::alloc(&module, rank);
179    sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
180    (0..rank).for_each(|i| {
181        module.scalar_znx_automorphism(
182            module.galois_element_inv(p0 * p1),
183            &mut sk_auto.data,
184            i,
185            &sk.data,
186            i,
187        );
188    });
189
190    let mut sk_auto_dft: SecretKeyFourier<Vec<u8>, FFT64> = SecretKeyFourier::alloc(&module, rank);
191    sk_auto_dft.dft(&module, &sk_auto);
192
193    (0..auto_key.rank_in()).for_each(|col_i| {
194        (0..auto_key.rows()).for_each(|row_i| {
195            auto_key.get_row(&module, row_i, col_i, &mut ct_glwe_dft);
196
197            ct_glwe_dft.decrypt(&module, &mut pt, &sk_auto_dft, scratch.borrow());
198            module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk.data, col_i);
199
200            let noise_have: f64 = pt.data.std(0, basek).log2();
201            let noise_want: f64 = log2_std_noise_gglwe_product(
202                module.n() as f64,
203                basek,
204                0.5,
205                0.5,
206                0f64,
207                sigma * sigma,
208                0f64,
209                rank as f64,
210                k_ksk,
211                k_ksk,
212            );
213
214            assert!(
215                (noise_have - noise_want).abs() <= 0.1,
216                "{} {}",
217                noise_have,
218                noise_want
219            );
220        });
221    });
222}