arnaucube
arnaucube/fhe-studyPublic Self-hosted repository
fhe-study/arith/src/tuple_ring.rs
arith/src/tuple_ring.rsRaw
  1//! This file implements the struct for an Tuple of Ring Rq elements and its
  2//! operations, which are performed element-wise.
  3
  4use itertools::zip_eq;
  5use rand::{distributions::Distribution, Rng};
  6use std::ops::{Add, Mul, Neg, Sub};
  7
  8use crate::{Ring, RingParam};
  9
 10/// Tuple of K Ring (Rq) elements. We use Vec<R> to allocate it in the heap,
 11/// since if using a fixed-size array it would overflow the stack.
 12#[derive(Clone, Debug)]
 13pub struct TR<R: Ring> {
 14    pub k: usize,
 15    pub r: Vec<R>,
 16}
 17// TODO rm pub from Vec<R>, so that TR can not be created from a Vec with
 18// invalid length, since it has to be created using the `new` method.
 19
 20impl<R: Ring> TR<R> {
 21    pub fn new(k: usize, r: Vec<R>) -> Self {
 22        assert_eq!(r.len(), k);
 23        Self { k, r }
 24    }
 25    pub fn zero(k: usize, r_param: &RingParam) -> Self {
 26        Self {
 27            k,
 28            r: (0..k).into_iter().map(|_| R::zero(r_param)).collect(),
 29        }
 30    }
 31    pub fn rand(
 32        mut rng: impl Rng,
 33        dist: impl Distribution<f64>,
 34        k: usize,
 35        r_param: &RingParam,
 36    ) -> Self {
 37        Self {
 38            k,
 39            r: (0..k)
 40                .into_iter()
 41                .map(|_| R::rand(&mut rng, &dist, r_param))
 42                .collect(),
 43        }
 44    }
 45    // returns the decomposition of each polynomial element
 46    pub fn decompose(&self, beta: u32, l: u32) -> Vec<Self> {
 47        unimplemented!()
 48        // self.0.iter().map(|r| r.decompose(beta, l)).collect() // this is Vec<Vec<Vec<R::C>>>
 49    }
 50}
 51
 52impl TR<crate::torus::T64> {
 53    pub fn mod_switch(&self, q2: u64) -> TR<crate::torus::T64> {
 54        TR::<crate::torus::T64> {
 55            k: self.k,
 56            r: self.r.iter().map(|c_i| c_i.mod_switch(q2)).collect(),
 57        }
 58    }
 59    // pub fn mod_switch(&self, Q2: u64) -> TR<crate::torus::T64, K> {
 60    //     TR(self.0.iter().map(|c_i| c_i.mod_switch(Q2)).collect())
 61    // }
 62}
 63impl TR<crate::ring_torus::Tn> {
 64    pub fn left_rotate(&self, h: usize) -> Self {
 65        TR {
 66            k: self.k,
 67            r: self.r.iter().map(|c_i| c_i.left_rotate(h)).collect(),
 68        }
 69    }
 70}
 71
 72impl<R: Ring> TR<R> {
 73    pub fn iter(&self) -> std::slice::Iter<R> {
 74        self.r.iter()
 75    }
 76}
 77
 78impl<R: Ring> Add<TR<R>> for TR<R> {
 79    type Output = Self;
 80    fn add(self, other: Self) -> Self {
 81        debug_assert_eq!(self.k, other.k);
 82
 83        Self {
 84            k: self.k,
 85            r: zip_eq(self.r, other.r)
 86                .map(|(s, o)| s + o)
 87                .collect::<Vec<_>>(),
 88        }
 89    }
 90}
 91
 92impl<R: Ring> Sub<TR<R>> for TR<R> {
 93    type Output = Self;
 94    fn sub(self, other: Self) -> Self {
 95        debug_assert_eq!(self.k, other.k);
 96
 97        Self {
 98            k: self.k,
 99            r: zip_eq(self.r, other.r).map(|(s, o)| s - o).collect(),
100        }
101    }
102}
103
104impl<R: Ring> Neg for TR<R> {
105    type Output = Self;
106
107    fn neg(self) -> Self::Output {
108        Self {
109            k: self.k,
110            r: self.r.iter().map(|e_i| -e_i.clone()).collect(),
111        }
112    }
113}
114
115/// for (TR,TR), the Mul operation is defined as the dot product:
116/// for A, B \in R^k, result = Σ A_i * B_i \in R
117impl<R: Ring> Mul<TR<R>> for TR<R> {
118    type Output = R;
119    fn mul(self, other: Self) -> R {
120        debug_assert_eq!(self.k, other.k);
121
122        zip_eq(self.r, other.r).map(|(s, o)| s * o).sum()
123    }
124}
125impl<R: Ring> Mul<&TR<R>> for &TR<R> {
126    type Output = R;
127    fn mul(self, other: &TR<R>) -> R {
128        debug_assert_eq!(self.k, other.k);
129
130        zip_eq(self.r.clone(), other.r.clone())
131            .map(|(s, o)| s * o)
132            .sum()
133    }
134}
135
136/// for (TR, R), the Mul operation is defined as each element of TR is
137/// multiplied by R
138impl<R: Ring> Mul<R> for TR<R> {
139    type Output = TR<R>;
140    fn mul(self, other: R) -> TR<R> {
141        Self {
142            k: self.k,
143            r: self.r.iter().map(|s| s.clone() * other.clone()).collect(),
144        }
145    }
146}
147impl<R: Ring> Mul<&R> for &TR<R> {
148    type Output = TR<R>;
149    fn mul(self, other: &R) -> TR<R> {
150        TR::<R> {
151            k: self.k,
152            r: self.r.iter().map(|s| s.clone() * other.clone()).collect(),
153        }
154    }
155}