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