cupcake/
lib.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5//! An implementation of the (additive homomorphism only) Fan-Vercauteren (FV) lattice-based homomorphic encryption scheme.
6//! # Overview
7//! Homomorphic encryption supports operations on encrypted data without knowing the decryption key.
8//!
9//! In order to use lattice-based homomorphic encryption, we first need to decide on the scheme to use and set up the parameters, including the polynomial degree (n) and the modulus (q).
10//!
11//! Currently, we only support one scheme (FV) and one set of parameters, corresponding to a polynomial degree of 2048 and a 54-bit prime modulus.
12//! ```
13//! let scheme = cupcake::default();
14//! ```
15//! # Setup
16//! In order to encrypt and decrypt data, we needs to generate a keypair, i.e. a secret key and a public key.
17//! ```
18//! let scheme = cupcake::default();
19//! use cupcake::traits::{KeyGeneration};
20//! let (pk, sk) = scheme.generate_keypair();
21//! ```
22//! The public key can be used for encryption and the secret key can be used for encryption or decryption.
23//!
24//! # Encryption and Decryption
25//!
26//! The default plaintext space of Cupcake is `Vec<u8>` of fixed size n. We can encrypt a vector under a public key like so
27//! ```
28//! # let scheme = cupcake::default();
29//! # use cupcake::traits::KeyGeneration;
30//! # let (pk, sk) = scheme.generate_keypair();
31//! use cupcake::traits::{SKEncryption, PKEncryption};
32//! let v = vec![1; scheme.n];
33//! let ct = scheme.encrypt(&v, &pk);
34//! ```
35//! Then, the ciphertext `ct` can be decrypted using the secret key:
36//! ```
37//! # let scheme = cupcake::default();
38//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
39//! # let (pk, sk) = scheme.generate_keypair();
40//! # let v = vec![1; scheme.n];
41//! # let ct = scheme.encrypt(&v, &pk);
42//! let w: Vec<u8>= scheme.decrypt(&ct, &sk);
43//! assert_eq!(v, w);
44//! ```
45//! You may also use other plaintext types, which are vectors of `Scalar` of size n. Here `Scalar`  represents an integer modulo a fixed modulus t.
46//! See the following example:
47//! ```
48//! # use cupcake::traits::{KeyGeneration, PKEncryption, SKEncryption};
49//! use cupcake::integer_arith::scalar::Scalar;
50//! let t = 199;
51//! let scheme = cupcake::default_with_plaintext_mod(t);
52//! let (pk, sk) = scheme.generate_keypair();
53//! let plain_modulus = scheme.t.clone();
54//! let pt = vec![Scalar::from(t-1 as u32); scheme.n];
55//! let ct = scheme.encrypt(&pt, &pk);
56//! let pt_actual: Vec<Scalar> = scheme.decrypt(&ct, &sk);
57//! assert_eq!(pt_actual, pt);
58//! ```
59//! # Homomorphic Operations
60//!
61//! We can encrypt two vectors and add up the resulting ciphertexts.
62//! ```
63//! # let scheme = cupcake::default();
64//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
65//! # let (pk, sk) = scheme.generate_keypair();
66//! use cupcake::traits::{AdditiveHomomorphicScheme};
67//! let z1 = vec![1; scheme.n];
68//! let mut ctz1 = scheme.encrypt(&z1, &pk);
69//! let z2 = vec![2; scheme.n];
70//! let ctz2 = scheme.encrypt(&z2, &pk);
71//! scheme.add_inplace(&mut ctz1, &ctz2);
72//! // Now ctz1 should decrypt to vec![3; scheme.n];
73//! let expected = vec![3; scheme.n];
74//! let actual: Vec<u8> = scheme.decrypt(&ctz1, &sk);
75//! assert_eq!(actual, expected);
76//! ```
77//! Alternatively, we can add a plaintext vector into a ciphertext
78//! ```
79//! # let scheme = cupcake::default();
80//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
81//! # let (pk, sk) = scheme.generate_keypair();
82//! use cupcake::traits::CipherPlainAddition;
83//! let z = vec![1; scheme.n];
84//! let mut ctz = scheme.encrypt(&z, &pk);
85//! let p = vec![4; scheme.n];
86//! scheme.add_plain_inplace(&mut ctz, &p);
87//! // Now ctz should decrypt to vec![5; scheme.n]
88//! let expected = vec![5; scheme.n];
89//! let actual: Vec<u8> = scheme.decrypt(&ctz, &sk);
90//! assert_eq!(actual, expected);
91//! ```
92//! # Rerandomization
93//! Furthermore, you can rerandomize a ciphertext using the public key. The output is another ciphertext which will be still decrypt to the same plaintext, but cannot be linked to the input.
94//! ```
95//! # let scheme = cupcake::default();
96//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
97//! # let (pk, sk) = scheme.generate_keypair();
98//! # use cupcake::traits::{AdditiveHomomorphicScheme};
99//! let mu = vec![1; scheme.n];
100//! let mut ct = scheme.encrypt(&mu, &pk);
101//! scheme.rerandomize(&mut ct, &pk);
102//! // The new ct should still decrypt to mu.
103//! let actual: Vec<u8> = scheme.decrypt(&ct, &sk);
104//! let expected = mu;
105//! assert_eq!(actual, expected);
106//! ```
107//! # Serialization
108//! We provide methods to serialize  a ciphertext into a ```Vec<u8>```. Note that after deserialization, a proper context needs to be set before the further operations can be done on the ciphertext. See
109//! the following example:
110//! ```
111//! # let scheme = cupcake::default();
112//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
113//! # let (pk, sk) = scheme.generate_keypair();
114//! # use cupcake::traits::{AdditiveHomomorphicScheme};
115//! use crate::cupcake::traits::Serializable;
116//! let v = vec![1; scheme.n];
117//! let w = vec![1; scheme.n];
118//! let ctv = scheme.encrypt(&v, &pk);
119//! let ctw = scheme.encrypt(&w, &pk);
120//! ```
121//! We can call the `to_bytes` function to serialize.
122//! ```
123//! # let scheme = cupcake::default();
124//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
125//! # let (pk, sk) = scheme.generate_keypair();
126//! # use cupcake::traits::{AdditiveHomomorphicScheme};
127//! # use crate::cupcake::traits::Serializable;
128//! # let v = vec![1; scheme.n];
129//! # let w = vec![1; scheme.n];
130//! # let ctv = scheme.encrypt(&v, &pk);
131//! # let ctw = scheme.encrypt(&w, &pk);
132//! let ctv_serialized = ctv.to_bytes();
133//! let ctw_serialized = ctw.to_bytes();
134//! ```
135//! In order to deserialize, use `scheme.from_bytes`.
136//! ```
137//! # let scheme = cupcake::default();
138//! # use cupcake::traits::{KeyGeneration, SKEncryption, PKEncryption};
139//! # let (pk, sk) = scheme.generate_keypair();
140//! # use cupcake::traits::{AdditiveHomomorphicScheme};
141//! # use crate::cupcake::traits::Serializable;
142//! # let v = vec![1; scheme.n];
143//! # let w = vec![1; scheme.n];
144//! # let ctv = scheme.encrypt(&v, &pk);
145//! # let ctw = scheme.encrypt(&w, &pk);
146//! # let ctv_serialized = ctv.to_bytes();
147//! # let ctw_serialized = ctw.to_bytes();
148//! let mut ctv_deserialized = scheme.from_bytes(&ctv_serialized);
149//! let ctw_deserialized = scheme.from_bytes(&ctw_serialized);
150//! assert_eq!(ctv, ctv_deserialized);
151//! ```
152//! We can perform homomorphic operations on deserialized ciphertexts.
153//! ```
154//! # let scheme = cupcake::default();
155//! # let (pk, sk) = scheme.generate_keypair();
156//! # use crate::cupcake::traits::*;
157//! # let v = vec![1; scheme.n];
158//! # let w = vec![1; scheme.n];
159//! # let ctv = scheme.encrypt(&v, &pk);
160//! # let ctw = scheme.encrypt(&w, &pk);
161//! # let ctv_serialized = ctv.to_bytes();
162//! # let ctw_serialized = ctw.to_bytes();
163//! # let mut ctv_deserialized = scheme.from_bytes(&ctv_serialized);
164//! # let ctw_deserialized = scheme.from_bytes(&ctw_serialized);
165//! scheme.add_inplace(&mut ctv_deserialized, &ctw_deserialized);
166//! let expected = vec![2; scheme.n];
167//! let actual: Vec<u8>= scheme.decrypt(&ctv_deserialized, &sk);
168//! assert_eq!(actual, expected);
169//! ```
170
171
172pub mod integer_arith;
173pub mod polyarith;
174#[cfg(feature = "bench")]
175pub mod rqpoly;
176#[cfg(not(feature = "bench"))]
177mod rqpoly;
178pub mod traits;
179mod serialize;
180mod utils;
181#[cfg(feature = "bench")]
182pub mod randutils;
183#[cfg(not(feature = "bench"))]
184mod randutils;
185
186use integer_arith::scalar::Scalar;
187use integer_arith::{SuperTrait, ArithUtils};
188use traits::*;
189use std::sync::Arc;
190
191/// Plaintext type
192pub type FVPlaintext<T> = Vec<T>;
193/// Default plaintext type
194pub type DefaultFVPlaintext = Vec<u8>;
195/// Ciphertext type
196pub type FVCiphertext<T> = (RqPoly<T>, RqPoly<T>);
197
198/// Default scheme type
199pub type DefaultShemeType = FV<Scalar>;
200
201/// SecretKey type
202pub struct SecretKey<T>(RqPoly<T>);
203use rqpoly::{FiniteRingElt, RqPoly, RqPolyContext};
204
205pub fn default() -> DefaultShemeType {
206    FV::<Scalar>::default_2048()
207}
208
209pub fn default_with_plaintext_mod(t: u32) -> DefaultShemeType {
210    FV::<Scalar>::default_2048_with_plaintext_mod(t)
211}
212
213/// (Additive only version of) the Fan-Vercauteren homomoprhic encryption scheme.
214pub struct FV<T>
215where
216    T: ArithUtils<T>,
217{
218    pub n: usize,
219    pub t: T,
220    pub q: T,
221    pub delta: T,
222    pub stdev: f64,
223    pub qdivtwo: T,
224    pub flooding_stdev: f64,
225    context: Arc<RqPolyContext<T>>,
226    poly_multiplier: fn(&RqPoly<T>, &RqPoly<T>) -> RqPoly<T>,
227}
228
229impl<T> FV<T>
230where
231T: ArithUtils<T>{
232    fn convert_pt_u8_to_scalar(&self, pt: &DefaultFVPlaintext) -> FVPlaintext<T>{
233        if T::to_u64(&self.t) != 256u64{
234            panic!("plaintext modulus should be 256")
235        }
236        let mut pt1 = vec![];
237        for pt_coeff in pt.iter(){
238            pt1.push(T::from_u32(*pt_coeff as u32,  &self.t));
239        }
240        pt1
241    }
242
243    fn convert_pt_scalar_to_u8(&self, pt: FVPlaintext<T>) -> DefaultFVPlaintext{
244        if T::to_u64(&self.t) != 256u64{
245            panic!("plaintext modulus should be 256")
246        }
247        let mut pt1 = vec![];
248        for pt_coeff in pt.iter(){
249            pt1.push(T::to_u64(pt_coeff) as u8);
250        }
251        pt1
252    }
253}
254
255impl<T> CipherPlainAddition<FVCiphertext<T>, FVPlaintext<T>> for FV<T>
256where
257    RqPoly<T>: FiniteRingElt,
258    T: Clone + ArithUtils<T> + PartialEq,
259{
260    // add a plaintext into a FVCiphertext.
261    fn add_plain_inplace(&self, ct: &mut FVCiphertext<T>, pt: &FVPlaintext<T>) {
262        for (ct_coeff, pt_coeff) in ct.1.coeffs.iter_mut().zip(pt.iter()) {
263            let temp = T::mul(pt_coeff, &self.delta);
264            *ct_coeff = T::add_mod(ct_coeff, &temp, &self.q);
265        }
266    }
267}
268
269
270impl<T> CipherPlainAddition<FVCiphertext<T>, DefaultFVPlaintext> for FV<T>
271where
272    RqPoly<T>: FiniteRingElt,
273    T: Clone + ArithUtils<T> + PartialEq + From<u32>,
274{
275    // add a plaintext into a FVCiphertext.
276    fn add_plain_inplace(&self, ct: &mut FVCiphertext<T>, pt: &DefaultFVPlaintext) {
277        for (ct_coeff, pt_coeff) in ct.1.coeffs.iter_mut().zip(pt.iter()) {
278            let temp = T::mul(&T::from(*pt_coeff as u32), &self.delta);
279            *ct_coeff = T::add_mod(ct_coeff, &temp, &self.q);
280        }
281    }
282}
283
284
285impl<T> AdditiveHomomorphicScheme<FVCiphertext<T>, SecretKey<T>> for FV<T>
286where
287    RqPoly<T>: FiniteRingElt,
288    T: SuperTrait<T>,
289{
290    fn add_inplace(&self, ct1: &mut FVCiphertext<T>, ct2: &FVCiphertext<T>) {
291        ct1.0.add_inplace(&ct2.0);
292        ct1.1.add_inplace(&ct2.1);
293    }
294
295    // rerandomize a ciphertext
296    fn rerandomize(&self, ct: &mut FVCiphertext<T>, pk: &FVCiphertext<T>) {
297        // add a public key encryption of zero.
298        let c_mask = self.encrypt_zero(pk);
299        self.add_inplace(ct, &c_mask);
300
301        // add large noise poly for noise flooding.
302        let elarge =
303            randutils::sample_gaussian_poly(self.context.clone(), self.flooding_stdev);
304        ct.1.add_inplace(&elarge);
305    }
306}
307
308// constructor and random poly sampling
309impl<T> FV<T>
310where
311    T: SuperTrait<T>+ PartialEq + Serializable,
312    RqPoly<T>: FiniteRingElt + NTT<T>,
313{
314    pub fn new(n: usize, q: &T) -> Self {
315        Self::new_with_ptxt_mod(n, &T::new_modulus(256), q)
316    }
317
318    pub fn new_with_ptxt_mod(n: usize, t: &T, q: &T) -> Self {
319        let context = Arc::new(RqPolyContext::new(n, q));
320        type RqPolyMultiplier<T> = fn(&RqPoly<T>, &RqPoly<T>) -> RqPoly<T>;
321        let default_multiplier: RqPolyMultiplier<T>;
322        if context.is_ntt_enabled {
323            default_multiplier =
324                |op1: &RqPoly<T>, op2: &RqPoly<T>| -> RqPoly<T> { op1.multiply_fast(op2) };
325        } else {
326            default_multiplier =
327                |op1: &RqPoly<T>, op2: &RqPoly<T>| -> RqPoly<T> { op1.multiply(op2) };
328        }
329        FV {
330            n,
331            t: t.clone(),
332            flooding_stdev: 2f64.powi(40),
333            delta: T::div(q, t), // &q/t,
334            qdivtwo: T::div(q, &T::from(2_u32)), // &q/2,
335            q: q.clone(),
336            stdev: 3.2,
337            context,
338            poly_multiplier: default_multiplier,
339        }
340    }
341
342    pub fn from_bytes(&self, bytes: &Vec<u8>) -> FVCiphertext<T>{
343        let mut ct = FVCiphertext::<T>::from_bytes(bytes);
344        self.set_context(&mut ct);
345        ct
346    }
347
348    fn set_context(&self, ctxt: &mut FVCiphertext<T>){
349        ctxt.0.set_context(self.context.clone());
350        ctxt.1.set_context(self.context.clone());
351    }
352}
353
354impl FV<Scalar> {
355    /// Construct a scheme with default parameters and plaintext modulus 256.
356    pub fn default_2048() -> FV<Scalar> {
357        let q = Scalar::new_modulus(18014398492704769u64);
358        Self::new(2048, &q)
359    }
360
361    /// Construct a scheme with provided plaintext modulus.
362    pub fn default_2048_with_plaintext_mod(t: u32) -> FV<Scalar> {
363        if t > 2u32.pow(10){
364            panic!("plain text modulus should not be more than 10 bits.")
365        }
366        let q = Scalar::new_modulus(18014398492704769u64);
367        let t = Scalar::new_modulus(t as u64);
368        Self::new_with_ptxt_mod(2048, &t, &q)
369    }
370}
371
372#[cfg(feature = "bigint")]
373impl FV<BigInt> {
374    pub fn default_2048() -> FV<BigInt> {
375        let q = BigInt::from_hex("3fffffff000001");
376        let context = Arc::new(RqPolyContext::new(2048, &q));
377        let multiplier = |op1: &RqPoly<BigInt>, op2: &RqPoly<BigInt>| -> RqPoly<BigInt> {
378            op1.multiply_fast(op2)
379        };
380
381        FV {
382            n: 2048,
383            q: q.clone(),
384            delta: &q / 256,
385            qdivtwo: &q / 2,
386            stdev: 3.2,
387            flooding_stdev: 1e40_f64,
388            context: context,
389            poly_multiplier: multiplier,
390        }
391    }
392}
393
394
395impl<T> KeyGeneration<FVCiphertext<T>,  SecretKey<T>> for FV<T>
396where
397    RqPoly<T>: FiniteRingElt,
398    T: SuperTrait<T>,
399{
400    fn generate_key(&self) -> SecretKey<T> {
401        let mut skpoly = randutils::sample_ternary_poly(self.context.clone());
402        if self.context.is_ntt_enabled {
403            skpoly.forward_transform();
404        }
405        SecretKey(skpoly)
406    }
407
408    fn generate_keypair(&self) -> (FVCiphertext<T>, SecretKey<T>) {
409        let sk = self.generate_key();
410        let mut pk = self.encrypt_zero_sk(&sk);
411        if self.context.is_ntt_enabled {
412            pk.0.forward_transform();
413            pk.1.forward_transform();
414        }
415        (pk, sk)
416    }
417}
418
419impl<T> EncryptionOfZeros<FVCiphertext<T>,  SecretKey<T>> for FV<T>
420where
421    RqPoly<T>: FiniteRingElt,
422    T: SuperTrait<T>,
423{
424    fn encrypt_zero(&self, pk: &FVCiphertext<T>) -> FVCiphertext<T> {
425        let mut u = randutils::sample_ternary_poly_prng(self.context.clone());
426        let e1 = randutils::sample_gaussian_poly(self.context.clone(), self.stdev);
427        let e2 = randutils::sample_gaussian_poly(self.context.clone(), self.stdev);
428
429        if self.context.is_ntt_enabled {
430            u.forward_transform();
431        }
432        // c0 = au + e1
433        // let mut c0 = RqPoly::new(self.context.clone()); 
434        let mut c0 = (self.poly_multiplier)(&pk.0, &u);
435        c0.add_inplace(&e1);
436
437        // c1 = bu + e2
438        // let mut c1 = RqPoly::new(self.context.clone()); 
439
440        let mut c1 = (self.poly_multiplier)(&pk.1, &u);
441        c1.add_inplace(&e2);
442
443        (c0, c1)
444    }
445
446    fn encrypt_zero_sk(&self, sk: &SecretKey<T>) -> FVCiphertext<T> {
447        let e = randutils::sample_gaussian_poly(self.context.clone(), self.stdev);
448        let a = randutils::sample_uniform_poly(self.context.clone());
449        let mut b = (self.poly_multiplier)(&a, &sk.0);
450        b.add_inplace(&e);
451        (a, b)
452    }
453}
454
455impl<T> PKEncryption<FVCiphertext<T>, FVPlaintext<T>, SecretKey<T>> for FV<T>
456where
457    RqPoly<T>: FiniteRingElt,
458    T: SuperTrait<T>,
459{
460    fn encrypt(&self, pt: &FVPlaintext<T>, pk: &FVCiphertext<T>) -> FVCiphertext<T> {
461        // use public key to encrypt
462        // pk = (a, as+e) = (a,b)
463        let (c0, mut c1) = self.encrypt_zero(pk);
464        // c1 = bu+e2 + Delta*m
465        let iter = c1.coeffs.iter_mut().zip(pt.iter());
466        for (x, y) in iter {
467            let temp = T::mul(y, &self.delta);
468            *x = T::add_mod(x, &temp, &self.q);
469        }
470        (c0, c1)
471    }
472}
473
474impl<T> PKEncryption<FVCiphertext<T>, DefaultFVPlaintext, SecretKey<T>> for FV<T>
475where
476    RqPoly<T>: FiniteRingElt,
477    T: SuperTrait<T>,
478{
479    fn encrypt(&self, pt: &DefaultFVPlaintext, pk: &FVCiphertext<T>) -> FVCiphertext<T> {
480        let pt1 = self.convert_pt_u8_to_scalar(pt);
481        self.encrypt(&pt1, pk)
482    }
483}
484
485impl<T> SKEncryption<FVCiphertext<T>, DefaultFVPlaintext, SecretKey<T>> for FV<T>
486where
487    RqPoly<T>: FiniteRingElt,
488    T: SuperTrait<T>,
489{
490    fn encrypt_sk(&self, pt: &DefaultFVPlaintext, sk: &SecretKey<T>) -> FVCiphertext<T>
491        {
492            let pt1 = self.convert_pt_u8_to_scalar(pt);
493            self.encrypt_sk(&pt1, sk)
494        }
495
496    fn decrypt(&self, ct: &FVCiphertext<T>, sk: &SecretKey<T>) -> DefaultFVPlaintext{
497        let pt1 = self.decrypt(ct, sk);
498        self.convert_pt_scalar_to_u8(pt1)
499    }
500}
501
502// This implements the sk-encryption for BFV scheme.
503impl<T> SKEncryption<FVCiphertext<T>, FVPlaintext<T>, SecretKey<T>> for FV<T>
504where
505    RqPoly<T>: FiniteRingElt,
506    T: SuperTrait<T>,
507{
508    fn encrypt_sk(&self, pt: &FVPlaintext<T>, sk: &SecretKey<T>) -> FVCiphertext<T> {
509        let e = randutils::sample_gaussian_poly(self.context.clone(), self.stdev);
510        let a = randutils::sample_uniform_poly(self.context.clone());
511
512
513        let mut b = (self.poly_multiplier)(&a, &sk.0);
514        b.add_inplace(&e);
515
516        // add scaled plaintext to
517        let iter = b.coeffs.iter_mut().zip(pt.iter());
518        for (x, y) in iter {
519            let temp = T::mul(y, &self.delta);
520            *x = T::add_mod(x, &temp, &self.q);
521        }
522        (a, b)
523    }
524
525    fn decrypt(&self, ct: &FVCiphertext<T>, sk: &SecretKey<T>) -> FVPlaintext<T> {
526        let temp1 = (self.poly_multiplier)(&ct.0, &sk.0);
527        let mut phase = ct.1.clone();
528        phase.sub_inplace(&temp1);
529        // then, extract value from phase.
530        let tt: u64 = self.t.rep(); 
531        let qq: u64 = self.q.rep(); 
532        let qdivtwo = qq / 2; 
533
534        let my_closure = |elm: &T| -> T{
535            let mut tmp:u64 = elm.rep(); 
536            tmp *= tt;
537            tmp += qdivtwo;  
538            tmp /= qq; 
539            tmp %= tt; 
540            T::from(tmp)
541        }; 
542
543        return phase.coeffs.iter()
544        .map(my_closure)
545        .collect();
546    }
547}
548
549#[cfg(test)]
550mod fv_scalar_tests {
551    use super::*;
552    #[test]
553    fn test_sk_encrypt_toy_param_scalar() {
554        let fv = FV::new(16, &Scalar::new_modulus(65537));
555
556        let sk = fv.generate_key();
557
558        let mut v = vec![0; fv.n];
559        for i in 0..fv.n {
560            v[i] = i as u8;
561        }
562        let ct = fv.encrypt_sk(&v, &sk);
563
564        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
565
566        assert_eq!(v, pt_actual);
567    }
568
569    #[test]
570    fn test_sk_encrypt_scalar() {
571        let fv = FV::<Scalar>::default_2048();
572
573        let sk = fv.generate_key();
574
575        let mut v = vec![0; fv.n];
576        for i in 0..fv.n {
577            v[i] = i as u8;
578        }
579        let ct = fv.encrypt_sk(&v, &sk);
580
581        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
582
583        assert_eq!(v, pt_actual);
584    }
585
586    #[test]
587    fn test_encrypt_default_param_scalar() {
588        let fv = FV::<Scalar>::default_2048();
589
590        let (pk, sk) = fv.generate_keypair();
591
592        let mut v = vec![0; fv.n];
593        for i in 0..fv.n {
594            v[i] = i as u8;
595        }
596        let ct = fv.encrypt(&v, &pk);
597
598        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
599
600        assert_eq!(v, pt_actual);
601    }
602
603    #[test]
604    fn test_rerandomize_scalar() {
605        let fv = FV::<Scalar>::default_2048();
606
607        let (pk, sk) = fv.generate_keypair();
608
609        let mut v = vec![0; fv.n];
610        for i in 0..fv.n {
611            v[i] = i as u8;
612        }
613        let mut ct = fv.encrypt(&v, &pk);
614
615        fv.rerandomize(&mut ct, &pk);
616
617        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
618
619        assert_eq!(v, pt_actual);
620    }
621
622    #[test]
623    fn test_add_scalar() {
624        let fv = FV::<Scalar>::default_2048();
625        let (pk, sk) = fv.generate_keypair();
626
627        let mut v = vec![0; fv.n];
628        for i in 0..fv.n {
629            v[i] = i as u8;
630        }
631
632        let mut w: Vec<u8> = vec![];
633        for i in 0..fv.n {
634            w.push((fv.n - i) as u8);
635        }
636
637        let mut vplusw = vec![];
638        for _ in 0..fv.n {
639            vplusw.push(fv.n as u8);
640        }
641        // encrypt v
642        let mut ctv = fv.encrypt_sk(&v, &sk);
643        let ctw = fv.encrypt(&w, &pk);
644
645        // ct_v + ct_w.
646        fv.add_inplace(&mut ctv, &ctw);
647        let pt_after_add: DefaultFVPlaintext = fv.decrypt(&ctv, &sk);
648        assert_eq!(pt_after_add, vplusw);
649    }
650
651    #[test]
652    fn test_add_plain_scalar() {
653        let fv = FV::<Scalar>::default_2048();
654        let (pk, sk) = fv.generate_keypair();
655
656        let mut v = vec![0; fv.n];
657        for i in 0..fv.n {
658            v[i] = i as u8;
659        }
660
661        let mut w: Vec<u8> = vec![];
662        for i in 0..fv.n {
663            w.push((fv.n - i) as u8);
664        }
665
666        let mut vplusw = vec![];
667        for _ in 0..fv.n {
668            vplusw.push(fv.n as u8);
669        }
670        // encrypt v
671        let mut ct = fv.encrypt(&v, &pk);
672
673        // ct_v + w.
674        fv.add_plain_inplace(&mut ct, &w);
675
676        let pt_after_add: DefaultFVPlaintext = fv.decrypt(&ct, &sk);
677
678        assert_eq!(pt_after_add, vplusw);
679    }
680
681    #[test]
682    fn test_flexible_plaintext_encrypt() {
683        let t = 199;
684        let fv = crate::default_with_plaintext_mod(t);
685        let (pk, sk) = fv.generate_keypair();
686        let plain_modulus = fv.t.clone();
687        let pt = vec![Scalar::from_u32(t-1, &plain_modulus); fv.n];
688        let ct = fv.encrypt(&pt, &pk);
689        let pt_actual: Vec<Scalar> = fv.decrypt(&ct, &sk);
690        assert_eq!(pt_actual, pt);
691    }
692
693    #[test]
694    fn test_flexible_plaintext_addition() {
695        let t = 199;
696        let fv = crate::default_with_plaintext_mod(t);
697        let (pk, sk) = fv.generate_keypair();
698        let plain_modulus = fv.t.clone();
699        let v = vec![Scalar::from_u32(t-1, &plain_modulus); fv.n];
700        let w = vec![Scalar::from_u32(t-1, &plain_modulus); fv.n];
701        let v_plus_w = vec![Scalar::from_u32(t-2, &plain_modulus); fv.n];
702        let mut ctv = fv.encrypt(&v, &pk);
703        let ctw = fv.encrypt(&w, &pk);
704        fv.add_inplace(&mut ctv, &ctw);
705        let pt_actual: Vec<Scalar>= fv.decrypt(&ctv, &sk);
706        assert_eq!(pt_actual, v_plus_w);
707    }
708
709    #[test]
710    fn test_flexible_plaintext_add_plaintext() {
711        let t = 199;
712        let fv = crate::default_with_plaintext_mod(t);
713        let (pk, sk) = fv.generate_keypair();
714        let plain_modulus = fv.t.clone();
715        let v = vec![Scalar::from_u32(t-1, &plain_modulus); fv.n];
716        let w = vec![Scalar::from_u32(1, &plain_modulus); fv.n];
717        let v_plus_w = vec![Scalar::from_u32(0, &plain_modulus); fv.n];
718        let mut ct = fv.encrypt(&v, &pk);
719        fv.add_plain_inplace(&mut ct, &w);
720        let pt_actual: Vec<Scalar> = fv.decrypt(&ct, &sk);
721        assert_eq!(pt_actual, v_plus_w);
722    }
723}
724
725// unit tests.
726#[cfg(feature = "bigint")]
727#[cfg(test)]
728mod fv_bigint_tests {
729    use super::*;
730    #[test]
731    fn test_sk_encrypt() {
732        let fv = FV::new(16, &BigInt::from(12289));
733
734        let sk = fv.generate_key();
735
736        let mut v = vec![0; fv.n];
737        for i in 0..fv.n {
738            v[i] = i as u8;
739        }
740        let ct = fv.encrypt_sk(&v, &sk);
741
742        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
743
744        assert_eq!(v, pt_actual);
745    }
746
747    #[test]
748    fn test_encrypt_toy_param() {
749        let fv = FV::new(4, &BigInt::from(65537));
750
751        let (pk, sk) = fv.generate_keypair();
752
753        let mut v = vec![0; fv.n];
754        for i in 0..fv.n {
755            v[i] = i as u8;
756        }
757        for _ in 0..10 {
758            let ct = fv.encrypt(&v, &pk);
759            let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
760            assert_eq!(v, pt_actual);
761        }
762    }
763
764    #[test]
765    fn test_encrypt_nonntt_toy_param() {
766        let fv = FV::new(4, &BigInt::from(1000000));
767
768        let (pk, sk) = fv.generate_keypair();
769
770        let mut v = vec![0; fv.n];
771        for i in 0..fv.n {
772            v[i] = i as u8;
773        }
774        for _ in 0..10 {
775            let ct = fv.encrypt(&v, &pk);
776            let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
777            assert_eq!(v, pt_actual);
778        }
779    }
780
781    #[test]
782    fn test_encrypt_large_param() {
783        let fv = FV::<BigInt>::default_2048();
784
785        let (pk, sk) = fv.generate_keypair();
786
787        let mut v = vec![0; fv.n];
788        for i in 0..fv.n {
789            v[i] = i as u8;
790        }
791        let ct = fv.encrypt(&v, &pk);
792
793        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
794
795        assert_eq!(v, pt_actual);
796    }
797
798    #[test]
799    fn test_rerandomize() {
800        let fv = FV::<BigInt>::default_2048();
801
802        let (pk, sk) = fv.generate_keypair();
803
804        let mut v = vec![0; fv.n];
805        for i in 0..fv.n {
806            v[i] = i as u8;
807        }
808        let mut ct = fv.encrypt(&v, &pk);
809
810        fv.rerandomize(&mut ct, &pk);
811
812        let pt_actual: Vec<u8> = fv.decrypt(&ct, &sk);
813
814        assert_eq!(v, pt_actual);
815    }
816    #[test]
817    fn test_add() {
818        let fv = FV::new(16, &BigInt::from(12289));
819
820        let sk = fv.generate_key();
821
822        let mut v = vec![0; fv.n];
823        for i in 0..fv.n {
824            v[i] = i as u8;
825        }
826
827        let mut w: Vec<u8> = vec![];
828        for i in 0..fv.n {
829            w.push((fv.n - i) as u8);
830        }
831
832        let mut vplusw = vec![];
833        for _ in 0..fv.n {
834            vplusw.push(fv.n as u8);
835        }
836        // encrypt v
837        let mut ctv = fv.encrypt_sk(&v, &sk);
838        let ctw = fv.encrypt_sk(&w, &sk);
839
840        // ct_v + ct_w.
841        fv.add_inplace(&mut ctv, &ctw);
842
843        let pt_after_add = fv.decrypt(&ctv, &sk);
844
845        assert_eq!(pt_after_add, vplusw);
846    }
847
848    #[test]
849    fn test_add_plain() {
850        let fv = FV::new(16, &BigInt::from(12289));
851        let sk = fv.generate_key();
852
853        let mut v = vec![0; fv.n];
854        for i in 0..fv.n {
855            v[i] = i as u8;
856        }
857
858        let mut w: Vec<u8> = vec![];
859        for i in 0..fv.n {
860            w.push((fv.n - i) as u8);
861        }
862
863        let mut vplusw = vec![];
864        for _ in 0..fv.n {
865            vplusw.push(fv.n as u8);
866        }
867        // encrypt v
868        let mut ct = fv.encrypt_sk(&v, &sk);
869
870        // ct_v + w.
871        fv.add_plain_inplace(&mut ct, &w);
872
873        let pt_after_add = fv.decrypt(&ct, &sk);
874
875        assert_eq!(pt_after_add, vplusw);
876    }
877}