Browse Source

add ciphertext-by-const (plaintext) addition & mult

gfhe-over-ring-trait
arnaucube 1 month ago
parent
commit
f3a368ab6a
2 changed files with 107 additions and 4 deletions
  1. +5
    -0
      arithmetic/src/ring.rs
  2. +102
    -4
      bfv/src/lib.rs

+ 5
- 0
arithmetic/src/ring.rs

@ -85,6 +85,11 @@ impl PR {
evals: None,
})
}
// Warning: this method assumes Q < P
pub fn remodule<const P: u64>(&self) -> PR<P, N> {
assert!(Q < P);
PR::<P, N>::from_vec_u64(self.coeffs().iter().map(|m_i| m_i.0).collect())
}
// TODO review if needed, or if with this interface
pub fn mul_by_matrix(&self, m: &Vec<Vec<Zq<Q>>>) -> Result<Vec<Zq<Q>>> {

+ 102
- 4
bfv/src/lib.rs

@ -10,7 +10,7 @@ use rand::Rng;
use rand_distr::{Normal, Uniform};
use std::ops;
use arithmetic::PR;
use arithmetic::{Zq, PR};
// error deviation for the Gaussian(Normal) distribution
// sigma=3.2 from: https://eprint.iacr.org/2022/162.pdf page 5
@ -30,9 +30,6 @@ impl RLWE {
fn add(lhs: Self, rhs: Self) -> Self {
RLWE::<Q, N>(lhs.0 + rhs.0, lhs.1 + rhs.1)
}
fn mul(lhs: Self, rhs: Self) -> Self {
todo!()
}
}
impl<const Q: u64, const N: usize> ops::Add<RLWE<Q, N>> for RLWE<Q, N> {
@ -42,6 +39,21 @@ impl ops::Add> for RLWE {
}
}
impl<const Q: u64, const N: usize, const T: u64> ops::Add<&PR<T, N>> for &RLWE<Q, N> {
type Output = RLWE<Q, N>;
fn add(self, rhs: &PR<T, N>) -> Self::Output {
// todo!()
BFV::<Q, N, T>::add_const(self, rhs)
}
}
impl<const Q: u64, const N: usize, const T: u64> ops::Mul<&PR<T, N>> for &RLWE<Q, N> {
type Output = RLWE<Q, N>;
fn mul(self, rhs: &PR<T, N>) -> Self::Output {
// todo!()
BFV::<Q, N, T>::mul_const(&self, rhs)
}
}
pub struct BFV<const Q: u64, const N: usize, const T: u64> {}
impl<const Q: u64, const N: usize, const T: u64> BFV<Q, N, T> {
@ -92,6 +104,17 @@ impl BFV {
.collect();
PR::<T, N>::from_vec_u64(r)
}
fn add_const(c: &RLWE<Q, N>, m: &PR<T, N>) -> RLWE<Q, N> {
// assuming T<Q, move m from Zq<T> to Zq<Q>
let m = m.remodule::<Q>();
RLWE::<Q, N>(c.0 + m * Self::DELTA, c.1)
}
fn mul_const(c: &RLWE<Q, N>, m: &PR<T, N>) -> RLWE<Q, N> {
// assuming T<Q, move m from Zq<T> to Zq<Q>
let m = m.remodule::<Q>();
RLWE::<Q, N>(c.0 * m * Self::DELTA, c.1)
}
}
#[cfg(test)]
@ -149,4 +172,79 @@ mod tests {
Ok(())
}
#[test]
fn test_constant_add_mul() -> Result<()> {
const Q: u64 = 2u64.pow(16) + 1;
const N: usize = 32;
const T: u64 = 4; // plaintext modulus
type S = BFV<Q, N, T>;
let mut rng = rand::thread_rng();
let (sk, pk) = S::new_key(&mut rng)?;
let msg_dist = Uniform::new(0_u64, T);
let m1 = PR::<T, N>::rand_u64(&mut rng, msg_dist)?;
let m2_const = PR::<T, N>::rand_u64(&mut rng, msg_dist)?;
let c1 = S::encrypt(&mut rng, &pk, &m1)?;
let c3_add = &c1 + &m2_const;
let c3_mul = &c1 * &m2_const;
let m3_add_recovered = S::decrypt(&sk, &c3_add);
let m3_mul_recovered = S::decrypt(&sk, &c3_mul);
assert_eq!(m1 + m2_const, m3_add_recovered);
let mut mul_res = naive_poly_mul::<T>(&m1.coeffs().to_vec(), &m2_const.coeffs().to_vec());
arithmetic::ring::modulus::<T, N>(&mut mul_res);
dbg!(&mul_res);
let mul_res_2 =
naive_poly_mul_2::<T, N>(&m1.coeffs().to_vec(), &m2_const.coeffs().to_vec());
assert_eq!(mul_res, mul_res_2);
let mul_res = PR::<T, N>::from_vec(mul_res);
assert_eq!(mul_res.coeffs(), m3_mul_recovered.coeffs());
Ok(())
}
fn naive_poly_mul<const T: u64>(a: &[Zq<T>], b: &[Zq<T>]) -> Vec<Zq<T>> {
let mut result: Vec<Zq<T>> = vec![Zq::zero(); a.len() + b.len() - 1];
for (i, &ai) in a.iter().enumerate() {
for (j, &bj) in b.iter().enumerate() {
result[i + j] = result[i + j] + (ai * bj);
}
}
result
}
fn naive_poly_mul_2<const T: u64, const N: usize>(
poly1: &[Zq<T>],
poly2: &[Zq<T>],
) -> Vec<Zq<T>> {
let degree1 = poly1.len();
let degree2 = poly2.len();
// The degree of the resulting polynomial will be degree1 + degree2 - 1
let mut result = vec![Zq::zero(); degree1 + degree2 - 1];
// Perform the multiplication
for i in 0..degree1 {
for j in 0..degree2 {
result[i + j] = result[i + j] + poly1[i] * poly2[j];
}
}
// Reduce the result modulo x^N + 1
let mut reduced_result = vec![Zq::zero(); N];
for i in 0..result.len() {
let mod_index = i % N; // wrap around using modulo N
reduced_result[mod_index] += result[i];
}
// Return the reduced polynomial
reduced_result
}
}

Loading…
Cancel
Save