BFV Parameters
Choosing FHE parameters involves balancing security, performance, and noise capacity. This page explains each parameter, the constraints that govern them, and the exact values NINE65 uses.
The Parameters
N — Ring Dimension
The polynomial degree. Must be a power of 2 (required by the NTT). Larger N means more security, more noise headroom, and slower operations.
| N | Security Range | Typical Use |
|---|---|---|
| 1024 | ~40 bits | Testing only |
| 2048 | ~80 bits | Testing only |
| 4096 | 128 bits | Standard production |
| 8192 | 128 bits (deep) | Deeper circuits at 128-bit security |
| 16384 | 192–256 bits | High/maximum security |
q — Ciphertext Modulus
The product of all NTT-friendly primes. Larger q means more noise budget but weaker security for a given N.
In NINE65, q is never stored as a single integer for production configs (it would overflow u64 for multi-prime setups). Instead, ciphertexts are represented in RNS form as residues modulo each prime separately.
t — Plaintext Modulus
The modulus for plaintext values. NINE65 uses t = 65537 (the Fermat prime F4, equal to 2^16 + 1) for all production configs. This gives a plaintext space of 65537 values per polynomial slot.
eta — CBD Parameter
The centered binomial distribution parameter. Error polynomials are sampled from CBD(eta), which produces coefficients in the range [-eta, eta]. Larger eta means wider error distribution, which increases noise growth but also increases security margin against certain attacks.
| Config | eta | Error Range |
|---|---|---|
| secure_128 | 3 | [-3, 3] |
| secure_192 | 4 | [-4, 4] |
| secure_256 | 5 | [-5, 5] |
NTT-Friendly Primes
For the Number Theoretic Transform to work in the ring Z_q[X]/(X^N + 1), each prime q_i must satisfy:
q_i - 1 === 0 (mod 2N)
This ensures the existence of a primitive 2N-th root of unity modulo q_i, which is required for the negacyclic NTT. NINE65 verifies this constraint at construction time in NTTEngine::try_new() and NTTEngineFFT::try_new().
HE Standard v1.1 Bounds
The Homomorphic Encryption Standard specifies maximum log2(q) values for each (N, security_level) pair:
| N | 128-bit max log2(q) | 192-bit max log2(q) | 256-bit max log2(q) |
|---|---|---|---|
| 1024 | 27 | 19 | 11 |
| 2048 | 54 | 37 | 29 |
| 4096 | 109 | 75 | 58 |
| 8192 | 218 | 152 | 118 |
| 16384 | 438 | 305 | 237 |
NINE65 validates compliance against these bounds in HEStandardBounds::is_compliant().
NINE65 Production Configurations
secure_128
The recommended configuration for most use cases.
| Parameter | Value |
|---|---|
| N | 4096 |
| Primes | 998244353, 985661441, 754974721 |
| Prime sizes | 3 x 30-bit |
| log2(q) | ~90 bits |
| t | 65537 |
| eta | 3 |
| Classical security | 129 bits |
| Quantum security | 86 bits |
| Hybrid security | 129 bits |
| HE Standard compliant | Yes (90 < 109 max for N=4096) |
secure_128_deep
Extended version for deeper circuits, using N=8192 to maintain security with a larger modulus.
| Parameter | Value |
|---|---|
| N | 8192 |
| Primes | 998244353, 985661441, 754974721, 469762049 |
| Prime sizes | 4 x 30-bit |
| log2(q) | ~120 bits |
| t | 65537 |
| eta | 3 |
secure_192
High-security configuration for long-term protection.
| Parameter | Value |
|---|---|
| N | 16384 |
| Primes | 998244353, 985661441, 754974721, 469762049, 167772161 |
| Prime sizes | 5 x 28–30-bit |
| log2(q) | ~147 bits |
| t | 65537 |
| eta | 4 |
| Classical security | 374 bits |
| Quantum security | 213 bits |
| Hybrid security | 318 bits |
secure_256
Maximum security. Significantly slower than lower tiers.
| Parameter | Value |
|---|---|
| N | 16384 |
| Primes | 998244353, 985661441, 754974721, 469762049, 167772161, 595591169 |
| Prime sizes | 6 x 28–30-bit |
| log2(q) | ~177 bits |
| t | 65537 |
| eta | 5 |
| Classical security | 311 bits |
| Quantum security | 177 bits |
| Hybrid security | 264 bits |
| HE Standard compliant | Yes (177 < 237 max for N=16384) |
Note: secure_256 uses 6 primes rather than 7. With 7 primes (log_q ~207), the ternary-secret MITM penalty would reduce hybrid security to 226 bits, which falls below the 230-bit minimum (256 x 90% threshold).
Construction-Time Verification
SecureConfig::new_verified() runs the lattice security estimator at construction time. This means you cannot create a SecureConfig with parameters that fail security checks:
// This runs the estimator and verifies the claimed 128-bit security
let config = SecureConfig::secure_128();
assert!(config.is_production_safe());
In release builds without the allow_insecure feature flag, the constructor panics if the estimated hybrid security is below 90% of the claimed level. Test configurations (test_fast_insecure, test_medium_insecure) are gated behind #[cfg(any(test, debug_assertions, feature = "allow_insecure"))] and cannot be constructed in release builds.
Choosing Parameters
- Default choice:
SecureConfig::secure_128(). Provides 128-bit security with good performance. - Deeper circuits:
SecureConfig::secure_128_deep(). Trades some speed for more multiplicative depth. - Long-term security:
SecureConfig::secure_192(). Use when data must remain secure for decades. - Maximum security:
SecureConfig::secure_256(). Use when regulatory requirements demand the highest tier.
Where to go next
- BFV Scheme — how the BFV encryption/decryption/evaluation pipeline works
- K-Elimination — how NINE65 achieves exact division in the RNS representation
- Security Configs — deeper dive into the lattice security estimator