Poulpy is a fast and modular FHE library that implements Ring-Learning-With-Errors based homomorphic encryption over the Torus. It adopts the bivariate polynomial representation proposed in Revisiting Key Decomposition Techniques for FHE: Simpler, Faster and More Generic to represent Torus polynomials. Compared with the residue number system (RNS), this representation provides simpler and more reusable arithmetic, a common plaintext space for all schemes, and native bridges between schemes. Poulpy also decouples scheme implementations from the polynomial arithmetic backend by being built from the ground up around a hardware abstraction layer that closely matches the API of spqlios-arithmetic. Leveraging the HAL, users can develop applications generic over the backend and choose a backend at runtime.
poulpy-hal: a crate providing layouts and a trait-based hardware acceleration layer with open extension points, matching the API and types of spqlios-arithmetic. This crate does not provide concrete implementations other than the layouts (e.g.VecZnx,VmpPmat).poulpy-core: a backend-agnostic crate implementing scheme-agnostic RLWE arithmetic for LWE, GLWE, GGLWE, and GGSW ciphertexts usingpoulpy-hal. It can be instantiated with any backend crate (e.g.poulpy-cpu-ref,poulpy-cpu-avx).poulpy-ckks: a backend-agnostic leveled CKKS implementation built onpoulpy-coreandpoulpy-hal. This is the first iteration of the CKKS crate: the evaluator is functional and tested, but the public API is still subject to change.poulpy-bin-fhe: a backend-agnostic binary/gate-level FHE crate built onpoulpy-coreandpoulpy-hal. This replaces the formerpoulpy-schemescrate.poulpy-cpu-ref: the reference CPU implementation ofpoulpy-hal.poulpy-cpu-avx: an AVX2/FMA accelerated CPU implementation ofpoulpy-hal. Enable it with theenable-avxfeature on crates that expose that feature.poulpy-bench: the consolidated Criterion benchmark suite for the workspace. It is an internal workspace crate and is not published to crates.io.
Existing FHE implementations (such as Lattigo or OpenFHE) use the residue number system (RNS) to represent large integers. Although the parallelism and carry-less arithmetic offered by the RNS representation provide efficient modular arithmetic over large integers, RNS also has drawbacks in the context of FHE. The main idea behind the bivariate representation is to decouple cyclotomic arithmetic from large-number arithmetic. Instead of using the RNS representation for large integers, integers are decomposed in base
This provides the following benefits:
-
Intuitive, efficient, and reusable parameterization and instances: Only the bit size of the modulus is required from the user (i.e. Torus precision). Parameterization is therefore natural and generic, and instances can be reused for any circuit consuming the same homomorphic capacity without loss of efficiency. With the RNS representation, individual NTT-friendly primes need to be specified for each level, making parameterization less user friendly and more circuit specific.
-
Optimal and granular rescaling: Ciphertext rescaling is carried out with bit shifts, enabling bit-level rescaling and precise noise/homomorphic-capacity management. In the RNS representation, ciphertext division can only be done by one of the primes composing the modulus, making scale management more difficult and often less efficient.
-
Linear number of DFTs in the half external product: The bivariate representation of the coefficients implicitly provides the digit decomposition. As a result, the number of DFTs is linear in the number of limbs, unlike in the RNS representation where it is quadratic due to RNS basis conversion. This enables much more efficient key switching, which is one of the most used and expensive FHE operations.
-
Unified plaintext space: The bivariate polynomial representation is, by nature, a high-precision discretized representation of the Torus
$\mathbb{T}_{N}[X]$ . Using the Torus as the common plaintext space for all schemes follows the vision of CHIMERA: Combining Ring-LWE-based Fully Homomorphic Encryption Schemes: unifying RLWE-based FHE schemes (TFHE, FHEW, BGV, BFV, CLPX, GBFV, CKKS, ...) under a single scheme with different encodings, enabling native and efficient scheme switching. -
Simpler implementation: Since cyclotomic arithmetic is decoupled from the coefficient representation, the same pipeline (including DFT) can be reused for all limbs, unlike in the RNS representation. The bivariate representation also has a straightforward flat, aligned, and vectorized memory layout. These properties make it a strong target for hardware acceleration.
-
Deterministic computation: Although it is defined on the Torus, bivariate arithmetic remains integer polynomial arithmetic, ensuring all computations are deterministic. Outputs are reproducible and identical regardless of the backend or hardware.
poulpy-hal: https://crates.io/crates/poulpy-halpoulpy-core: https://crates.io/crates/poulpy-corepoulpy-ckks: https://crates.io/crates/poulpy-ckkspoulpy-bin-fhe: https://crates.io/crates/poulpy-bin-fhepoulpy-cpu-ref: https://crates.io/crates/poulpy-cpu-refpoulpy-cpu-avx: https://crates.io/crates/poulpy-cpu-avx
For example, a CKKS application can depend on:
[dependencies]
poulpy-ckks = "0.5"
poulpy-cpu-ref = "0.5"For binary FHE:
[dependencies]
poulpy-bin-fhe = "0.5"
poulpy-cpu-ref = "0.5"- Crate package pages and generated Rust documentation are linked from the crates.io entries above.
- Architecture diagrams and design notes live in the
/docsfolder. - Crate-specific READMEs provide more focused usage notes, especially
poulpy-ckksandpoulpy-bench.
We welcome external contributions, please see CONTRIBUTING.
Please see SECURITY.
Poulpy is licensed under the Apache-2.0 License. See NOTICE & LICENSE.
Poulpy was incubated by PhantomZone with grants from Ethereum Foundation and ENS Foundation.
Consider joining our telegram group for any questions or discussions.
Team behind poulpy accepts financial contributions over various platforms. Please see funding.json for funding.
Please use the following BibTeX entry for citing Poulpy:
@misc{poulpy,
title = {Poulpy v0.5.0},
howpublished = {Online: \url{https://github.com/poulpy-fhe/poulpy}},
month = Apr,
year = 2026,
note = {Phantom Zone}
}

