mirror of
https://github.com/arnaucube/fhe-study.git
synced 2026-01-24 04:33:52 +01:00
fit T64 into the 'Ring' trait, this is to use it in tfhe instead of using Tn<1> which is more tedious
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use rand::{distributions::Distribution, Rng};
|
use rand::{distributions::Distribution, Rng};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::iter::Sum;
|
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
|
/// 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
|
/// ring_torus.rs#Tn. Is not a 'pure algebraic ring', but more a custom trait
|
||||||
@@ -17,6 +17,7 @@ pub trait Ring:
|
|||||||
+ Mul<Output = Self> // internal product
|
+ Mul<Output = Self> // internal product
|
||||||
+ Mul<u64, Output = Self> // scalar mul, external product
|
+ Mul<u64, Output = Self> // scalar mul, external product
|
||||||
+ Mul<Self::C, Output = Self>
|
+ Mul<Self::C, Output = Self>
|
||||||
|
+ Neg<Output = Self>
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Clone
|
+ Clone
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
use rand::{distributions::Distribution, Rng};
|
use rand::{distributions::Distribution, Rng};
|
||||||
use std::array;
|
use std::array;
|
||||||
use std::iter::Sum;
|
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};
|
use crate::{ring::Ring, torus::T64, Rq, Zq};
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ impl<const N: usize> Ring for Tn<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rand(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self {
|
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 {
|
fn from_vec(coeffs: Vec<Self::C>) -> Self {
|
||||||
@@ -152,6 +152,14 @@ impl<const N: usize> SubAssign for Tn<N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Neg for Tn<N> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Tn(array::from_fn(|i| -self.0[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<const N: usize> PartialEq for Tn<N> {
|
impl<const N: usize> PartialEq for Tn<N> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
|
|||||||
@@ -4,38 +4,66 @@ use std::{
|
|||||||
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::ring::Ring;
|
||||||
|
|
||||||
/// Let 𝕋 = ℝ/ℤ, where 𝕋 is a ℤ-module, with homogeneous external product.
|
/// Let 𝕋 = ℝ/ℤ, where 𝕋 is a ℤ-module, with homogeneous external product.
|
||||||
/// Let 𝕋q
|
/// Let 𝕋q
|
||||||
/// T64 is 𝕋q with q=2^Ω, with Ω=64. We identify 𝕋q=(1/q)ℤ/ℤ ≈ ℤq.
|
/// T64 is 𝕋q with q=2^Ω, with Ω=64. We identify 𝕋q=(1/q)ℤ/ℤ ≈ ℤq.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct T64(pub u64);
|
pub struct T64(pub u64);
|
||||||
|
|
||||||
impl T64 {
|
// implement the `Ring` trait for T64, so that it can be used where we would use
|
||||||
pub fn zero() -> Self {
|
// `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)
|
Self(0u64)
|
||||||
}
|
}
|
||||||
pub fn rand(mut rng: impl Rng, dist: impl Distribution<u64>) -> Self {
|
fn rand(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self {
|
||||||
let r: u64 = dist.sample(&mut rng);
|
|
||||||
Self(r)
|
|
||||||
}
|
|
||||||
pub fn rand_f64(mut rng: impl Rng, dist: impl Distribution<f64>) -> Self {
|
|
||||||
let r: f64 = dist.sample(&mut rng);
|
let r: f64 = dist.sample(&mut rng);
|
||||||
Self(r.round() as u64)
|
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.
|
/// 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!(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()
|
.rev()
|
||||||
.map(|i| T64(((self.0 >> i) & 1) as u64))
|
.map(|i| T64(((self.0 >> i) & 1) as u64))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
pub fn mod_switch<const Q2: u64>(&self) -> T64 {
|
fn remodule<const P: u64>(&self) -> T64 {
|
||||||
todo!()
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<T64> for T64 {
|
impl Add<T64> for T64 {
|
||||||
@@ -99,6 +127,9 @@ impl Mul<u64> for T64 {
|
|||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn mul(self, s: u64) -> Self {
|
fn mul(self, s: u64) -> Self {
|
||||||
|
if self.0 == 0 {
|
||||||
|
return Self(0);
|
||||||
|
}
|
||||||
Self(self.0.wrapping_mul(s))
|
Self(self.0.wrapping_mul(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rand_distr::{Normal, Uniform};
|
|||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::{
|
use std::{
|
||||||
array,
|
array,
|
||||||
ops::{Add, Mul, Sub},
|
ops::{Add, Mul, Neg, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ring;
|
use crate::Ring;
|
||||||
@@ -37,6 +37,12 @@ impl<R: Ring, const K: usize> TR<R, K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R: Ring, const K: usize> TR<R, K> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<R> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Ring, const K: usize> Add<TR<R, K>> for TR<R, K> {
|
impl<R: Ring, const K: usize> Add<TR<R, K>> for TR<R, K> {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, other: Self) -> Self {
|
fn add(self, other: Self) -> Self {
|
||||||
@@ -55,6 +61,14 @@ impl<R: Ring, const K: usize> Sub<TR<R, K>> for TR<R, K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// for (TR,TR), the Mul operation is defined as the dot product:
|
/// for (TR,TR), the Mul operation is defined as the dot product:
|
||||||
/// for A, B \in R^k, result = Σ A_i * B_i \in R
|
/// for A, B \in R^k, result = Σ A_i * B_i \in R
|
||||||
impl<R: Ring, const K: usize> Mul<TR<R, K>> for TR<R, K> {
|
impl<R: Ring, const K: usize> Mul<TR<R, K>> for TR<R, K> {
|
||||||
|
|||||||
Reference in New Issue
Block a user