Skip to main content

poulpy_core/default/encryption/
mod.rs

1//! Secret-key and public-key encryption of ciphertexts and evaluation keys.
2//!
3//! This module provides traits and implementations for encrypting various
4//! lattice-based cryptographic objects, including:
5//!
6//! - **Ciphertexts**: [`GLWEEncryptSk`], [`GLWEEncryptPk`], [`GGLWEEncryptSk`],
7//!   [`GGSWEncryptSk`], [`LWEEncryptSk`] for encrypting plaintexts under
8//!   GLWE, GGLWE, GGSW, and LWE schemes.
9//!
10//! - **Key-switching keys**: [`GLWESwitchingKeyEncryptSk`], [`LWESwitchingKeyEncrypt`],
11//!   [`GLWEToLWESwitchingKeyEncryptSk`], [`LWEToGLWESwitchingKeyEncryptSk`] for
12//!   generating keys that enable switching between different secret keys or
13//!   between LWE and GLWE domains.
14//!
15//! - **Evaluation keys**: [`GLWEAutomorphismKeyEncryptSk`], [`GLWETensorKeyEncryptSk`],
16//!   [`GGLWEToGGSWKeyEncryptSk`] for generating keys used in automorphism,
17//!   tensor product, and GGLWE-to-GGSW conversion operations.
18//!
19//! - **Public keys**: [`GLWEPublicKeyGenerate`] for generating GLWE public keys
20//!   from secret keys.
21//!
22//! Encryption methods follow a consistent pattern with PRNG sources:
23//! - `source_xa`: source for mask/randomness sampling
24//! - `source_xe`: source for error/noise sampling
25//! - `source_xu`: source for uniform sampling (used in public-key encryption)
26//!
27//! Scratch space requirements for each operation can be queried via companion
28//! `*_tmp_bytes` methods.
29
30#![allow(clippy::too_many_arguments)]
31
32pub mod compressed;
33pub mod gglwe;
34pub mod gglwe_to_ggsw_key;
35pub mod ggsw;
36pub mod glwe;
37pub mod glwe_automorphism_key;
38pub mod glwe_public_key;
39pub mod glwe_switching_key;
40pub mod glwe_tensor_key;
41pub mod glwe_to_lwe_key;
42pub mod lwe;
43pub mod lwe_switching_key;
44pub mod lwe_to_glwe_key;
45
46pub use crate::api::{DeclaredK, EncryptionInfos, GGSWEncryptSk, GLWEEncryptSk};
47pub use compressed::*;
48pub use gglwe::*;
49pub use gglwe_to_ggsw_key::*;
50pub use ggsw::*;
51pub use glwe::*;
52pub use glwe_automorphism_key::*;
53pub use glwe_public_key::*;
54pub use glwe_switching_key::*;
55pub use glwe_tensor_key::*;
56pub use glwe_to_lwe_key::*;
57pub use lwe::*;
58pub use lwe_switching_key::*;
59pub use lwe_to_glwe_key::*;
60use poulpy_hal::layouts::NoiseInfos;
61
62use crate::layouts::{
63    GGLWEInfos, GGLWELayout, GGSWInfos, GGSWLayout, GLWEInfos, GLWELayout, LWEInfos, LWELayout, TorusPrecision,
64};
65use anyhow::Result;
66
67/// Standard deviation of the discrete Gaussian distribution used for error sampling
68/// during encryption. Set to 3.2.
69pub const DEFAULT_SIGMA_XE: f64 = 3.2;
70
71/// Truncation bound for the discrete Gaussian error distribution, defined as 6.0 * [DEFAULT_SIGMA_XE].
72/// Samples are rejected if their absolute value exceeds this bound.
73pub const DEFAULT_BOUND_XE: f64 = 6.0 * DEFAULT_SIGMA_XE;
74
75impl DeclaredK for LWELayout {
76    fn k(&self) -> TorusPrecision {
77        self.k
78    }
79}
80
81impl DeclaredK for GLWELayout {
82    fn k(&self) -> TorusPrecision {
83        self.k
84    }
85}
86
87impl DeclaredK for GGLWELayout {
88    fn k(&self) -> TorusPrecision {
89        self.k
90    }
91}
92
93impl DeclaredK for GGSWLayout {
94    fn k(&self) -> TorusPrecision {
95        self.k
96    }
97}
98
99pub struct EncryptionLayout<L> {
100    pub layout: L,
101    pub noise: NoiseInfos,
102}
103
104impl<L: DeclaredK> EncryptionLayout<L> {
105    pub fn new(layout: L, noise: NoiseInfos) -> Result<Self> {
106        anyhow::ensure!(
107            noise.k <= layout.max_k().as_usize(),
108            "k_xe: {} > layout.max_k(): {}",
109            noise.k,
110            layout.max_k()
111        );
112        Ok(Self { layout, noise })
113    }
114
115    pub fn new_from_default_sigma(layout: L) -> Result<Self> {
116        let noise = NoiseInfos::new(layout.k().as_usize(), DEFAULT_SIGMA_XE, DEFAULT_BOUND_XE)?;
117        Self::new(layout, noise)
118    }
119}
120
121impl<L> EncryptionInfos for EncryptionLayout<L> {
122    fn noise_infos(&self) -> NoiseInfos {
123        self.noise
124    }
125}
126
127impl EncryptionInfos for NoiseInfos {
128    fn noise_infos(&self) -> NoiseInfos {
129        *self
130    }
131}
132
133impl<L: LWEInfos> LWEInfos for EncryptionLayout<L> {
134    fn base2k(&self) -> crate::layouts::Base2K {
135        self.layout.base2k()
136    }
137
138    fn n(&self) -> crate::layouts::Degree {
139        self.layout.n()
140    }
141
142    fn size(&self) -> usize {
143        self.layout.size()
144    }
145}
146
147impl<L: GLWEInfos> GLWEInfos for EncryptionLayout<L> {
148    fn rank(&self) -> crate::layouts::Rank {
149        self.layout.rank()
150    }
151}
152
153impl<L: GGLWEInfos> GGLWEInfos for EncryptionLayout<L> {
154    fn dnum(&self) -> crate::layouts::Dnum {
155        self.layout.dnum()
156    }
157
158    fn dsize(&self) -> crate::layouts::Dsize {
159        self.layout.dsize()
160    }
161
162    fn rank_in(&self) -> crate::layouts::Rank {
163        self.layout.rank_in()
164    }
165
166    fn rank_out(&self) -> crate::layouts::Rank {
167        self.layout.rank_out()
168    }
169}
170
171impl<L: GGSWInfos> GGSWInfos for EncryptionLayout<L> {
172    fn dnum(&self) -> crate::layouts::Dnum {
173        self.layout.dnum()
174    }
175
176    fn dsize(&self) -> crate::layouts::Dsize {
177        self.layout.dsize()
178    }
179}