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 anyhow::Result;
 5use itertools::zip_eq;
 6use rand::{distributions::Distribution, Rng};
 7use rand_distr::{Normal, Uniform};
 8use std::iter::Sum;
 9use std::{
10    array,
11    ops::{Add, Mul, Sub},
12};
13
14use crate::Ring;
15
16/// Tuple of K Ring (Rq) elements. We use Vec<R> to allocate it in the heap,
17/// since if using a fixed-size array it would overflow the stack.
18#[derive(Clone, Debug)]
19pub struct TR<R: Ring, const K: usize>(pub Vec<R>);
20
21impl<R: Ring, const K: usize> TR<R, K> {
22    pub fn zero() -> Self {
23        Self((0..K).into_iter().map(|_| R::zero()).collect())
24    }
25    pub fn rand(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self {
26        Self(
27            (0..K)
28                .into_iter()
29                .map(|_| R::rand(&mut rng, &dist))
30                .collect(),
31        )
32    }
33    // returns the decomposition of each polynomial element
34    pub fn decompose(&self, beta: u32, l: u32) -> Vec<Self> {
35        unimplemented!()
36        // self.0.iter().map(|r| r.decompose(beta, l)).collect() // this is Vec<Vec<Vec<R::C>>>
37    }
38}
39
40impl<R: Ring, const K: usize> Add<TR<R, K>> for TR<R, K> {
41    type Output = Self;
42    fn add(self, other: Self) -> Self {
43        Self(
44            zip_eq(self.0, other.0)
45                .map(|(s, o)| s + o)
46                .collect::<Vec<_>>(),
47        )
48    }
49}
50
51impl<R: Ring, const K: usize> Sub<TR<R, K>> for TR<R, K> {
52    type Output = Self;
53    fn sub(self, other: Self) -> Self {
54        Self(zip_eq(self.0, other.0).map(|(s, o)| s - o).collect())
55    }
56}
57
58/// for (TR,TR), the Mul operation is defined as the dot product:
59/// for A, B \in R^k, result = Σ A_i * B_i \in R
60impl<R: Ring, const K: usize> Mul<TR<R, K>> for TR<R, K> {
61    type Output = R;
62    fn mul(self, other: Self) -> R {
63        zip_eq(self.0, other.0).map(|(s, o)| s * o).sum()
64    }
65}
66impl<R: Ring, const K: usize> Mul<&TR<R, K>> for &TR<R, K> {
67    type Output = R;
68    fn mul(self, other: &TR<R, K>) -> R {
69        zip_eq(self.0.clone(), other.0.clone())
70            .map(|(s, o)| s * o)
71            .sum()
72    }
73}
74
75/// for (TR, R), the Mul operation is defined as each element of TR is
76/// multiplied by R
77impl<R: Ring, const K: usize> Mul<R> for TR<R, K> {
78    type Output = TR<R, K>;
79    fn mul(self, other: R) -> TR<R, K> {
80        Self(self.0.iter().map(|s| s.clone() * other.clone()).collect())
81    }
82}
83impl<R: Ring, const K: usize> Mul<&R> for &TR<R, K> {
84    type Output = TR<R, K>;
85    fn mul(self, other: &R) -> TR<R, K> {
86        TR::<R, K>(self.0.iter().map(|s| s.clone() * other.clone()).collect())
87    }
88}