This commit is contained in:
Janmajaya Mall
2024-05-18 17:39:08 +05:30
parent 66464941cc
commit 0d1bea64a7
7 changed files with 1316 additions and 1580 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -146,26 +146,25 @@ impl<El> BoolParameters<El> {
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
struct DecompostionLogBase(pub(crate) usize); pub(crate) struct DecompostionLogBase(pub(crate) usize);
impl AsRef<usize> for DecompostionLogBase { impl AsRef<usize> for DecompostionLogBase {
fn as_ref(&self) -> &usize { fn as_ref(&self) -> &usize {
&self.0 &self.0
} }
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
struct DecompositionCount(pub(crate) usize); pub(crate) struct DecompositionCount(pub(crate) usize);
impl AsRef<usize> for DecompositionCount { impl AsRef<usize> for DecompositionCount {
fn as_ref(&self) -> &usize { fn as_ref(&self) -> &usize {
&self.0 &self.0
} }
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
struct LweDimension(pub(crate) usize); pub(crate) struct LweDimension(pub(crate) usize);
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
struct PolynomialSize(pub(crate) usize); pub(crate) struct PolynomialSize(pub(crate) usize);
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
struct Modulus<T>(pub(crate) T); pub(crate) struct Modulus<T>(pub(crate) T);
pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: Modulus(268369921u64), rlwe_q: Modulus(268369921u64),

View File

@@ -13,6 +13,30 @@ fn gadget_vector<T: PrimInt>(logq: usize, logb: usize, d: usize) -> Vec<T> {
.collect_vec() .collect_vec()
} }
pub trait RlweDecomposer {
type Element;
type D: Decomposer<Element = Self::Element>;
/// Decomposer for RLWE Part A
fn a(&self) -> &Self::D;
/// Decomposer for RLWE Part B
fn b(&self) -> &Self::D;
}
impl<D> RlweDecomposer for (D, D)
where
D: Decomposer,
{
type D = D;
type Element = D::Element;
fn a(&self) -> &Self::D {
&self.0
}
fn b(&self) -> &Self::D {
&self.1
}
}
pub trait Decomposer { pub trait Decomposer {
type Element; type Element;
fn new(q: Self::Element, logb: usize, d: usize) -> Self; fn new(q: Self::Element, logb: usize, d: usize) -> Self;
@@ -142,6 +166,44 @@ impl<T: PrimInt + WrappingSub + Debug + NumInfo> Decomposer for DefaultDecompose
} }
} }
// impl<T> Decomposer for dyn AsRef<DefaultDecomposer<T>>
// where
// DefaultDecomposer<T>: Decomposer<Element = T>,
// {
// type Element = T;
// fn new(q: Self::Element, logb: usize, d: usize) -> Self {
// DefaultDecomposer::<T>::new(q, logb, d)
// }
// fn decompose(&self, v: &Self::Element) -> Vec<Self::Element> {
// todo!()
// }
// fn decomposition_count(&self) -> usize {
// todo!()
// }
// }
// impl<U: AsRef<DefaultDecomposer<T>>> Decomposer for U
// where
// DefaultDecomposer<T>: Decomposer,
// {
// type Element = T;
// fn new(q: Self::Element, logb: usize, d: usize) -> Self {
// todo!()
// }
// fn decompose(&self, v: &Self::Element) -> Vec<Self::Element> {
// todo!()
// }
// fn decomposition_count(&self) -> usize {
// todo!()
// }
// }
fn round_value<T: PrimInt>(value: T, ignore_bits: usize) -> T { fn round_value<T: PrimInt>(value: T, ignore_bits: usize) -> T {
if ignore_bits == 0 { if ignore_bits == 0 {
return value; return value;

View File

@@ -42,6 +42,9 @@ pub trait Matrix: AsRef<[Self::R]> {
fn split_at_row(&self, idx: usize) -> (&[<Self as Matrix>::R], &[<Self as Matrix>::R]) { fn split_at_row(&self, idx: usize) -> (&[<Self as Matrix>::R], &[<Self as Matrix>::R]) {
self.as_ref().split_at(idx) self.as_ref().split_at(idx)
} }
/// Does the matrix fit sub-matrix of dimension row x col
fn fits(&self, row: usize, col: usize) -> bool;
} }
pub trait MatrixMut: Matrix + AsMut<[<Self as Matrix>::R]> pub trait MatrixMut: Matrix + AsMut<[<Self as Matrix>::R]>
@@ -96,6 +99,10 @@ impl<T> Matrix for Vec<Vec<T>> {
fn dimension(&self) -> (usize, usize) { fn dimension(&self) -> (usize, usize) {
(self.len(), self[0].len()) (self.len(), self[0].len())
} }
fn fits(&self, row: usize, col: usize) -> bool {
self.len() >= row && self[0].len() >= col
}
} }
impl<T> Matrix for &[Vec<T>] { impl<T> Matrix for &[Vec<T>] {
@@ -105,6 +112,10 @@ impl<T> Matrix for &[Vec<T>] {
fn dimension(&self) -> (usize, usize) { fn dimension(&self) -> (usize, usize) {
(self.len(), self[0].len()) (self.len(), self[0].len())
} }
fn fits(&self, row: usize, col: usize) -> bool {
self.len() >= row && self[0].len() >= col
}
} }
impl<T> Matrix for &mut [Vec<T>] { impl<T> Matrix for &mut [Vec<T>] {
@@ -114,6 +125,10 @@ impl<T> Matrix for &mut [Vec<T>] {
fn dimension(&self) -> (usize, usize) { fn dimension(&self) -> (usize, usize) {
(self.len(), self[0].len()) (self.len(), self[0].len())
} }
fn fits(&self, row: usize, col: usize) -> bool {
self.len() >= row && self[0].len() >= col
}
} }
impl<T> MatrixMut for Vec<Vec<T>> {} impl<T> MatrixMut for Vec<Vec<T>> {}

View File

@@ -111,7 +111,9 @@ pub(crate) fn lwe_key_switch<
operator: &Op, operator: &Op,
decomposer: &D, decomposer: &D,
) { ) {
assert!(lwe_ksk.dimension().0 == ((lwe_in.as_ref().len() - 1) * decomposer.decomposition_count())); assert!(
lwe_ksk.dimension().0 == ((lwe_in.as_ref().len() - 1) * decomposer.decomposition_count())
);
assert!(lwe_out.as_ref().len() == lwe_ksk.dimension().1); assert!(lwe_out.as_ref().len() == lwe_ksk.dimension().1);
let lwe_in_a_decomposed = lwe_in let lwe_in_a_decomposed = lwe_in

View File

@@ -17,229 +17,244 @@ mod tests {
Matrix, Row, Secret, Matrix, Row, Secret,
}; };
// Test B part with limbd -1 when variance of m is 1 // // Test B part with limbd -1 when variance of m is 1
#[test] // #[test]
fn trial() { // fn trial() {
let logq = 28; // let logq = 28;
let ring_size = 1 << 10; // let ring_size = 1 << 10;
let q = generate_prime(logq, (ring_size as u64) << 1, 1 << logq).unwrap(); // let q = generate_prime(logq, (ring_size as u64) << 1, 1 <<
let logb = 7; // logq).unwrap(); let logb = 7;
let d0 = 3; // let d0 = 3;
let d1 = d0 - 1; // let d1 = d0 - 1;
let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize); // let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as
// usize);
let mut rng = DefaultSecureRng::new(); // let mut rng = DefaultSecureRng::new();
let decomposer = DefaultDecomposer::new(q, logb, d0); // let decomposer = DefaultDecomposer::new(q, logb, d0);
let gadget_vector = decomposer.gadget_vector(); // let gadget_vector = decomposer.gadget_vector();
for i in 0..100 { // for i in 0..100 {
// m should have norm 1 // // m should have norm 1
let mut m0 = vec![0u64; ring_size as usize]; // let mut m0 = vec![0u64; ring_size as usize];
m0[thread_rng().gen_range(0..ring_size)] = 1; // m0[thread_rng().gen_range(0..ring_size)] = 1;
let modq_op = ModularOpsU64::new(q); // let modq_op = ModularOpsU64::new(q);
let nttq_op = NttBackendU64::new(q, ring_size); // let nttq_op = NttBackendU64::new(q, ring_size);
// Encrypt RGSW(m0) // // Encrypt RGSW(m0)
let mut rgsw_seed = [0u8; 32]; // let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed); // rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw = // let mut seeded_rgsw =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q); // SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size,
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed); // d0, rgsw_seed, q); let mut p_rng =
secret_key_encrypt_rgsw( // DefaultSecureRng::new_seeded(rgsw_seed);
&mut seeded_rgsw.data, // secret_key_encrypt_rgsw(
&m0, // &mut seeded_rgsw.data,
&gadget_vector, // &m0,
sk.values(), // &gadget_vector,
&modq_op, // &gadget_vector,
&nttq_op, // sk.values(),
&mut p_rng, // &modq_op,
&mut rng, // &nttq_op,
); // &mut p_rng,
// &mut rng,
// );
// Encrypt RLWE(m1) // // Encrypt RLWE(m1)
let mut m1 = vec![0u64; ring_size]; // let mut m1 = vec![0u64; ring_size];
RandomUniformDist::random_fill(&mut rng, &q, m1.as_mut_slice()); // RandomUniformDist::random_fill(&mut rng, &q, m1.as_mut_slice());
let mut rlwe_seed = [0u8; 32]; // let mut rlwe_seed = [0u8; 32];
rng.fill_bytes(&mut rlwe_seed); // rng.fill_bytes(&mut rlwe_seed);
let mut seeded_rlwe: SeededRlweCiphertext<Vec<u64>, [u8; 32]> = // let mut seeded_rlwe: SeededRlweCiphertext<Vec<u64>, [u8; 32]> =
SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size, rlwe_seed, q); // SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size,
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed); // rlwe_seed, q); let mut p_rng =
secret_key_encrypt_rlwe( // DefaultSecureRng::new_seeded(rlwe_seed);
&m1, // secret_key_encrypt_rlwe(
&mut seeded_rlwe.data, // &m1,
sk.values(), // &mut seeded_rlwe.data,
&modq_op, // sk.values(),
&nttq_op, // &modq_op,
&mut p_rng, // &nttq_op,
&mut rng, // &mut p_rng,
); // &mut rng,
// );
let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe); // let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>,
let rgsw = RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from( // DefaultSecureRng>::from(&seeded_rlwe); let rgsw =
&seeded_rgsw, // RgswCiphertextEvaluationDomain::<_, DefaultSecureRng,
); // NttBackendU64>::from( &seeded_rgsw,
// );
// RLWE(m0m1) = RLWE(m1) x RGSW(m0) // // RLWE(m0m1) = RLWE(m1) x RGSW(m0)
let mut scratch = vec![vec![0u64; ring_size]; d0 + 2]; // let mut scratch = vec![vec![0u64; ring_size]; d0 + 2];
less1_rlwe_by_rgsw( // less1_rlwe_by_rgsw(
&mut rlwe, // &mut rlwe,
&rgsw.data, // &rgsw.data,
&mut scratch, // &mut scratch,
&decomposer, // &decomposer,
&nttq_op, // &nttq_op,
&modq_op, // &modq_op,
0, // 0,
1, // 1,
); // );
// rlwe_by_rgsw( // // rlwe_by_rgsw(
// &mut rlwe, // // &mut rlwe,
// &rgsw.data, // // &rgsw.data,
// &mut scratch, // // &mut scratch,
// &decomposer, // // &decomposer,
// &nttq_op, // // &nttq_op,
// &modq_op, // // &modq_op,
// ); // // );
// measure noise // // measure noise
let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) % q as u128) as u64; // let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) %
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, q); // q as u128) as u64; let m0m1 = negacyclic_mul(&m0, &m1,
let noise = measure_noise(&rlwe, &m0m1, &nttq_op, &modq_op, sk.values()); // mul_mod, q); let noise = measure_noise(&rlwe, &m0m1,
println!("Noise: {noise}"); // &nttq_op, &modq_op, sk.values()); println!("Noise: {noise}");
} // }
} // }
// Test B part with limbd -1 when variance of m is 1 // // Test B part with limbd -1 when variance of m is 1
#[test] // #[test]
fn rgsw_saver() { // fn rgsw_saver() {
let logq = 60; // let logq = 60;
let ring_size = 1 << 11; // let ring_size = 1 << 11;
let q = generate_prime(logq, (ring_size as u64) << 1, 1 << logq).unwrap(); // let q = generate_prime(logq, (ring_size as u64) << 1, 1 <<
let logb = 12; // logq).unwrap(); let logb = 12;
let d0 = 4; // let d0 = 4;
let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize); // let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as
// usize);
let mut rng = DefaultSecureRng::new(); // let mut rng = DefaultSecureRng::new();
let decomposer = DefaultDecomposer::new(q, logb, d0); // let decomposer = DefaultDecomposer::new(q, logb, d0);
let gadget_vector = decomposer.gadget_vector(); // let gadget_vector = decomposer.gadget_vector();
for i in 0..100 { // for i in 0..100 {
let modq_op = ModularOpsU64::new(q); // let modq_op = ModularOpsU64::new(q);
let nttq_op = NttBackendU64::new(q, ring_size); // let nttq_op = NttBackendU64::new(q, ring_size);
// Encrypt RGSW(m0) // // Encrypt RGSW(m0)
let mut m0 = vec![0u64; ring_size as usize]; // let mut m0 = vec![0u64; ring_size as usize];
m0[thread_rng().gen_range(0..ring_size)] = 1; // m0[thread_rng().gen_range(0..ring_size)] = 1;
let mut rgsw_seed = [0u8; 32]; // let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed); // rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw0 = // let mut seeded_rgsw0 =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q); // SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size,
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed); // d0, rgsw_seed, q); let mut p_rng =
secret_key_encrypt_rgsw( // DefaultSecureRng::new_seeded(rgsw_seed);
&mut seeded_rgsw0.data, // secret_key_encrypt_rgsw(
&m0, // &mut seeded_rgsw0.data,
&gadget_vector, // &m0,
sk.values(), // &gadget_vector,
&modq_op, // &gadget_vector,
&nttq_op, // sk.values(),
&mut p_rng, // &modq_op,
&mut rng, // &nttq_op,
); // &mut p_rng,
// &mut rng,
// );
// Encrypt RGSW(m1) // // Encrypt RGSW(m1)
let mut m1 = vec![0u64; ring_size as usize]; // let mut m1 = vec![0u64; ring_size as usize];
m1[thread_rng().gen_range(0..ring_size)] = 1; // m1[thread_rng().gen_range(0..ring_size)] = 1;
let mut rgsw_seed = [0u8; 32]; // let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed); // rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw1 = // let mut seeded_rgsw1 =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q); // SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size,
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed); // d0, rgsw_seed, q); let mut p_rng =
secret_key_encrypt_rgsw( // DefaultSecureRng::new_seeded(rgsw_seed);
&mut seeded_rgsw1.data, // secret_key_encrypt_rgsw(
&m1, // &mut seeded_rgsw1.data,
&gadget_vector, // &m1,
sk.values(), // &gadget_vector,
&modq_op, // &gadget_vector,
&nttq_op, // sk.values(),
&mut p_rng, // &modq_op,
&mut rng, // &nttq_op,
); // &mut p_rng,
// &mut rng,
// );
// TODO(Jay): Why cant you create RgswCIphertext from SeededRgswCiphertext? // // TODO(Jay): Why cant you create RgswCIphertext from
let mut rgsw0 = { // SeededRgswCiphertext? let mut rgsw0 = {
let mut evl_tmp = // let mut evl_tmp =
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from( // RgswCiphertextEvaluationDomain::<_, DefaultSecureRng,
&seeded_rgsw0, // NttBackendU64>::from( &seeded_rgsw0,
); // );
evl_tmp // evl_tmp
.data // .data
.iter_mut() // .iter_mut()
.for_each(|ri| nttq_op.backward(ri.as_mut())); // .for_each(|ri| nttq_op.backward(ri.as_mut()));
evl_tmp.data // evl_tmp.data
}; // };
let rgsw1 = RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from( // let rgsw1 = RgswCiphertextEvaluationDomain::<_, DefaultSecureRng,
&seeded_rgsw1, // NttBackendU64>::from( &seeded_rgsw1,
); // );
let mut scratch_matrix_d_plus_rgsw_by_ring = vec![vec![0u64; ring_size]; d0 + (d0 * 4)]; // let mut scratch_matrix_d_plus_rgsw_by_ring = vec![vec![0u64;
// ring_size]; d0 + (d0 * 4)];
// RGSW(m0m1) = RGSW(m0)xRGSW(m1) // // RGSW(m0m1) = RGSW(m0)xRGSW(m1)
rgsw_by_rgsw_inplace( // rgsw_by_rgsw_inplace(
&mut rgsw0, // &mut rgsw0,
&rgsw1.data, // &rgsw1.data,
&decomposer, // &decomposer,
&mut scratch_matrix_d_plus_rgsw_by_ring, // &decomposer,
&nttq_op, // &mut scratch_matrix_d_plus_rgsw_by_ring,
&modq_op, // &nttq_op,
); // &modq_op,
// );
// send RGSW(m0m1) to Evaluation domain // // send RGSW(m0m1) to Evaluation domain
let mut rgsw01 = rgsw0; // let mut rgsw01 = rgsw0;
rgsw01 // rgsw01
.iter_mut() // .iter_mut()
.for_each(|v| nttq_op.forward(v.as_mut_slice())); // .for_each(|v| nttq_op.forward(v.as_mut_slice()));
// RLWE(m2) // // RLWE(m2)
let mut m2 = vec![0u64; ring_size as usize]; // let mut m2 = vec![0u64; ring_size as usize];
RandomUniformDist::random_fill(&mut rng, &q, m2.as_mut_slice()); // RandomUniformDist::random_fill(&mut rng, &q, m2.as_mut_slice());
let mut rlwe_seed = [0u8; 32]; // let mut rlwe_seed = [0u8; 32];
rng.fill_bytes(&mut rlwe_seed); // rng.fill_bytes(&mut rlwe_seed);
let mut seeded_rlwe = // let mut seeded_rlwe =
SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size, rlwe_seed, q); // SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size,
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed); // rlwe_seed, q); let mut p_rng =
secret_key_encrypt_rlwe( // DefaultSecureRng::new_seeded(rlwe_seed);
&m2, // secret_key_encrypt_rlwe(
&mut seeded_rlwe.data, // &m2,
sk.values(), // &mut seeded_rlwe.data,
&modq_op, // sk.values(),
&nttq_op, // &modq_op,
&mut p_rng, // &nttq_op,
&mut rng, // &mut p_rng,
); // &mut rng,
// );
let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe); // let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>,
// DefaultSecureRng>::from(&seeded_rlwe);
// RLWE(m0m1m2) = RLWE(m2) x RGSW(m0m1) // // RLWE(m0m1m2) = RLWE(m2) x RGSW(m0m1)
let mut scratch_matrix_dplus2_ring = vec![vec![0u64; ring_size]; d0 + 2]; // let mut scratch_matrix_dplus2_ring = vec![vec![0u64; ring_size];
less1_rlwe_by_rgsw( // d0 + 2]; less1_rlwe_by_rgsw(
&mut rlwe, // &mut rlwe,
&rgsw01, // &rgsw01,
&mut scratch_matrix_dplus2_ring, // &mut scratch_matrix_dplus2_ring,
&decomposer, // &decomposer,
&nttq_op, // &nttq_op,
&modq_op, // &modq_op,
1, // 1,
2, // 2,
); // );
let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) % q as u128) as u64; // let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) %
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, q); // q as u128) as u64; let m0m1 = negacyclic_mul(&m0, &m1,
let m0m1m2 = negacyclic_mul(&m2, &m0m1, mul_mod, q); // mul_mod, q); let m0m1m2 = negacyclic_mul(&m2, &m0m1, mul_mod,
let noise = measure_noise(&rlwe.data, &m0m1m2, &nttq_op, &modq_op, sk.values()); // q); let noise = measure_noise(&rlwe.data, &m0m1m2, &nttq_op,
// &modq_op, sk.values());
println!("Noise: {noise}"); // println!("Noise: {noise}");
} // }
} // }
} }

File diff suppressed because it is too large Load Diff