arnaucube
arnaucube/fhe-studyPublic Self-hosted repository
fit T64 into the 'Ring' trait, this is to use it in tfhe instead of using Tn<1> which is more tedious
arnaucube git@arnaucube.com
Sun, 27 Jul 2025 19:22:41 +0000
commit

4f89caef1eab17c5ae90fc9be115f9ae1b150247

parent

81306edf05817861d43bdf90b6ef01c5c2653f6d

4 files changed, 69 insertions(+), 15 deletions(-)

jump to
M arith/src/ring.rs → arith/src/ring.rs

@@ -1,7 +1,7 @@

use rand::{distributions::Distribution, Rng}; use std::fmt::Debug; use std::iter::Sum; -use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}; /// Represents a ring element. Currently implemented by ring_nq.rs#Rq and /// ring_torus.rs#Tn. Is not a 'pure algebraic ring', but more a custom trait

@@ -17,6 +17,7 @@ + SubAssign

+ Mul<Output = Self> // internal product + Mul<u64, Output = Self> // scalar mul, external product + Mul<Self::C, Output = Self> + + Neg<Output = Self> + PartialEq + Debug + Clone
M arith/src/ring_torus.rs → arith/src/ring_torus.rs

@@ -10,7 +10,7 @@

use rand::{distributions::Distribution, Rng}; use std::array; use std::iter::Sum; -use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}; use crate::{ring::Ring, torus::T64, Rq, Zq};

@@ -34,7 +34,7 @@ Self(array::from_fn(|_| T64::zero()))

} fn rand(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self { - Self(array::from_fn(|_| T64::rand_f64(&mut rng, &dist))) + Self(array::from_fn(|_| T64::rand(&mut rng, &dist))) } fn from_vec(coeffs: Vec<Self::C>) -> Self {

@@ -149,6 +149,14 @@ fn sub_assign(&mut self, rhs: Self) {

for i in 0..N { self.0[i] -= rhs.0[i]; } + } +} + +impl<const N: usize> Neg for Tn<N> { + type Output = Self; + + fn neg(self) -> Self::Output { + Tn(array::from_fn(|i| -self.0[i])) } }
M arith/src/torus.rs → arith/src/torus.rs

@@ -4,37 +4,65 @@ iter::Sum,

ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use crate::ring::Ring; + /// Let 𝕋 = ℝ/ℤ, where 𝕋 is a ℤ-module, with homogeneous external product. /// Let 𝕋q /// T64 is 𝕋q with q=2^Ω, with Ω=64. We identify 𝕋q=(1/q)ℤ/ℤ ≈ ℤq. #[derive(Debug, Clone, Copy, PartialEq)] pub struct T64(pub u64); -impl T64 { - pub fn zero() -> Self { +// implement the `Ring` trait for T64, so that it can be used where we would use +// `Tn<1>`. +impl Ring for T64 { + type C = T64; + const Q: u64 = u64::MAX; // WIP + const N: usize = 1; + + fn coeffs(&self) -> Vec<T64> { + vec![self.clone()] + } + fn zero() -> Self { Self(0u64) } - pub fn rand(mut rng: impl Rng, dist: impl Distribution<u64>) -> Self { - let r: u64 = dist.sample(&mut rng); - Self(r) - } - pub fn rand_f64(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self { + fn rand(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self { let r: f64 = dist.sample(&mut rng); Self(r.round() as u64) + } + fn from_vec(coeffs: Vec<Self::C>) -> Self { + assert_eq!(coeffs.len(), 1); + coeffs[0] } + // TODO rm beta & l from inputs, make it always beta=2,l=64. /// Note: only beta=2 and l=64 is supported. - pub fn decompose(&self, beta: u32, l: u32) -> Vec<Self> { + fn decompose(&self, beta: u32, l: u32) -> Vec<Self> { assert_eq!(beta, 2u32); // only beta=2 supported - assert_eq!(l, 64u32); // only l=64 supported + // assert_eq!(l, 64u32); // only l=64 supported - (0..64) + // (0..64) + (0..l) .rev() .map(|i| T64(((self.0 >> i) & 1) as u64)) .collect() } - pub fn mod_switch<const Q2: u64>(&self) -> T64 { + fn remodule<const P: u64>(&self) -> T64 { + todo!() + } + + fn mod_switch<const Q2: u64>(&self) -> T64 { todo!() + } + + fn mul_div_round(&self, num: u64, den: u64) -> Self { + T64(((num as f64 * self.0 as f64) / den as f64).round() as u64) + } +} + +impl T64 { + pub fn rand_u64(mut rng: impl Rng, dist: impl Distribution<u64>) -> Self { + let r: u64 = dist.sample(&mut rng); + Self(r) } }

@@ -99,6 +127,9 @@ impl Mul<u64> for T64 {

type Output = Self; fn mul(self, s: u64) -> Self { + if self.0 == 0 { + return Self(0); + } Self(self.0.wrapping_mul(s)) } }
M arith/src/tuple_ring.rs → arith/src/tuple_ring.rs

@@ -8,7 +8,7 @@ use rand_distr::{Normal, Uniform};

use std::iter::Sum; use std::{ array, - ops::{Add, Mul, Sub}, + ops::{Add, Mul, Neg, Sub}, }; use crate::Ring;

@@ -34,6 +34,12 @@ // returns the decomposition of each polynomial element

pub fn decompose(&self, beta: u32, l: u32) -> Vec<Self> { unimplemented!() // self.0.iter().map(|r| r.decompose(beta, l)).collect() // this is Vec<Vec<Vec<R::C>>> + } +} + +impl<R: Ring, const K: usize> TR<R, K> { + pub fn iter(&self) -> std::slice::Iter<R> { + self.0.iter() } }

@@ -52,6 +58,14 @@ impl<R: Ring, const K: usize> Sub<TR<R, K>> for TR<R, K> {

type Output = Self; fn sub(self, other: Self) -> Self { Self(zip_eq(self.0, other.0).map(|(s, o)| s - o).collect()) + } +} + +impl<R: Ring, const K: usize> Neg for TR<R, K> { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(self.0.iter().map(|&e_i| -e_i).collect()) } }