# 🐙 Poulpy-Core **Poulpy-Core** is a Rust crate built on **`poulpy-hal`**, providing scheme- and backend-agnostic RLWE-based homomorphic encryption building blocks. ## Getting Started ```rust use poulpy_backend::cpu_spqlios::FFT64; use poulpy_core::{ GLWEOperations, SIGMA, layouts::{ GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, prepared::{GLWESecretPrepared, PrepareAlloc}, }, }; use poulpy_hal::{ api::{ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform}, layouts::{Module, ScratchOwned}, source::Source, }; fn main() { // Ring degree let log_n: usize = 10; let n: usize = 1< = Module::::new(n as u64); // Allocates ciphertext & plaintexts let mut ct: GLWECiphertext> = GLWECiphertext::alloc(n, base2k, k_ct, rank); let mut pt_want: GLWEPlaintext> = GLWEPlaintext::alloc(n, base2k, k_pt); let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(n, base2k, k_pt); // CPRNG let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([1u8; 32]); let mut source_xa: Source = Source::new([2u8; 32]); // Scratch space let mut scratch: ScratchOwned = ScratchOwned::alloc( GLWECiphertext::encrypt_sk_tmp_bytes(&module, n, base2k, ct.k()) | GLWECiphertext::decrypt_tmp_bytes(&module, n, base2k, ct.k()), ); // Generate secret-key let mut sk: GLWESecret> = GLWESecret::alloc(n, rank); sk.fill_ternary_prob(0.5, &mut source_xs); // Backend-prepared secret let sk_prepared: GLWESecretPrepared, FFT64> = sk.prepare_alloc(&module, scratch.borrow()); // Uniform plaintext module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, k_pt, &mut source_xa); // Encryption ct.encrypt_sk( &module, &pt_want, &sk_prepared, &mut source_xa, &mut source_xe, scratch.borrow(), ); // Decryption ct.decrypt(&module, &mut pt_have, &sk_prepared, scratch.borrow()); // Diff between pt - Dec(Enc(pt)) pt_want.sub_inplace_ab(&module, &pt_have); // Ideal vs. actual noise let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k() as f64).exp2(); let noise_want: f64 = SIGMA; // Check assert!(noise_have <= noise_want + 0.2); } ``` ## Layouts This 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: * **Standard** → Front-end, serializable layouts. These are backend-agnostic and act as inputs/outputs of computations (e.g., `GGLWEAutomorphismKey`). * **Compressed** → Compact serializable variants of the standard layouts. They are not usable for computation but significantly reduce storage size (e.g., `GGLWEAutomorphismKeyCompressed`). * **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`). All **standard** and **compressed** layouts implement the `WriterTo` and `ReaderFrom` traits, enabling straightforward serialization/deserialization with any type implementing `Write` or `Read`: ```rust pub trait WriterTo { fn write_to(&self, writer: &mut W) -> Result<()>; } pub trait ReaderFrom { fn read_from(&mut self, reader: &mut R) -> Result<()>; } ``` ### Example Workflow ```mermaid flowchart TD A[GGLWEAutomorphismKeyCompressed]-->|decompress|B[GGLWEAutomorphismKey]-->|prepare|C[GGLWEAutomorphismKeyPrepared] ``` Equivalent Rust: ```rust let mut atk_compressed: GGLWEAutomorphismKeyCompressed> = GGLWEAutomorphismKeyCompressed::alloc(...); let mut atk: GGLWEAutomorphismKey> = GGLWEAutomorphismKey::alloc(...); atk.decompress(module, &atk_compressed); let mut atk_prep: GGLWEAutomorphismKeyPrepared, B> = GLWESecretPrepared, B> = atk.prepare_alloc(...); ``` --- ## Encryption & Decryption * **Encryption** → Supported for all **standard** and **compressed** layouts. * **Decryption** → Only directly available for `LWECiphertext` and `GLWECiphertext`. However, it remains naturally usable on `GGLWE` and `GGSW` objects, since these are vectors/matrices of `GLWECiphertext`. ```rust let mut atk: GGLWEAutomorphismKey> = GGLWEAutomorphismKey::alloc(...); atk.encrypt_sk(...); atk.at(row, 0).decrypt(...); ``` ## Keyswitching, Automorphism & External Product Keyswitching, automorphisms, and external products are supported for all ciphertext types where they are well-defined. This includes subtypes such as `GGLWEAutomorphismKey`. For example: ```rust atk.external_product(...); ggsw.automorphism(...); ``` --- ## Additional Features * Ciphertexts: `LWE` and `GLWE` * `GLWE` ring packing * `GLWE` trace * Noise analysis for `GLWE`, `GGLWE`, `GGSW` * Basic operations over `GLWE` ciphertexts and plaintexts --- ## Tests A fully generic test suite is available in [`src/tests/generics`](./src/tests/generics).