1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
//! NEON/ASIMD-accelerated CPU backend for the Poulpy lattice cryptography library.
//!
//! This crate provides `FFT64Neon` and `NTT4x30Neon`, high-performance backend
//! implementations for [`poulpy_hal`] that leverage AArch64 SIMD (NEON / ASIMD)
//! to accelerate cryptographic operations in fully homomorphic encryption (FHE)
//! schemes based on Module-LWE.
//!
//! # Architecture
//!
//! `poulpy_hal` defines a hardware abstraction layer (HAL) via the [`Backend`](poulpy_hal::layouts::Backend)
//! trait and a family of _open extension point_ (OEP) traits in [`poulpy_hal::oep`]. This crate
//! implements every OEP trait for `FFT64Neon` and `NTT4x30Neon` using hand-tuned NEON intrinsics
//! and inline assembly where profiling demonstrates performance benefits over compiler-generated code.
//!
//! The internal modules are organized by operation domain:
//!
//! | Module | Domain |
//! |-----------------|-----------------------------------------------------------|
//! | `module` | Backend handle lifecycle, FFT/NTT table management |
//! | `neon` | Low-level NEON kernels (FFT, NTT, mat-vec, conversions) |
//! | `fft64` | f64 complex-FFT backend wiring (`FFT64Neon`) |
//! | `ntt4x30` | Q120 NTT backend wiring (`NTT4x30Neon`), VMP |
//! | `znx` | Single ring element (`Z[X]/(X^n+1)`) SIMD arithmetic |
//! | `vec_znx_big` | Large-coefficient (i128) ring element vectors |
//!
//! # Scalar types
//!
//! - `FFT64Neon`: `ScalarPrep = f64`, `ScalarBig = i64`.
//! - `NTT4x30Neon`: `ScalarPrep = Q120bScalar` (4 × u64 CRT residues over `Primes30`), `ScalarBig = i128`.
//!
//! # CPU requirements
//!
//! This backend **requires** AArch64 CPUs. NEON / ASIMD is part of the AArch64
//! architectural baseline, so no runtime feature detection is needed: any
//! AArch64 target supports the full SIMD instruction set used by this crate.
//!
//! # Compile-time requirements
//!
//! NEON / ASIMD is enabled by default on AArch64 targets, so no `RUSTFLAGS`
//! target-feature flag is required:
//!
//! ```text
//! cargo build --features enable-neon
//! ```
//!
//! If `enable-neon` is enabled but the target architecture is not `aarch64`,
//! the build fails immediately with a `compile_error!`.
//!
//! # Correctness guarantees
//!
//! ## Determinism
//!
//! Integer / modular operations (`Znx*`, `I128BigOps`, `Ntt*`, `NttDFTExecute`) produce
//! **bit-identical results** against `poulpy-cpu-ref`. Floating-point operations in FFT
//! match the reference within ULP tolerance — NEON kernels use FMA (`vfmaq_f64`) where
//! the scalar reference does not, so individual rounding bits may differ.
//!
//! ## Overflow handling
//!
//! Integer overflow is **intentional** and managed through bivariate polynomial representation.
//! The normalization functions (`znx_normalize_*`) use wrapping arithmetic to propagate carries
//! correctly across limbs in base-2^k representation.
//!
//! ## Memory alignment
//!
//! All data layouts enforce 64-byte alignment (matching cache line size) as specified by
//! `poulpy_hal::DEFAULTALIGN`. This alignment enables aligned SIMD loads/stores and
//! the use of `stnp` non-temporal pair stores in the VMP overwrite-apply path.
//!
//! ## Safety invariants
//!
//! Many functions are marked `unsafe` and require:
//! - Target architecture is AArch64 (verified at compile time via `compile_error!`).
//! - Input slices have matching lengths where documented.
//! - Input values satisfy documented bounds (e.g., `|x| < 2^50` for IEEE 754 conversions).
//! - Buffers are properly aligned (enforced by HAL allocators).
//!
//! Violating these invariants may result in:
//! - Undefined behavior (e.g., out-of-bounds memory access).
//! - Silent incorrect results (e.g., exceeding numeric bounds in FP conversion).
//! - Panics (in debug mode via assertions, or unconditionally for critical invariants).
//!
//! # Performance characteristics
//!
//! ## Asymptotic complexity
//!
//! - **FFT/IFFT**: O(n log n) for polynomial degree n.
//! - **Convolution**: O(n log n) via FFT-based approach.
//! - **VMP**: O(n · nrows · ncols) over a prime-major prepared-matrix layout.
//! - **Normalization**: O(n) per limb with vectorized digit extraction.
//!
//! ## Speedup over reference backend
//!
//! Speedups depend on the host micro-architecture and on the operation profile of the
//! workload. Run the benches in `poulpy-bench` (or the bundled `bench_neon_vs_ref` example)
//! on the target host for representative numbers. Qualitative trends:
//!
//! - **Ring element arithmetic** (add/sub/negate): bandwidth-bound, modest gains.
//! - **NTT/INTT, mat-vec, and convolution**: noticeable gains from hand-tuned NEON kernels;
//! the convolution apply path dispatches to the fused canonical `ntt_mul_bbc_tile4_x2` kernel.
//! - **VMP** (large degree): the largest gains, scaling with coefficient size;
//! uses `stnp` non-temporal stores to avoid cache pollution.
//!
//! ## Memory layout
//!
//! - **Vectorized storage**: Elements packed in groups of 4 (matching the AVX backend's
//! `i64` block stride for cross-backend layout compatibility). NEON's 128-bit registers
//! process each block as two `int64x2_t` / `uint64x2_t` per iteration.
//! - **Tail handling**: Scalar fallback for lengths not divisible by 4.
//! - **Cache-friendly**: 64-byte alignment ensures single cache line per vector load.
//! - **Q120 layout**: a q120 vector packs four u64 lanes (one per `Primes30` prime) across
//! two NEON registers — `lo` for primes 0/1, `hi` for primes 2/3.
//!
//! # Threading and concurrency
//!
//! - **`FFT64Neon` / `NTT4x30Neon` are `Send + Sync`**: zero-sized marker types, no internal state.
//! - **`Module<FFT64Neon>` / `Module<NTT4x30Neon>` are `Send + Sync`**: FFT/NTT tables are immutable after construction.
//! - **Operations require `&mut` for outputs**: prevents data races at the API level.
//! - **No internal locking**: all synchronization is the caller's responsibility.
//!
//! # Feature flags
//!
//! - `enable-neon` (required): opt-in compilation of the backend. Without this feature,
//! the crate is an empty shell, allowing the workspace to build on non-aarch64 targets.
//! - `enable-ckks` (optional): wires the CKKS scheme OEP impls for both backends.
//!
//! # Platform support
//!
//! - **Required**: AArch64 (Apple Silicon, ARMv8-A and later).
//! - **Tested under**: native AArch64 hosts.
//! - **Not supported**: 32-bit ARM, x86, RISC-V, or any other architecture.
//!
//! # Threat model
//!
//! This library assumes an **"honest but curious"** adversary model:
//! - **No malicious inputs**: callers are trusted to provide well-formed data within documented bounds.
//! - **No timing attack mitigation**: operations are not constant-time (performance is prioritized).
//! - **Memory safety**: bounds are validated to prevent crashes and corruption, but not for security.
//!
//! # Usage
//!
//! This crate exports two public marker types, `FFT64Neon` and `NTT4x30Neon`, used as type
//! parameters to the HAL generic types. Application code typically does not import this
//! crate directly, but instead uses it via `poulpy_core` or `poulpy_bin_fhe` with
//! runtime backend selection.
//!
//! # Versioning and stability
//!
//! This crate follows semantic versioning. The public API consists of the `FFT64Neon` and
//! `NTT4x30Neon` marker types, the `FFT64NeonReimTable` and `ReimFFT(I)Neon` FFT executors,
//! and their trait implementations from `poulpy_hal::oep`. All other items are
//! implementation details subject to change without notice.
compile_error!;
pub use ;
pub use NTT4x30Neon;
// --- TransferFrom impls ---