fhe-study/arith/src/ring.rs
arith/src/ring.rsRaw
1use rand::{distr::Distribution, Rng};
2use std::fmt::Debug;
3use std::iter::Sum;
4use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct RingParam {
8 pub q: u64, // TODO think if really needed or it's fine with coeffs[0].q
9 pub n: usize,
10}
11
12/// Represents a ring element. Currently implemented by ring_nq.rs#Rq and
13/// ring_torus.rs#Tn. Is not a 'pure algebraic ring', but more a custom trait
14/// definition which includes methods like `mod_switch`.
15// assumed to be mod (X^N +1)
16pub trait Ring:
17 Sized
18 + Add<Output = Self>
19 + AddAssign
20 + Sum
21 + Sub<Output = Self>
22 + SubAssign
23 + Mul<Output = Self> // internal product
24 + Mul<u64, Output = Self> // scalar mul, external product
25 + Mul<Self::C, Output = Self>
26 + Neg<Output = Self>
27 + PartialEq
28 + Debug
29 + Clone
30 // + Copy
31 + Sum<<Self as Add>::Output>
32 + Sum<<Self as Mul>::Output>
33{
34 /// C defines the coefficient type
35 type C: Debug + Clone;
36
37 fn param(&self) -> RingParam;
38 fn coeffs(&self) -> Vec<Self::C>;
39 fn zero(param: &RingParam) -> Self;
40 // note/wip/warning: dist (0,q) with f64, will output more '0=q' elements than other values
41 fn rand(rng: impl Rng, dist: impl Distribution<f64>, param: &RingParam) -> Self;
42
43 fn from_vec(param: &RingParam, coeffs: Vec<Self::C>) -> Self;
44
45 fn decompose(&self, beta: u32, l: u32) -> Vec<Self>;
46
47 fn remodule(&self, p:u64) -> impl Ring;
48 fn mod_switch(&self, p:u64) -> impl Ring;
49
50 /// returns [ [(num/den) * self].round() ] mod q
51 /// ie. performs the multiplication and division over f64, and then it
52 /// rounds the result, only applying the mod Q (if the ring is mod Q) at the
53 /// end.
54 fn mul_div_round(&self, num: u64, den: u64) -> Self;
55}