arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/README.md
poulpy-core/README.mdRaw
  1# 🐙 Poulpy-Core
  2
  3**Poulpy-Core** is a Rust crate built on **`poulpy-hal`**, providing scheme- and backend-agnostic RLWE-based homomorphic encryption building blocks.
  4
  5## Getting Started
  6
  7```rust
  8use poulpy_core::{
  9    GLWESub, SIGMA,
 10    layouts::{
 11        Base2K, Degree, GLWE, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWESecret, LWEInfos, Rank, TorusPrecision,
 12        prepared::GLWESecretPrepared,
 13    },
 14};
 15use poulpy_cpu_ref::FFT64Ref;
 16use poulpy_hal::{
 17    api::{ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform},
 18    layouts::{Module, ScratchOwned},
 19    source::Source,
 20};
 21
 22fn main() {
 23    // Ring degree
 24    let log_n: usize = 10;
 25
 26    let n: Degree = Degree(1 << log_n);
 27
 28    // Base-2-k (implicit digit decomposition)
 29    let base2k: Base2K = Base2K(14);
 30
 31    // Ciphertext Torus precision (equivalent to ciphertext modulus)
 32    let k_ct: TorusPrecision = TorusPrecision(27);
 33
 34    // Plaintext Torus precision (equivament to plaintext modulus)
 35    let k_pt: TorusPrecision = TorusPrecision(base2k.into());
 36
 37    // GLWE rank
 38    let rank: Rank = Rank(1);
 39
 40    // Instantiate Module (DFT Tables)
 41    let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(n.0 as u64);
 42
 43    let glwe_ct_infos: GLWELayout = GLWELayout {
 44        n,
 45        base2k,
 46        k: k_ct,
 47        rank,
 48    };
 49
 50    let glwe_pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout { n, base2k, k: k_pt };
 51
 52    // Allocates ciphertext & plaintexts
 53    let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_ct_infos);
 54    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos);
 55    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos);
 56
 57    // CPRNG
 58    let mut source_xs: Source = Source::new([0u8; 32]);
 59    let mut source_xe: Source = Source::new([1u8; 32]);
 60    let mut source_xa: Source = Source::new([2u8; 32]);
 61
 62    // Scratch space
 63    let mut scratch: ScratchOwned<FFT64Ref> = ScratchOwned::alloc(
 64        GLWE::encrypt_sk_tmp_bytes(&module, &glwe_ct_infos) | GLWE::decrypt_tmp_bytes(&module, &glwe_ct_infos),
 65    );
 66
 67    // Generate secret-key
 68    let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_ct_infos);
 69    sk.fill_ternary_prob(0.5, &mut source_xs);
 70
 71    // Backend-prepared secret
 72    let mut sk_prepared: GLWESecretPrepared<Vec<u8>, FFT64Ref> = GLWESecretPrepared::alloc(&module, rank);
 73    sk_prepared.prepare(&module, &sk);
 74
 75    // Uniform plaintext
 76    module.vec_znx_fill_uniform(base2k.into(), &mut pt_want.data, 0, &mut source_xa);
 77
 78    // Encryption
 79    ct.encrypt_sk(
 80        &module,
 81        &pt_want,
 82        &sk_prepared,
 83        &mut source_xa,
 84        &mut source_xe,
 85        scratch.borrow(),
 86    );
 87
 88    // Decryption
 89    ct.decrypt(&module, &mut pt_have, &sk_prepared, scratch.borrow());
 90
 91    // Diff between pt - Dec(Enc(pt))
 92    module.glwe_sub_inplace(&mut pt_want, &pt_have);
 93
 94    // Ideal vs. actual noise
 95    let noise_have: f64 = pt_want.data.stats(base2k.into(), 0).std() * (ct.k().as_u32() as f64).exp2();
 96    let noise_want: f64 = SIGMA;
 97
 98    // Check
 99    assert!(noise_have <= noise_want + 0.2);
100}
101```
102
103## Layouts
104
105This crate defines three categories of layouts for `LWE`, `GLWE`, `GGLWE`, and `GGSW` objects (and their derivatives), all instantiated using **`poulpy-hal`** layouts. Each serves a distinct purpose:
106
107* **Standard** → Front-end, serializable layouts. These are backend-agnostic and act as inputs/outputs of computations (e.g., `GGLWEAutomorphismKey`).
108* **Compressed** → Compact serializable variants of the standard layouts. They are not usable for computation but significantly reduce storage size (e.g., `GGLWEAutomorphismKeyCompressed`).
109* **Prepared** → Backend-optimized, opaque layouts used only for computation (write-only). These store preprocessed data for efficient execution on a specific backend (e.g., `GGLWEAutomorphismKeyPrepared`).
110
111All **standard** and **compressed** layouts implement the `WriterTo` and `ReaderFrom` traits, enabling straightforward serialization/deserialization with any type implementing `Write` or `Read`:
112
113```rust
114pub trait WriterTo {
115    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()>;
116}
117
118pub trait ReaderFrom {
119    fn read_from<R: Read>(&mut self, reader: &mut R) -> Result<()>;
120}
121```
122
123### Example Workflow
124
125```mermaid
126flowchart TD
127    A[GGLWEAutomorphismKeyCompressed]-->|decompress|B[GGLWEAutomorphismKey]-->|prepare|C[GGLWEAutomorphismKeyPrepared]
128```
129
130Equivalent Rust:
131
132```rust
133let mut atk_compressed: GGLWEAutomorphismKeyCompressed<Vec<u8>> = 
134    GGLWEAutomorphismKeyCompressed::alloc(...);
135let mut atk: GGLWEAutomorphismKey<Vec<u8>> = 
136    GGLWEAutomorphismKey::alloc(...);
137atk.decompress(module, &atk_compressed);
138let mut atk_prep: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = GLWESecretPrepared<Vec<u8>, B> = atk.prepare_alloc(...);
139```
140
141---
142
143## Encryption & Decryption
144
145* **Encryption** → Supported for all **standard** and **compressed** layouts.
146* **Decryption** → Only directly available for `LWECiphertext` and `GLWECiphertext`.
147  However, it remains naturally usable on `GGLWE` and `GGSW` objects, since these are vectors/matrices of `GLWECiphertext`.
148
149```rust
150let mut atk: GGLWEAutomorphismKey<Vec<u8>> =
151        GGLWEAutomorphismKey::alloc(...);
152atk.encrypt_sk(...);
153atk.at(row, 0).decrypt(...);
154```
155## Keyswitching, Automorphism & External Product
156
157Keyswitching, automorphisms and external products are supported for all ciphertext types where they are well-defined.
158This includes subtypes such as `GGLWEAutomorphismKey`.
159
160For example:
161
162```rust
163atk.external_product(...);
164ggsw.automorphism(...);
165```
166
167---
168
169## Additional Features
170
171* Ciphertexts: `LWE` and `GLWE`
172* `GLWE` ring packing
173* `GLWE` trace
174* Noise analysis for `GLWE`, `GGLWE`, `GGSW`
175* Basic operations over `GLWE` ciphertexts and plaintexts
176
177---
178
179## Tests
180
181A fully generic test suite is available in [`src/tests/test_suite`](./src/tests/test_suite).