he_ring/lib.rs
1#![feature(never_type)]
2#![feature(fn_traits)]
3#![feature(unboxed_closures)]
4#![feature(test)]
5#![feature(const_type_name)]
6#![feature(allocator_api)]
7#![feature(ptr_alignment_type)]
8#![feature(associated_type_defaults)]
9#![feature(generic_arg_infer)]
10#![feature(min_specialization)]
11#![feature(array_chunks)]
12#![feature(mapped_lock_guards)]
13
14#![allow(non_snake_case)]
15#![allow(type_alias_bounds)]
16#![allow(non_camel_case_types)]
17#![allow(non_upper_case_globals)]
18
19#![doc = include_str!("../Readme.md")]
20
21use std::alloc::Global;
22use std::time::Instant;
23
24use feanor_math::integer::BigIntRing;
25use feanor_math::primitive_int::*;
26use feanor_math::ring::*;
27use feanor_math::rings::zn::zn_64::Zn;
28
29extern crate feanor_math;
30#[cfg(feature = "use_hexl")]
31extern crate feanor_math_hexl;
32extern crate test;
33extern crate thread_local;
34extern crate serde;
35extern crate rand;
36extern crate rand_distr;
37
38///
39/// Simple way to create a ring element from a list of its coefficients as `i32`.
40///
41#[cfg(test)]
42fn ring_literal<R>(ring: R, data: &[i32]) -> El<R>
43 where R: RingStore,
44 R::Type: feanor_math::rings::extension::FreeAlgebra
45{
46 use feanor_math::homomorphism::*;
47 use feanor_math::rings::extension::*;
48
49 ring.from_canonical_basis(data.iter().map(|x| ring.base_ring().int_hom().map(*x)))
50}
51
52///
53/// The default convolution algorithm that will be used by all tests and benchmarks.
54/// It is also a good choice when instantiating homomorphic encryption as a user.
55///
56/// By default, it will point to a pure-rust implementation of convolution (currently
57/// [`crate::ntt::ntt_convolution::NTTConv`]), but can be changed by using the feature
58/// `use_hexl`.
59///
60#[cfg(feature = "use_hexl")]
61pub type DefaultConvolution = feanor_math_hexl::conv::HEXLConvolution;
62
63///
64/// The default convolution algorithm that will be used by all tests and benchmarks.
65/// It is also a good choice when instantiating homomorphic encryption as a user.
66///
67/// By default, it will point to a pure-rust implementation of convolution (currently
68/// [`crate::ntt::ntt_convolution::NTTConv`]), but can be changed by using the feature
69/// `use_hexl`.
70///
71#[cfg(not(feature = "use_hexl"))]
72pub type DefaultConvolution = crate::ntt::ntt_convolution::NTTConv<Zn>;
73
74///
75/// The default algorithm for computing negacyclic NTTs that will be used by
76/// all tests and benchmarks. It is also a good choice when instantiating homomorphic
77/// encryption as a user.
78///
79/// By default, it will point to a pure-rust implementation of the negacyclic NTT
80/// (currently [`crate::number_ring::pow2_cyclotomic::RustNegacyclicNTT`]), but can be
81/// changed by using the feature `use_hexl`.
82///
83#[cfg(feature = "use_hexl")]
84pub type DefaultNegacyclicNTT = feanor_math_hexl::hexl::HEXLNegacyclicNTT;
85
86///
87/// The default algorithm for computing negacyclic NTTs that will be used by
88/// all tests and benchmarks. It is also a good choice when instantiating homomorphic
89/// encryption as a user.
90///
91/// By default, it will point to a pure-rust implementation of the negacyclic NTT
92/// (currently [`crate::number_ring::pow2_cyclotomic::RustNegacyclicNTT`]), but can be
93/// changed by using the feature `use_hexl`.
94///
95#[cfg(not(feature = "use_hexl"))]
96pub type DefaultNegacyclicNTT = crate::number_ring::pow2_cyclotomic::RustNegacyclicNTT<Zn>;
97
98///
99/// The default allocator for ciphertext ring elements, which will be used by all tests and
100/// benchmarks. It is also a good choice when instantiating homomorphic encryption as a user.
101///
102/// Currently, this is always [`std::alloc::Global`].
103///
104pub type DefaultCiphertextAllocator = Global;
105
106///
107/// Euler's totient function.
108///
109#[allow(unused)]
110fn euler_phi(factorization: &[(i64, usize)]) -> i64 {
111 StaticRing::<i64>::RING.prod(factorization.iter().map(|(p, e)| (p - 1) * StaticRing::<i64>::RING.pow(*p, e - 1)))
112}
113
114///
115/// Euler's totient function.
116///
117/// It takes a list of all distinct prime factors of `n`, and returns `phi(n)`.
118///
119fn euler_phi_squarefree(factorization: &[i64]) -> i64 {
120 StaticRing::<i64>::RING.prod(factorization.iter().map(|p| p - 1))
121}
122
123///
124/// Runs the given function. If `LOG` is true, its running time is printed to stdout.
125///
126pub fn log_time<F, T, const LOG: bool, const COUNTER_VAR_COUNT: usize>(description: &str, step_fn: F) -> T
127 where F: FnOnce(&mut [usize; COUNTER_VAR_COUNT]) -> T
128{
129 if LOG {
130 println!("{}", description);
131 }
132 let mut counters = [0; COUNTER_VAR_COUNT];
133 let start = Instant::now();
134 let result = step_fn(&mut counters);
135 let end = Instant::now();
136 if LOG {
137 println!("done in {} ms, {:?}", (end - start).as_millis(), counters);
138 }
139 return result;
140}
141
142///
143/// The ring of integers, implemented using arbitrary precision
144///
145const ZZbig: BigIntRing = BigIntRing::RING;
146///
147/// The ring of integers, implemented using 64-bit integers
148///
149const ZZi64: StaticRing<i64> = StaticRing::<i64>::RING;
150///
151/// The ring of integers, implemented using 128-bit integers
152///
153const ZZi128: StaticRing<i128> = StaticRing::<i128>::RING;
154
155///
156/// Contains some macros that mimic `#[derive(Deserialize)]` but for [`serde::de::DeserializeSeed`].
157///
158mod serialization_helper;
159
160///
161/// Contains an abstraction for NTTs and convolutions, which can then be
162/// used to configure the ring implementations in this crate.
163///
164pub mod ntt;
165
166///
167/// Defines the trait [`cyclotomic::CyclotomicRing`] for rings of the form `R[X]/(Phi_n)`, where `R` is any base ring.
168///
169pub mod cyclotomic;
170
171///
172/// Implementation of fast RNS conversion algorithms.
173///
174pub mod rnsconv;
175
176///
177/// Contains an HE-specific abstraction for number rings.
178///
179pub mod number_ring;
180
181///
182/// Implementation of rings using double-RNS representation.
183///
184pub mod ciphertext_ring;
185
186///
187/// Contains an implementation of "gadget products", which are a form of inner
188/// products that are commonly used in HE to compute multiplications of noisy values
189/// in a way that reduces the increase in noise.
190///
191pub mod gadget_product;
192
193///
194/// Contains an implementation of the BFV scheme.
195///
196pub mod bfv;
197
198///
199/// The implementation of arithmetic-galois circuits (i.e. circuits built
200/// from linear combination, multiplication and galois gates).
201///
202pub mod circuit;
203
204///
205/// Contains algorithms to compute linear transformations and represent
206/// them as linear combination of Galois automorphisms, as required for
207/// (second-generation) HE schemes.
208///
209pub mod lintransform;
210
211///
212/// Contains algorithms to build arithmetic circuits, with a focus on
213/// digit extraction polynomials.
214///
215pub mod digitextract;
216
217///
218/// Contains an implementation of the BGV scheme.
219///
220pub mod bgv;
221
222///
223/// This is a workaround for displaying examples on `docs.rs`.
224///
225/// Contains an empty submodule for each example, whose documentation gives
226/// a guide to the corresponding concepts of HE-Ring.
227///
228/// Note that this module is only included when building the documentation,
229/// you cannot use it when importing `he-ring` as a crate.
230///
231#[cfg(any(doc, doctest))]
232pub mod examples {
233 #[doc = include_str!("../examples/bfv_basics/Readme.md")]
234 pub mod bfv_basics {}
235 #[doc = include_str!("../examples/bgv_basics/Readme.md")]
236 pub mod bgv_basics {}
237 #[doc = include_str!("../examples/bfv_impl_v1/Readme.md")]
238 pub mod bfv_impl_v1 {}
239 #[doc = include_str!("../examples/bfv_impl_v2/Readme.md")]
240 pub mod bfv_impl_v2 {}
241}