Browse Source

add support for word-size modulus

par-agg-key-shares
Janmajaya Mall 11 months ago
parent
commit
8ec7143d80
11 changed files with 953 additions and 1677 deletions
  1. +203
    -36
      src/backend.rs
  2. +274
    -1224
      src/bool/evaluator.rs
  3. +72
    -10
      src/bool/parameters.rs
  4. +1
    -2
      src/lib.rs
  5. +39
    -34
      src/lwe.rs
  6. +9
    -9
      src/multi_party.rs
  7. +15
    -14
      src/noise.rs
  8. +15
    -9
      src/ntt.rs
  9. +63
    -103
      src/random.rs
  10. +152
    -153
      src/rgsw.rs
  11. +110
    -83
      src/utils.rs

+ 203
- 36
src/backend.rs

@ -1,11 +1,14 @@
use std::marker::PhantomData;
use itertools::izip;
use num_traits::{WrappingAdd, WrappingMul, WrappingSub};
use num_traits::{PrimInt, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingSub, Zero};
pub trait Modulus {
type Element;
fn is_native() -> bool;
/// Modulus value if it fits in Element
fn q(&self) -> Option<Self::Element>;
/// Is modulus native?
fn is_native(&self) -> bool;
/// -1 in signed representaiton
fn neg_one(&self) -> Self::Element;
/// Largest unsigned value that fits in the modulus. That is, q - 1.
@ -13,15 +16,70 @@ pub trait Modulus {
/// Smallest unsigned value that fits in the modulus
/// Always assmed to be 0.
fn smallest_unsigned_value(&self) -> Self::Element;
/// Max +value in signed representation
fn signed_max(&self) -> Self::Element;
/// Min -value in signed representation
fn signed_min(&self) -> Self::Element;
/// Convert unsigned value in signed represetation to i64
fn to_i64(&self, v: &Self::Element) -> i64;
/// Convert f64 to signed represented in modulus
fn from_f64(&self, v: f64) -> Self::Element;
/// Convert i64 to signed represented in modulus
fn from_i64(&self, v: i64) -> Self::Element;
}
impl Modulus for u64 {
type Element = u64;
fn is_native(&self) -> bool {
// q of size u64 can never be a naitve modulus
false
}
fn largest_unsigned_value(&self) -> Self::Element {
self - 1
}
fn neg_one(&self) -> Self::Element {
self - 1
}
fn smallest_unsigned_value(&self) -> Self::Element {
0
}
fn to_i64(&self, v: &Self::Element) -> i64 {
assert!(v < self);
if *v > (self >> 1) {
ToPrimitive::to_i64(&(self - v)).unwrap()
} else {
ToPrimitive::to_i64(v).unwrap()
}
}
fn from_f64(&self, v: f64) -> Self::Element {
//FIXME (Jay): Before I check whether v is smaller than 0 with `let is_neg =
// o.is_sign_negative() && o != 0.0; I'm ocnfused why didn't I simply check <
// 0.0?
let v = v.round();
if v < 0.0 {
self - v.to_u64().unwrap()
} else {
v.to_u64().unwrap()
}
}
fn from_i64(&self, v: i64) -> Self::Element {
if v < 0 {
self - v.to_u64().unwrap()
} else {
v.to_u64().unwrap()
}
}
fn q(&self) -> Option<Self::Element> {
Some(*self)
}
}
pub trait ModInit {
type M;
fn new(modulus: Self::M) -> Self;
}
pub trait GetModulus {
type Element;
fn new(q: Self::Element) -> Self;
type M: Modulus<Element = Self::Element>;
fn modulus(&self) -> &Self::M;
}
pub trait VectorOps {
@ -44,7 +102,7 @@ pub trait VectorOps {
c: &Self::Element,
);
fn modulus(&self) -> Self::Element;
// fn modulus(&self) -> Self::Element;
}
pub trait ArithmeticOps {
@ -55,20 +113,28 @@ pub trait ArithmeticOps {
fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
fn neg(&self, a: &Self::Element) -> Self::Element;
fn modulus(&self) -> Self::Element;
// fn modulus(&self) -> Self::Element;
}
pub struct ModularOpsU64 {
pub struct ModularOpsU64<T> {
q: u64,
logq: usize,
barrett_mu: u128,
barrett_alpha: usize,
modulus: T,
}
impl ModInit for ModularOpsU64 {
type Element = u64;
fn new(q: u64) -> ModularOpsU64 {
let logq = 64 - q.leading_zeros();
impl<T> ModInit for ModularOpsU64<T>
where
T: Modulus<Element = u64>,
{
type M = T;
fn new(modulus: Self::M) -> ModularOpsU64<T> {
assert!(!modulus.is_native());
// largest unsigned value modulus fits is modulus-1
let q = modulus.largest_unsigned_value() + 1;
let logq = 64 - (q + 1u64).leading_zeros();
// barrett calculation
let mu = (1u128 << (logq * 2 + 3)) / (q as u128);
@ -79,11 +145,12 @@ impl ModInit for ModularOpsU64 {
logq: logq as usize,
barrett_alpha: alpha as usize,
barrett_mu: mu,
modulus,
}
}
}
impl ModularOpsU64 {
impl<T> ModularOpsU64<T> {
fn add_mod_fast(&self, a: u64, b: u64) -> u64 {
debug_assert!(a < self.q);
debug_assert!(b < self.q);
@ -136,7 +203,7 @@ impl ModularOpsU64 {
}
}
impl ArithmeticOps for ModularOpsU64 {
impl<T> ArithmeticOps for ModularOpsU64<T> {
type Element = u64;
fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
@ -155,12 +222,12 @@ impl ArithmeticOps for ModularOpsU64 {
self.q - *a
}
fn modulus(&self) -> Self::Element {
self.q
}
// fn modulus(&self) -> Self::Element {
// self.q
// }
}
impl VectorOps for ModularOpsU64 {
impl<T> VectorOps for ModularOpsU64<T> {
type Element = u64;
fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
@ -220,31 +287,131 @@ impl VectorOps for ModularOpsU64 {
});
}
fn modulus(&self) -> Self::Element {
self.q
// fn modulus(&self) -> Self::Element {
// self.q
// }
}
impl<T> GetModulus for ModularOpsU64<T>
where
T: Modulus,
{
type Element = T::Element;
type M = T;
fn modulus(&self) -> &Self::M {
&self.modulus
}
}
pub struct WordSizeModulus<T> {
_phantom: PhantomData<T>,
modulus: T,
}
impl<T> ModInit for WordSizeModulus<T> {
type Element = T;
fn new<M>(q: M) -> Self {
impl<T> ModInit for WordSizeModulus<T>
where
T: Modulus,
{
type M = T;
fn new(modulus: T) -> Self {
assert!(modulus.is_native());
// For now assume ModulusOpsU64 is only used for u64
Self {
_phantom: PhantomData,
}
Self { modulus: modulus }
}
}
impl<T> ArithmeticOps for WordSizeModulus<T>
where
T: Modulus,
T::Element: WrappingAdd + WrappingSub + WrappingMul + Zero,
{
type Element = T::Element;
fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
T::Element::wrapping_add(a, b)
}
fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
T::Element::wrapping_mul(a, b)
}
fn neg(&self, a: &Self::Element) -> Self::Element {
T::Element::wrapping_sub(&T::Element::zero(), a)
}
fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
T::Element::wrapping_sub(a, b)
}
// fn modulus(&self) -> &T {
// &self.modulus
// }
}
// impl<T: WrappingAdd + WrappingSub + WrappingMul> ArithmeticOps for
// WordSizeModulus<T> { fn add(&self, a: &Self::Element, b: &Self::Element)
// -> Self::Element { T::wrapping_add(*a, *b)
// }
impl<T> VectorOps for WordSizeModulus<T>
where
T: Modulus,
T::Element: WrappingAdd + WrappingSub + WrappingMul + Zero,
{
type Element = T::Element;
fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
*ai = T::Element::wrapping_add(ai, bi);
});
}
fn elwise_sub_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
*ai = T::Element::wrapping_sub(ai, bi);
});
}
fn elwise_mul_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
*ai = T::Element::wrapping_mul(ai, bi);
});
}
fn elwise_neg_mut(&self, a: &mut [Self::Element]) {
a.iter_mut()
.for_each(|ai| *ai = T::Element::wrapping_sub(&T::Element::zero(), ai));
}
fn elwise_scalar_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &Self::Element) {
izip!(out.iter_mut(), a.iter()).for_each(|(oi, ai)| {
*oi = T::Element::wrapping_mul(ai, b);
});
}
fn elwise_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &[Self::Element]) {
izip!(out.iter_mut(), a.iter(), b.iter()).for_each(|(oi, ai, bi)| {
*oi = T::Element::wrapping_mul(ai, bi);
});
}
fn elwise_scalar_mul_mut(&self, a: &mut [Self::Element], b: &Self::Element) {
a.iter_mut().for_each(|ai| {
*ai = T::Element::wrapping_mul(ai, b);
});
}
fn elwise_fma_mut(&self, a: &mut [Self::Element], b: &[Self::Element], c: &[Self::Element]) {
izip!(a.iter_mut(), b.iter(), c.iter()).for_each(|(ai, bi, ci)| {
*ai = T::Element::wrapping_add(ai, &T::Element::wrapping_mul(bi, ci));
});
}
// fn modulus(&self) -> Self::Element {
fn elwise_fma_scalar_mut(
&self,
a: &mut [Self::Element],
b: &[Self::Element],
c: &Self::Element,
) {
izip!(a.iter_mut(), b.iter()).for_each(|(ai, bi)| {
*ai = T::Element::wrapping_add(ai, &T::Element::wrapping_mul(bi, c));
});
}
// }
// }
// fn modulus(&self) -> &T {
// &self.modulus
// }
}

+ 274
- 1224
src/bool/evaluator.rs
File diff suppressed because it is too large
View File


+ 72
- 10
src/bool/parameters.rs

@ -1,10 +1,12 @@
use crate::decomposer::Decomposer;
use num_traits::{ConstZero, PrimInt, Zero};
use crate::{backend::Modulus, decomposer::Decomposer};
#[derive(Clone, PartialEq)]
pub(super) struct BoolParameters<El> {
rlwe_q: CiphertextModulus<El>,
lwe_q: CiphertextModulus<El>,
br_q: CiphertextModulus<El>,
br_q: usize,
rlwe_n: PolynomialSize,
lwe_n: LweDimension,
lwe_decomposer_base: DecompostionLogBase,
@ -30,7 +32,7 @@ impl BoolParameters {
&self.lwe_q
}
pub(crate) fn br_q(&self) -> &CiphertextModulus<El> {
pub(crate) fn br_q(&self) -> &usize {
&self.br_q
}
@ -164,12 +166,72 @@ pub(crate) struct LweDimension(pub(crate) usize);
#[derive(Clone, Copy, PartialEq)]
pub(crate) struct PolynomialSize(pub(crate) usize);
#[derive(Clone, Copy, PartialEq)]
pub(crate) struct CiphertextModulus<T>(T);
/// T eqauls modulus when modulus is non-native. Otherwise T equals 0. bool is
/// true when modulus is native, false otherwise.
pub(crate) struct CiphertextModulus<T>(T, bool);
impl<T: ConstZero> CiphertextModulus<T> {
const fn new_native() -> Self {
// T::zero is stored only for convenience. It has no use when modulus
// is native. That is, either u128,u64,u32,u16
Self(T::ZERO, true)
}
const fn new_non_native(q: T) -> Self {
Self(q, false)
}
}
impl<T> Modulus for CiphertextModulus<T>
where
T: PrimInt,
{
type Element = T;
fn is_native(&self) -> bool {
false
}
fn largest_unsigned_value(&self) -> Self::Element {
if self.1 {
T::max_value()
} else {
self.0 - T::one()
}
}
fn neg_one(&self) -> Self::Element {
if self.1 {
T::max_value()
} else {
self.0 - T::one()
}
}
// fn signed_max(&self) -> Self::Element {}
// fn signed_min(&self) -> Self::Element {}
fn smallest_unsigned_value(&self) -> Self::Element {
T::zero()
}
fn to_i64(&self, v: &Self::Element) -> i64 {
todo!()
}
fn from_f64(&self, v: f64) -> Self::Element {
todo!()
}
fn from_i64(&self, v: i64) -> Self::Element {
todo!()
}
fn q(&self) -> Option<Self::Element> {
todo!()
}
}
pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: CiphertextModulus(268369921u64),
lwe_q: CiphertextModulus(1 << 16),
br_q: CiphertextModulus(1 << 10),
rlwe_q: CiphertextModulus::new_non_native(268369921u64),
lwe_q: CiphertextModulus::new_non_native(1 << 16),
br_q: 1 << 10,
rlwe_n: PolynomialSize(1 << 10),
lwe_n: LweDimension(493),
lwe_decomposer_base: DecompostionLogBase(4),
@ -185,9 +247,9 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters = BoolParameters:: {
};
pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: CiphertextModulus(1152921504606830593),
lwe_q: CiphertextModulus(1 << 20),
br_q: CiphertextModulus(1 << 11),
rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
lwe_q: CiphertextModulus::new_non_native(1 << 20),
br_q: 1 << 10,
rlwe_n: PolynomialSize(1 << 11),
lwe_n: LweDimension(500),
lwe_decomposer_base: DecompostionLogBase(4),

+ 1
- 2
src/lib.rs

@ -2,8 +2,7 @@ use itertools::{izip, Itertools};
use num::UnsignedInteger;
use num_traits::{abs, Zero};
use rand::CryptoRng;
use random::{RandomGaussianDist, RandomUniformDist};
use utils::TryConvertFrom;
use utils::TryConvertFrom1;
mod backend;
mod bool;

+ 39
- 34
src/lwe.rs

@ -9,12 +9,13 @@ use itertools::{izip, Itertools};
use num_traits::{abs, PrimInt, ToPrimitive, Zero};
use crate::{
backend::{ArithmeticOps, VectorOps},
backend::{ArithmeticOps, GetModulus, Modulus, VectorOps},
decomposer::Decomposer,
lwe,
num::UnsignedInteger,
random::{DefaultSecureRng, NewWithSeed, RandomGaussianDist, RandomUniformDist, DEFAULT_RNG},
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal},
random::{
DefaultSecureRng, NewWithSeed, RandomFillGaussianInModulus, RandomGaussianElementInModulus,
RandomFillUniformInModulus, DEFAULT_RNG,
},
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1, WithLocal},
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
};
@ -53,7 +54,7 @@ struct LweKeySwitchingKey {
impl<
M: MatrixMut + MatrixEntity,
R: NewWithSeed + RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
R: NewWithSeed + RandomFillUniformInModulus<[M::MatElement], M::MatElement>,
> From<&SeededLweKeySwitchingKey<M::R, R::Seed>> for LweKeySwitchingKey<M, R>
where
M::R: RowMut,
@ -64,7 +65,7 @@ where
let mut p_rng = R::new_with_seed(value.seed.clone());
let mut data = M::zeros(value.data.as_ref().len(), value.to_lwe_n + 1);
izip!(value.data.as_ref().iter(), data.iter_rows_mut()).for_each(|(bi, lwe_i)| {
RandomUniformDist::random_fill(&mut p_rng, &value.modulus, &mut lwe_i.as_mut()[1..]);
RandomFillUniformInModulus::random_fill(&mut p_rng, &value.modulus, &mut lwe_i.as_mut()[1..]);
lwe_i.as_mut()[0] = *bi;
});
LweKeySwitchingKey {
@ -132,9 +133,11 @@ pub(crate) fn lwe_key_switch<
pub fn lwe_ksk_keygen<
Ro: Row + RowMut + RowEntity,
S,
Op: VectorOps<Element = Ro::Element> + ArithmeticOps<Element = Ro::Element>,
R: RandomGaussianDist<Ro::Element, Parameters = Ro::Element>,
PR: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
Op: VectorOps<Element = Ro::Element>
+ ArithmeticOps<Element = Ro::Element>
+ GetModulus<Element = Ro::Element>,
R: RandomGaussianElementInModulus<Ro::Element, Op::M>,
PR: RandomFillUniformInModulus<[Ro::Element], Op::M>,
>(
from_lwe_sk: &[S],
to_lwe_sk: &[S],
@ -144,17 +147,17 @@ pub fn lwe_ksk_keygen<
p_rng: &mut PR,
rng: &mut R,
) where
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro: TryConvertFrom1<[S], Op::M>,
Ro::Element: Zero + Debug,
{
assert!(ksk_out.as_ref().len() == (from_lwe_sk.len() * gadget.len()));
let d = gadget.len();
let modulus = VectorOps::modulus(operator);
let mut neg_sk_in_m = Ro::try_convert_from(from_lwe_sk, &modulus);
let modulus = operator.modulus();
let mut neg_sk_in_m = Ro::try_convert_from(from_lwe_sk, modulus);
operator.elwise_neg_mut(neg_sk_in_m.as_mut());
let sk_out_m = Ro::try_convert_from(to_lwe_sk, &modulus);
let sk_out_m = Ro::try_convert_from(to_lwe_sk, modulus);
let mut scratch = Ro::zeros(to_lwe_sk.len());
@ -162,7 +165,7 @@ pub fn lwe_ksk_keygen<
|(neg_sk_in_si, d_lwes_partb)| {
izip!(gadget.iter(), d_lwes_partb.into_iter()).for_each(|(f, lwe_b)| {
// sample `a`
RandomUniformDist::random_fill(p_rng, &modulus, scratch.as_mut());
RandomFillUniformInModulus::random_fill(p_rng, &modulus, scratch.as_mut());
// a * z
let mut az = Ro::Element::zero();
@ -173,8 +176,7 @@ pub fn lwe_ksk_keygen<
// a*z + (-s_i)*\beta^j + e
let mut b = operator.add(&az, &operator.mul(f, neg_sk_in_si));
let mut e = Ro::Element::zero();
RandomGaussianDist::random_fill(rng, &modulus, &mut e);
let e = RandomGaussianElementInModulus::random(rng, &modulus);
b = operator.add(&b, &e);
*lwe_b = b;
@ -186,10 +188,9 @@ pub fn lwe_ksk_keygen<
/// Encrypts encoded message m as LWE ciphertext
pub fn encrypt_lwe<
Ro: Row + RowMut,
R: RandomGaussianDist<Ro::Element, Parameters = Ro::Element>
+ RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
Op: ArithmeticOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
R: RandomGaussianElementInModulus<Ro::Element, Op::M> + RandomFillUniformInModulus<[Ro::Element], Op::M>,
S,
Op: ArithmeticOps<Element = Ro::Element>,
>(
lwe_out: &mut Ro,
m: &Ro::Element,
@ -197,14 +198,14 @@ pub fn encrypt_lwe<
operator: &Op,
rng: &mut R,
) where
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro: TryConvertFrom1<[S], Op::M>,
Ro::Element: Zero,
{
let s = Ro::try_convert_from(s, &operator.modulus());
let s = Ro::try_convert_from(s, operator.modulus());
assert!(s.as_ref().len() == (lwe_out.as_ref().len() - 1));
// a*s
RandomUniformDist::random_fill(rng, &operator.modulus(), &mut lwe_out.as_mut()[1..]);
RandomFillUniformInModulus::random_fill(rng, operator.modulus(), &mut lwe_out.as_mut()[1..]);
let mut sa = Ro::Element::zero();
izip!(lwe_out.as_mut().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
let tmp = operator.mul(ai, si);
@ -212,22 +213,25 @@ pub fn encrypt_lwe<
});
// b = a*s + e + m
let mut e = Ro::Element::zero();
RandomGaussianDist::random_fill(rng, &operator.modulus(), &mut e);
let e = RandomGaussianElementInModulus::random(rng, operator.modulus());
let b = operator.add(&operator.add(&sa, &e), m);
lwe_out.as_mut()[0] = b;
}
pub fn decrypt_lwe<Ro: Row, Op: ArithmeticOps<Element = Ro::Element>, S>(
pub fn decrypt_lwe<
Ro: Row,
Op: ArithmeticOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
S,
>(
lwe_ct: &Ro,
s: &[S],
operator: &Op,
) -> Ro::Element
where
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro: TryConvertFrom1<[S], Op::M>,
Ro::Element: Zero,
{
let s = Ro::try_convert_from(s, &operator.modulus());
let s = Ro::try_convert_from(s, operator.modulus());
let mut sa = Ro::Element::zero();
izip!(lwe_ct.as_ref().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
@ -244,14 +248,18 @@ where
/// - ct: Input LWE ciphertext
/// - s: corresponding secret
/// - ideal_m: Ideal `encoded` message
pub(crate) fn measure_noise_lwe<Ro: Row, Op: ArithmeticOps<Element = Ro::Element>, S>(
pub(crate) fn measure_noise_lwe<
Ro: Row,
Op: ArithmeticOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
S,
>(
ct: &Ro,
s: &[S],
operator: &Op,
ideal_m: &Ro::Element,
) -> f64
where
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro: TryConvertFrom1<[S], Op::M>,
Ro::Element: Zero + ToPrimitive + PrimInt + Display,
{
assert!(s.len() == ct.as_ref().len() - 1,);
@ -265,10 +273,7 @@ where
let mut diff = operator.sub(&m, ideal_m);
let q = operator.modulus();
if diff > (q >> 1) {
diff = q - diff;
}
return diff.to_f64().unwrap().log2();
return q.to_i64(&diff).to_f64().unwrap().abs().log2();
}
#[cfg(test)]

+ 9
- 9
src/multi_party.rs

@ -1,18 +1,18 @@
use crate::{
backend::VectorOps,
backend::{GetModulus, VectorOps},
ntt::Ntt,
random::{NewWithSeed, RandomGaussianDist, RandomUniformDist},
utils::TryConvertFrom,
random::{NewWithSeed, RandomFillGaussianInModulus, RandomFillUniformInModulus},
utils::TryConvertFrom1,
Matrix, Row, RowEntity, RowMut,
};
pub(crate) fn public_key_share<
R: Row + RowMut + RowEntity,
S,
ModOp: VectorOps<Element = R::Element>,
ModOp: VectorOps<Element = R::Element> + GetModulus<Element = R::Element>,
NttOp: Ntt<Element = R::Element>,
Rng: RandomGaussianDist<[R::Element], Parameters = R::Element>,
PRng: RandomUniformDist<[R::Element], Parameters = R::Element>,
Rng: RandomFillGaussianInModulus<[R::Element], ModOp::M>,
PRng: RandomFillUniformInModulus<[R::Element], ModOp::M>,
>(
share_out: &mut R,
s_i: &[S],
@ -21,7 +21,7 @@ pub(crate) fn public_key_share<
p_rng: &mut PRng,
rng: &mut Rng,
) where
R: TryConvertFrom<[S], Parameters = R::Element>,
R: TryConvertFrom1<[S], ModOp::M>,
{
let ring_size = share_out.as_ref().len();
assert!(s_i.len() == ring_size);
@ -31,7 +31,7 @@ pub(crate) fn public_key_share<
// sample a
let mut a = {
let mut a = R::zeros(ring_size);
RandomUniformDist::random_fill(p_rng, &q, a.as_mut());
RandomFillUniformInModulus::random_fill(p_rng, &q, a.as_mut());
a
};
@ -42,6 +42,6 @@ pub(crate) fn public_key_share<
modop.elwise_mul_mut(s.as_mut(), a.as_ref());
nttop.backward(s.as_mut());
RandomGaussianDist::random_fill(rng, &q, share_out.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, share_out.as_mut());
modop.elwise_add_mut(share_out.as_mut(), s.as_ref()); // s*e + e
}

+ 15
- 14
src/noise.rs

@ -2,20 +2,21 @@
mod tests {
use rand::{thread_rng, Rng};
use crate::{
backend::{ArithmeticOps, ModInit, ModularOpsU64},
decomposer::{Decomposer, DefaultDecomposer},
ntt::{Ntt, NttBackendU64, NttInit},
random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist},
rgsw::{
less1_rlwe_by_rgsw, measure_noise, rgsw_by_rgsw_inplace, rlwe_by_rgsw,
secret_key_encrypt_rgsw, secret_key_encrypt_rlwe, RgswCiphertext,
RgswCiphertextEvaluationDomain, RlweCiphertext, RlweSecret, SeededRgswCiphertext,
SeededRlweCiphertext,
},
utils::{generate_prime, negacyclic_mul},
Matrix, Row, Secret,
};
// use crate::{
// backend::{ArithmeticOps, ModInit, ModularOpsU64},
// decomposer::{Decomposer, DefaultDecomposer},
// ntt::{Ntt, NttBackendU64, NttInit},
// random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist},
// rgsw::{
// less1_rlwe_by_rgsw, measure_noise, rgsw_by_rgsw_inplace,
// rlwe_by_rgsw, secret_key_encrypt_rgsw,
// secret_key_encrypt_rlwe, RgswCiphertext,
// RgswCiphertextEvaluationDomain, RlweCiphertext, RlweSecret,
// SeededRgswCiphertext, SeededRlweCiphertext,
// },
// utils::{generate_prime, negacyclic_mul},
// Matrix, Row, Secret,
// };
// // Test B part with limbd -1 when variance of m is 1
// #[test]

+ 15
- 9
src/ntt.rs

@ -3,15 +3,14 @@ use rand::{thread_rng, Rng, RngCore, SeedableRng};
use rand_chacha::ChaCha8Rng;
use crate::{
backend::{ArithmeticOps, ModInit, ModularOpsU64},
backend::{ArithmeticOps, ModInit, ModularOpsU64, Modulus},
utils::{mod_exponent, mod_inverse, shoup_representation_fq},
};
pub trait NttInit {
type Element;
pub trait NttInit<M> {
/// Ntt istance must be compatible across different instances with same `q`
/// and `n`
fn new(q: Self::Element, n: usize) -> Self;
fn new(q: &M, n: usize) -> Self;
}
pub trait Ntt {
@ -204,9 +203,8 @@ pub struct NttBackendU64 {
psi_inv_powers_bo_shoup: Box<[u64]>,
}
impl NttInit for NttBackendU64 {
type Element = u64;
fn new(q: u64, n: usize) -> Self {
impl NttBackendU64 {
fn _new(q: u64, n: usize) -> Self {
// \psi = 2n^{th} primitive root of unity in F_q
let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
let psi = find_primitive_root(q, (n * 2) as u64, &mut rng)
@ -270,6 +268,14 @@ impl NttInit for NttBackendU64 {
}
}
impl<M: Modulus<Element = u64>> NttInit<M> for NttBackendU64 {
fn new(q: &M, n: usize) -> Self {
// This NTT does not support native modulus
assert!(!q.is_native());
NttBackendU64::_new(q.q().unwrap(), n)
}
}
impl NttBackendU64 {
fn reduce_from_lazy(&self, a: &mut [u64]) {
let q = self.q;
@ -356,7 +362,7 @@ mod tests {
#[test]
fn native_ntt_backend_works() {
// TODO(Jay): Improve tests. Add tests for different primes and ring size.
let ntt_backend = NttBackendU64::new(Q_60_BITS, N);
let ntt_backend = NttBackendU64::_new(Q_60_BITS, N);
for _ in 0..K {
let mut a = random_vec_in_fq(N, Q_60_BITS);
let a_clone = a.clone();
@ -391,7 +397,7 @@ mod tests {
.collect_vec();
for p in primes.into_iter() {
let ntt_backend = NttBackendU64::new(p, N);
let ntt_backend = NttBackendU64::_new(p, N);
let modulus_backend = ModularOpsU64::new(p);
for _ in 0..K {
let a = random_vec_in_fq(N, p);

+ 63
- 103
src/random.rs

@ -17,26 +17,45 @@ pub(crate) trait NewWithSeed {
fn new_with_seed(seed: Self::Seed) -> Self;
}
pub trait RandomGaussianDist<M>
pub trait RandomElement<T> {
/// Sample Random element of type T
fn random(&mut self) -> T;
}
pub trait RandomElementInModulus<T, M> {
/// Sample Random element of type T in range [0, modulus)
fn random(&mut self, modulus: &M) -> T;
}
pub trait RandomGaussianElementInModulus<T, M> {
/// Sample Random gaussian element from \mu = 0.0 and \sigma = 3.19. Sampled
/// element is converted to signed representation in modulus.
fn random(&mut self, modulus: &M) -> T;
}
pub trait RandomFill<M>
where
M: ?Sized,
{
type Parameters: ?Sized;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
/// Fill container with random elements of type of its elements
fn random_fill(&mut self, container: &mut M);
}
pub trait RandomUniformDist<M>
pub trait RandomFillUniformInModulus<M, P>
where
M: ?Sized,
{
type Parameters: ?Sized;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
/// Fill container with random elements in range [0, modulus)
fn random_fill(&mut self, modulus: &P, container: &mut M);
}
pub trait RandomUniformDist1<M, P>
pub trait RandomFillGaussianInModulus<M, P>
where
M: ?Sized,
{
/// Fill container with gaussian elements sampled from normal distribution
/// with \mu = 0.0 and \sigma = 3.19. Elements are converted to signed
/// represented in the modulus.
fn random_fill(&mut self, modulus: &P, container: &mut M);
}
@ -67,25 +86,17 @@ impl NewWithSeed for DefaultSecureRng {
}
}
impl RandomUniformDist<usize> for DefaultSecureRng {
type Parameters = usize;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut usize) {
*container = self.rng.gen_range(0..*parameters);
}
}
impl RandomUniformDist<[u8]> for DefaultSecureRng {
type Parameters = u8;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u8]) {
self.rng.fill_bytes(container);
}
}
impl RandomUniformDist<[u32]> for DefaultSecureRng {
type Parameters = u32;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
impl<T, C> RandomFillUniformInModulus<[T], C> for DefaultSecureRng
where
T: PrimInt + SampleUniform,
C: Modulus<Element = T>,
{
fn random_fill(&mut self, modulus: &C, container: &mut [T]) {
izip!(
(&mut self.rng).sample_iter(Uniform::new(0, parameters)),
(&mut self.rng).sample_iter(Uniform::new_inclusive(
T::zero(),
modulus.largest_unsigned_value()
)),
container.iter_mut()
)
.for_each(|(from, to)| {
@ -94,30 +105,31 @@ impl RandomUniformDist<[u32]> for DefaultSecureRng {
}
}
impl<T, C> RandomUniformDist1<[T], C> for DefaultSecureRng
impl<T, C> RandomFillGaussianInModulus<[T], C> for DefaultSecureRng
where
T: PrimInt + SampleUniform,
C: Modulus<Element = T>,
{
fn random_fill(&mut self, modulus: &C, container: &mut [T]) {
izip!(
(&mut self.rng).sample_iter(Uniform::new_inclusive(
T::zero(),
modulus.largest_unsigned_value()
)),
rand_distr::Normal::new(0.0, 3.19f64)
.unwrap()
.sample_iter(&mut self.rng),
container.iter_mut()
)
.for_each(|(from, to)| {
*to = from;
*to = modulus.from_f64(from);
});
}
}
impl RandomUniformDist<[u64]> for DefaultSecureRng {
type Parameters = u64;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
impl<T> RandomFill<[T]> for DefaultSecureRng
where
T: PrimInt + SampleUniform,
{
fn random_fill(&mut self, container: &mut [T]) {
izip!(
(&mut self.rng).sample_iter(Uniform::new(0, parameters)),
(&mut self.rng).sample_iter(Uniform::new_inclusive(T::zero(), T::max_value())),
container.iter_mut()
)
.for_each(|(from, to)| {
@ -126,83 +138,31 @@ impl RandomUniformDist<[u64]> for DefaultSecureRng {
}
}
impl RandomGaussianDist<u64> for DefaultSecureRng {
type Parameters = u64;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u64) {
let o = rand_distr::Normal::new(0.0, 3.19f64)
.unwrap()
.sample(&mut self.rng)
.round();
// let o = 0.0f64;
let is_neg = o.is_sign_negative() && o != 0.0;
if is_neg {
*container = parameters - (o.abs() as u64);
} else {
*container = o as u64;
}
impl<T> RandomElement<T> for DefaultSecureRng
where
T: PrimInt + SampleUniform,
{
fn random(&mut self) -> T {
Uniform::new_inclusive(T::zero(), T::max_value()).sample(&mut self.rng)
}
}
impl RandomGaussianDist<u32> for DefaultSecureRng {
type Parameters = u32;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u32) {
let o = rand_distr::Normal::new(0.0, 3.19f32)
.unwrap()
.sample(&mut self.rng)
.round();
// let o = 0.0f32;
let is_neg = o.is_sign_negative() && o != 0.0;
if is_neg {
*container = parameters - (o.abs() as u32);
} else {
*container = o as u32;
}
impl<T> RandomElementInModulus<T, T> for DefaultSecureRng
where
T: PrimInt + SampleUniform,
{
fn random(&mut self, modulus: &T) -> T {
Uniform::new_inclusive(T::zero(), modulus).sample(&mut self.rng)
}
}
impl RandomGaussianDist<[u64]> for DefaultSecureRng {
type Parameters = u64;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
izip!(
impl<T, M: Modulus<Element = T>> RandomGaussianElementInModulus<T, M> for DefaultSecureRng {
fn random(&mut self, modulus: &M) -> T {
modulus.from_f64(
rand_distr::Normal::new(0.0, 3.19f64)
.unwrap()
.sample_iter(&mut self.rng),
container.iter_mut()
)
.for_each(|(oi, v)| {
let oi = oi.round();
let is_neg = oi.is_sign_negative() && oi != 0.0;
if is_neg {
*v = parameters - (oi.abs() as u64);
} else {
*v = oi as u64;
}
});
}
}
impl RandomGaussianDist<[u32]> for DefaultSecureRng {
type Parameters = u32;
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
izip!(
rand_distr::Normal::new(0.0, 3.19f32)
.unwrap()
.sample_iter(&mut self.rng),
container.iter_mut()
.sample(&mut self.rng),
)
.for_each(|(oi, v)| {
let oi = oi.round();
let is_neg = oi.is_sign_negative() && oi != 0.0;
if is_neg {
*v = parameters - (oi.abs() as u32);
} else {
*v = oi as u32;
}
});
}
}

+ 152
- 153
src/rgsw.rs

@ -9,34 +9,32 @@ use itertools::{izip, Itertools};
use num_traits::{PrimInt, Signed, ToPrimitive, Zero};
use crate::{
backend::{ArithmeticOps, VectorOps},
backend::{ArithmeticOps, GetModulus, Modulus, VectorOps},
decomposer::{self, Decomposer, RlweDecomposer},
ntt::{self, Ntt, NttInit},
random::{DefaultSecureRng, NewWithSeed, RandomGaussianDist, RandomUniformDist},
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal},
random::{
DefaultSecureRng, NewWithSeed, RandomElementInModulus, RandomFill, RandomFillGaussianInModulus,
RandomFillUniformInModulus,
},
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1, WithLocal},
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
};
pub struct SeededAutoKey<M, S>
pub struct SeededAutoKey<M, S, Mod>
where
M: Matrix,
{
data: M,
seed: S,
modulus: M::MatElement,
modulus: Mod,
}
impl<M: Matrix + MatrixEntity, S> SeededAutoKey<M, S> {
fn empty<D: Decomposer>(
ring_size: usize,
auto_decomposer: &D,
seed: S,
modulus: M::MatElement,
) -> Self {
impl<M: Matrix + MatrixEntity, S, Mod: Modulus<Element = M::MatElement>> SeededAutoKey<M, S, Mod> {
fn empty<D: Decomposer>(ring_size: usize, auto_decomposer: &D, seed: S, modulus: Mod) -> Self {
SeededAutoKey {
data: M::zeros(auto_decomposer.decomposition_count(), ring_size),
seed,
modulus: modulus,
modulus,
}
}
}
@ -48,22 +46,23 @@ pub struct AutoKeyEvaluationDomain {
impl<
M: MatrixMut + MatrixEntity,
R: RandomUniformDist<[M::MatElement], Parameters = M::MatElement> + NewWithSeed,
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement>,
> From<&SeededAutoKey<M, R::Seed>> for AutoKeyEvaluationDomain<M, R, N>
Mod: Modulus<Element = M::MatElement> + Clone,
R: RandomFillUniformInModulus<[M::MatElement], Mod> + NewWithSeed,
N: NttInit<Mod> + Ntt<Element = M::MatElement>,
> From<&SeededAutoKey<M, R::Seed, Mod>> for AutoKeyEvaluationDomain<M, R, N>
where
<M as Matrix>::R: RowMut,
M::MatElement: Copy,
R::Seed: Clone,
{
fn from(value: &SeededAutoKey<M, R::Seed>) -> Self {
fn from(value: &SeededAutoKey<M, R::Seed, Mod>) -> Self {
let (d, ring_size) = value.data.dimension();
let mut data = M::zeros(2 * d, ring_size);
// sample RLWE'_A(-s(X^k))
let mut p_rng = R::new_with_seed(value.seed.clone());
data.iter_rows_mut().take(d).for_each(|r| {
RandomUniformDist::random_fill(&mut p_rng, &value.modulus, r.as_mut());
RandomFillUniformInModulus::random_fill(&mut p_rng, &value.modulus, r.as_mut());
});
// copy over RLWE'_B(-s(X^k))
@ -72,7 +71,7 @@ where
});
// send RLWE'(-s(X^k)) polynomials to evaluation domain
let ntt_op = N::new(value.modulus, ring_size);
let ntt_op = N::new(&value.modulus, ring_size);
data.iter_rows_mut()
.for_each(|r| ntt_op.forward(r.as_mut()));
@ -83,22 +82,22 @@ where
}
}
pub struct RgswCiphertext<M: Matrix> {
pub struct RgswCiphertext<M: Matrix, Mod> {
/// Rgsw ciphertext polynomials
pub(crate) data: M,
modulus: M::MatElement,
modulus: Mod,
/// Decomposition for RLWE part A
d_a: usize,
/// Decomposition for RLWE part B
d_b: usize,
}
impl<M: MatrixEntity> RgswCiphertext<M> {
impl<M: MatrixEntity, Mod: Modulus<Element = M::MatElement>> RgswCiphertext<M, Mod> {
pub(crate) fn empty<D: RlweDecomposer>(
ring_size: usize,
decomposer: &D,
modulus: M::MatElement,
) -> RgswCiphertext<M> {
modulus: Mod,
) -> RgswCiphertext<M, Mod> {
RgswCiphertext {
data: M::zeros(
decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count() * 2,
@ -111,40 +110,40 @@ impl RgswCiphertext {
}
}
pub struct SeededRgswCiphertext<M, S>
pub struct SeededRgswCiphertext<M, S, Mod>
where
M: Matrix,
{
pub(crate) data: M,
seed: S,
modulus: M::MatElement,
modulus: Mod,
/// Decomposition for RLWE part A
d_a: usize,
/// Decomposition for RLWE part B
d_b: usize,
}
impl<M: Matrix + MatrixEntity, S> SeededRgswCiphertext<M, S> {
impl<M: Matrix + MatrixEntity, S, Mod> SeededRgswCiphertext<M, S, Mod> {
pub(crate) fn empty<D: RlweDecomposer>(
ring_size: usize,
decomposer: &D,
seed: S,
modulus: M::MatElement,
) -> SeededRgswCiphertext<M, S> {
modulus: Mod,
) -> SeededRgswCiphertext<M, S, Mod> {
SeededRgswCiphertext {
data: M::zeros(
decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count(),
ring_size,
),
seed,
modulus: modulus,
modulus,
d_a: decomposer.a().decomposition_count(),
d_b: decomposer.b().decomposition_count(),
}
}
}
impl<M: Debug + Matrix, S: Debug> Debug for SeededRgswCiphertext<M, S>
impl<M: Debug + Matrix, S: Debug, Mod: Debug> Debug for SeededRgswCiphertext<M, S, Mod>
where
M::MatElement: Debug,
{
@ -164,16 +163,17 @@ pub struct RgswCiphertextEvaluationDomain {
impl<
M: MatrixMut + MatrixEntity,
R: NewWithSeed + RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement> + Debug,
> From<&SeededRgswCiphertext<M, R::Seed>> for RgswCiphertextEvaluationDomain<M, R, N>
Mod: Modulus<Element = M::MatElement>,
R: NewWithSeed + RandomFillUniformInModulus<[M::MatElement], Mod>,
N: NttInit<Mod> + Ntt<Element = M::MatElement> + Debug,
> From<&SeededRgswCiphertext<M, R::Seed, Mod>> for RgswCiphertextEvaluationDomain<M, R, N>
where
<M as Matrix>::R: RowMut,
M::MatElement: Copy,
R::Seed: Clone,
M: Debug,
{
fn from(value: &SeededRgswCiphertext<M, R::Seed>) -> Self {
fn from(value: &SeededRgswCiphertext<M, R::Seed, Mod>) -> Self {
let mut data = M::zeros(value.d_a * 2 + value.d_b * 2, value.data.dimension().1);
// copy RLWE'(-sm)
@ -203,7 +203,7 @@ where
// Send polynomials to evaluation domain
let ring_size = data.dimension().1;
let nttop = N::new(value.modulus, ring_size);
let nttop = N::new(&value.modulus, ring_size);
data.iter_rows_mut()
.for_each(|ri| nttop.forward(ri.as_mut()));
@ -216,15 +216,16 @@ where
impl<
M: MatrixMut + MatrixEntity,
Mod: Modulus<Element = M::MatElement>,
R,
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement>,
> From<&RgswCiphertext<M>> for RgswCiphertextEvaluationDomain<M, R, N>
N: NttInit<Mod> + Ntt<Element = M::MatElement>,
> From<&RgswCiphertext<M, Mod>> for RgswCiphertextEvaluationDomain<M, R, N>
where
<M as Matrix>::R: RowMut,
M::MatElement: Copy,
M: Debug,
{
fn from(value: &RgswCiphertext<M>) -> Self {
fn from(value: &RgswCiphertext<M, Mod>) -> Self {
let mut data = M::zeros(value.d_a * 2 + value.d_b * 2, value.data.dimension().1);
// copy RLWE'(-sm)
@ -247,7 +248,7 @@ where
// Send polynomials to evaluation domain
let ring_size = data.dimension().1;
let nttop = N::new(value.modulus, ring_size);
let nttop = N::new(&value.modulus, ring_size);
data.iter_rows_mut()
.for_each(|ri| nttop.forward(ri.as_mut()));
@ -286,17 +287,14 @@ impl AsRef<[M::R]> for RgswCiphertextEvaluationDomain
}
}
pub struct SeededRlweCiphertext<R, S>
where
R: Row,
{
pub struct SeededRlweCiphertext<R, S, Mod> {
pub(crate) data: R,
pub(crate) seed: S,
pub(crate) modulus: R::Element,
pub(crate) modulus: Mod,
}
impl<R: RowEntity, S> SeededRlweCiphertext<R, S> {
pub(crate) fn empty(ring_size: usize, seed: S, modulus: R::Element) -> Self {
impl<R: RowEntity, S, Mod> SeededRlweCiphertext<R, S, Mod> {
pub(crate) fn empty(ring_size: usize, seed: S, modulus: Mod) -> Self {
SeededRlweCiphertext {
data: R::zeros(ring_size),
seed,
@ -360,20 +358,23 @@ impl IsTrivial for RlweCiphertext {
}
}
impl<R: Row, M: MatrixEntity<R = R, MatElement = R::Element> + MatrixMut, Rng: NewWithSeed>
From<&SeededRlweCiphertext<R, Rng::Seed>> for RlweCiphertext<M, Rng>
impl<
R: Row,
M: MatrixEntity<R = R, MatElement = R::Element> + MatrixMut,
Rng: NewWithSeed + RandomFillUniformInModulus<[M::MatElement], Mod>,
Mod: Modulus<Element = R::Element>,
> From<&SeededRlweCiphertext<R, Rng::Seed, Mod>> for RlweCiphertext<M, Rng>
where
Rng::Seed: Clone,
Rng: RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
<M as Matrix>::R: RowMut,
R::Element: Copy,
{
fn from(value: &SeededRlweCiphertext<R, Rng::Seed>) -> Self {
fn from(value: &SeededRlweCiphertext<R, Rng::Seed, Mod>) -> Self {
let mut data = M::zeros(2, value.data.as_ref().len());
// sample a
let mut p_rng = Rng::new_with_seed(value.seed.clone());
RandomUniformDist::random_fill(&mut p_rng, &value.modulus, data.get_row_mut(0));
RandomFillUniformInModulus::random_fill(&mut p_rng, &value.modulus, data.get_row_mut(0));
data.get_row_mut(1).copy_from_slice(value.data.as_ref());
@ -413,7 +414,7 @@ pub struct RlwePublicKey {
impl<
M: MatrixMut + MatrixEntity,
Rng: NewWithSeed + RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
Rng: NewWithSeed + RandomFillUniformInModulus<[M::MatElement], M::MatElement>,
> From<&SeededRlwePublicKey<M::R, Rng::Seed>> for RlwePublicKey<M, Rng>
where
<M as Matrix>::R: RowMut,
@ -425,7 +426,7 @@ where
// sample a
let mut p_rng = Rng::new_with_seed(value.seed);
RandomUniformDist::random_fill(&mut p_rng, &value.modulus, data.get_row_mut(0));
RandomFillUniformInModulus::random_fill(&mut p_rng, &value.modulus, data.get_row_mut(0));
// copy over b
data.get_row_mut(1).copy_from_slice(value.data.as_ref());
@ -956,10 +957,10 @@ pub(crate) fn rgsw_by_rgsw_inplace<
pub(crate) fn secret_key_encrypt_rgsw<
Mmut: MatrixMut + MatrixEntity,
S,
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>
+ RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
ModOp: VectorOps<Element = Mmut::MatElement>,
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>
+ RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
>(
out_rgsw: &mut Mmut,
@ -972,8 +973,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
p_rng: &mut PR,
rng: &mut R,
) where
<Mmut as Matrix>::R:
RowMut + RowEntity + TryConvertFrom<[S], Parameters = Mmut::MatElement> + Debug,
<Mmut as Matrix>::R: RowMut + RowEntity + TryConvertFrom1<[S], ModOp::M> + Debug,
Mmut::MatElement: Copy + Debug,
{
let d_a = gadget_a.len();
@ -1000,7 +1000,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
)
.for_each(|(ai, bi, beta_i)| {
// Sample a_i
RandomUniformDist::random_fill(rng, &q, ai.as_mut());
RandomFillUniformInModulus::random_fill(rng, &q, ai.as_mut());
// a_i * s
scratch_space.as_mut().copy_from_slice(ai.as_ref());
@ -1009,7 +1009,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
ntt_op.backward(scratch_space.as_mut());
// b_i = e_i + a_i * s
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
mod_op.elwise_add_mut(bi.as_mut(), scratch_space.as_ref());
// a_i + \beta_i * m
@ -1022,7 +1022,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
// polynomials of part A of RLWE'(m) are sampled from seed
let mut a = Mmut::zeros(d_b, ring_size);
a.iter_rows_mut()
.for_each(|ai| RandomUniformDist::random_fill(p_rng, &q, ai.as_mut()));
.for_each(|ai| RandomFillUniformInModulus::random_fill(p_rng, &q, ai.as_mut()));
a
};
@ -1041,7 +1041,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
mod_op.elwise_scalar_mul(scratch_space.as_mut(), m.as_ref(), beta_i);
// Sample e_i
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
// e_i + beta_i * m + ai*s
mod_op.elwise_add_mut(bi.as_mut(), scratch_space.as_ref());
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
@ -1051,10 +1051,10 @@ pub(crate) fn secret_key_encrypt_rgsw<
pub(crate) fn public_key_encrypt_rgsw<
Mmut: MatrixMut + MatrixEntity,
M: Matrix<MatElement = Mmut::MatElement>,
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>
+ RandomUniformDist<[u8], Parameters = u8>
+ RandomUniformDist<usize, Parameters = usize>,
ModOp: VectorOps<Element = Mmut::MatElement>,
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>
+ RandomFill<[u8]>
+ RandomElementInModulus<usize, usize>,
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
>(
out_rgsw: &mut Mmut,
@ -1066,7 +1066,7 @@ pub(crate) fn public_key_encrypt_rgsw<
ntt_op: &NttOp,
rng: &mut R,
) where
<Mmut as Matrix>::R: RowMut + RowEntity + TryConvertFrom<[i32], Parameters = Mmut::MatElement>,
<Mmut as Matrix>::R: RowMut + RowEntity + TryConvertFrom1<[i32], ModOp::M>,
Mmut::MatElement: Copy,
{
let ring_size = public_key.dimension().1;
@ -1113,8 +1113,8 @@ pub(crate) fn public_key_encrypt_rgsw<
ntt_op.backward(u_eval_copy.as_mut());
// sample error
RandomGaussianDist::random_fill(rng, &q, ai.as_mut());
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, ai.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
// a = p0*u+e0
mod_op.elwise_add_mut(ai.as_mut(), u_eval.as_ref());
@ -1152,8 +1152,8 @@ pub(crate) fn public_key_encrypt_rgsw<
ntt_op.backward(u_eval_copy.as_mut());
// sample error
RandomGaussianDist::random_fill(rng, &q, ai.as_mut());
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, ai.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
// a = p0*u+e0
mod_op.elwise_add_mut(ai.as_mut(), u_eval.as_ref());
@ -1182,10 +1182,12 @@ pub(crate) fn public_key_encrypt_rgsw<
/// - to_s: secret polynomial to key switch to.
pub(crate) fn rlwe_ksk_gen<
Mmut: MatrixMut + MatrixEntity,
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
ModOp: ArithmeticOps<Element = Mmut::MatElement>
+ VectorOps<Element = Mmut::MatElement>
+ GetModulus<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>,
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
>(
ksk_out: &mut Mmut,
neg_from_s: Mmut::R,
@ -1202,7 +1204,7 @@ pub(crate) fn rlwe_ksk_gen<
let d = gadget_vector.len();
assert!(ksk_out.dimension() == (d, ring_size));
let q = ArithmeticOps::modulus(mod_op);
let q = mod_op.modulus();
ntt_op.forward(to_s.as_mut());
@ -1210,7 +1212,7 @@ pub(crate) fn rlwe_ksk_gen<
let mut part_a = {
let mut a = Mmut::zeros(d, ring_size);
a.iter_rows_mut()
.for_each(|ai| RandomUniformDist::random_fill(p_rng, &q, ai.as_mut()));
.for_each(|ai| RandomFillUniformInModulus::random_fill(p_rng, q, ai.as_mut()));
a
};
izip!(
@ -1225,7 +1227,7 @@ pub(crate) fn rlwe_ksk_gen<
ntt_op.backward(ai.as_mut());
// ei + to_s*ai
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
// beta_i * -from_s
@ -1239,11 +1241,13 @@ pub(crate) fn rlwe_ksk_gen<
pub(crate) fn galois_key_gen<
Mmut: MatrixMut + MatrixEntity,
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
ModOp: ArithmeticOps<Element = Mmut::MatElement>
+ VectorOps<Element = Mmut::MatElement>
+ GetModulus<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
S,
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>,
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
>(
ksk_out: &mut Mmut,
s: &[S],
@ -1255,23 +1259,23 @@ pub(crate) fn galois_key_gen<
rng: &mut R,
) where
<Mmut as Matrix>::R: RowMut,
Mmut::R: TryConvertFrom<[S], Parameters = Mmut::MatElement> + RowEntity,
Mmut::R: TryConvertFrom1<[S], ModOp::M> + RowEntity,
Mmut::MatElement: Copy + Sub<Output = Mmut::MatElement>,
{
let ring_size = s.len();
let (auto_map_index, auto_map_sign) = generate_auto_map(ring_size, auto_k);
let q = ArithmeticOps::modulus(mod_op);
let q = mod_op.modulus();
// s(X) -> -s(X^k)
let s = Mmut::R::try_convert_from(s, &q);
let s = Mmut::R::try_convert_from(s, q);
let mut neg_s_auto = Mmut::R::zeros(s.as_ref().len());
izip!(s.as_ref(), auto_map_index.iter(), auto_map_sign.iter()).for_each(
|(el, to_index, sign)| {
// if sign is +ve (true), then negate because we need -s(X) (i.e. do the
// opposite than the usual case)
if *sign {
neg_s_auto.as_mut()[*to_index] = q - *el;
neg_s_auto.as_mut()[*to_index] = mod_op.neg(el);
} else {
neg_s_auto.as_mut()[*to_index] = *el;
}
@ -1298,11 +1302,11 @@ pub(crate) fn galois_key_gen<
/// second rows consting polynomial `b`
pub(crate) fn secret_key_encrypt_rlwe<
Ro: Row + RowMut + RowEntity,
ModOp: VectorOps<Element = Ro::Element>,
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
NttOp: Ntt<Element = Ro::Element>,
S,
R: RandomGaussianDist<[Ro::Element], Parameters = Ro::Element>,
PR: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
R: RandomFillGaussianInModulus<[Ro::Element], ModOp::M>,
PR: RandomFillUniformInModulus<[Ro::Element], ModOp::M>,
>(
m: &[Ro::Element],
b_rlwe_out: &mut Ro,
@ -1312,7 +1316,7 @@ pub(crate) fn secret_key_encrypt_rlwe<
p_rng: &mut PR,
rng: &mut R,
) where
Ro: TryConvertFrom<[S], Parameters = Ro::Element> + Debug,
Ro: TryConvertFrom1<[S], ModOp::M> + Debug,
{
let ring_size = s.len();
assert!(m.as_ref().len() == ring_size);
@ -1323,19 +1327,19 @@ pub(crate) fn secret_key_encrypt_rlwe<
// sample a
let mut a = {
let mut a = Ro::zeros(ring_size);
RandomUniformDist::random_fill(p_rng, &q, a.as_mut());
RandomFillUniformInModulus::random_fill(p_rng, q, a.as_mut());
a
};
// s * a
let mut sa = Ro::try_convert_from(s, &q);
let mut sa = Ro::try_convert_from(s, q);
ntt_op.forward(sa.as_mut());
ntt_op.forward(a.as_mut());
mod_op.elwise_mul_mut(sa.as_mut(), a.as_ref());
ntt_op.backward(sa.as_mut());
// sample e
RandomGaussianDist::random_fill(rng, &q, b_rlwe_out.as_mut());
RandomFillGaussianInModulus::random_fill(rng, q, b_rlwe_out.as_mut());
mod_op.elwise_add_mut(b_rlwe_out.as_mut(), m.as_ref());
mod_op.elwise_add_mut(b_rlwe_out.as_mut(), sa.as_ref());
}
@ -1343,13 +1347,13 @@ pub(crate) fn secret_key_encrypt_rlwe<
pub(crate) fn public_key_encrypt_rlwe<
M: Matrix,
Mmut: MatrixMut<MatElement = M::MatElement>,
ModOp: VectorOps<Element = M::MatElement>,
ModOp: VectorOps<Element = M::MatElement> + GetModulus<Element = M::MatElement>,
NttOp: Ntt<Element = M::MatElement>,
S,
R: RandomGaussianDist<[M::MatElement], Parameters = M::MatElement>
+ RandomUniformDist<[M::MatElement], Parameters = M::MatElement>
+ RandomUniformDist<[u8], Parameters = u8>
+ RandomUniformDist<usize, Parameters = usize>,
R: RandomFillGaussianInModulus<[M::MatElement], ModOp::M>
+ RandomFillUniformInModulus<[M::MatElement], ModOp::M>
+ RandomFill<[u8]>
+ RandomElementInModulus<usize, usize>,
>(
rlwe_out: &mut Mmut,
pk: &M,
@ -1358,7 +1362,7 @@ pub(crate) fn public_key_encrypt_rlwe<
ntt_op: &NttOp,
rng: &mut R,
) where
<Mmut as Matrix>::R: RowMut + TryConvertFrom<[S], Parameters = M::MatElement> + RowEntity,
<Mmut as Matrix>::R: RowMut + TryConvertFrom1<[S], ModOp::M> + RowEntity,
M::MatElement: Copy,
S: Zero + Signed + Copy,
{
@ -1369,7 +1373,7 @@ pub(crate) fn public_key_encrypt_rlwe<
let mut u = vec![S::zero(); ring_size];
fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
let mut u = Mmut::R::try_convert_from(&u, &q);
let mut u = Mmut::R::try_convert_from(&u, q);
ntt_op.forward(u.as_mut());
let mut ua = Mmut::R::zeros(ring_size);
@ -1389,7 +1393,7 @@ pub(crate) fn public_key_encrypt_rlwe<
// sample error
rlwe_out.iter_rows_mut().for_each(|ri| {
RandomGaussianDist::random_fill(rng, &q, ri.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, ri.as_mut());
});
// a*u + e0
@ -1405,10 +1409,10 @@ pub(crate) fn public_key_encrypt_rlwe<
pub(crate) fn gen_rlwe_public_key<
Ro: RowMut + RowEntity,
S,
ModOp: VectorOps<Element = Ro::Element>,
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
NttOp: Ntt<Element = Ro::Element>,
PRng: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
Rng: RandomGaussianDist<[Ro::Element], Parameters = Ro::Element>,
PRng: RandomFillUniformInModulus<[Ro::Element], ModOp::M>,
Rng: RandomFillGaussianInModulus<[Ro::Element], ModOp::M>,
>(
part_b_out: &mut Ro,
s: &[S],
@ -1417,7 +1421,7 @@ pub(crate) fn gen_rlwe_public_key<
p_rng: &mut PRng,
rng: &mut Rng,
) where
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro: TryConvertFrom1<[S], ModOp::M>,
{
let ring_size = s.len();
assert!(part_b_out.as_ref().len() == ring_size);
@ -1427,7 +1431,7 @@ pub(crate) fn gen_rlwe_public_key<
// sample a
let mut a = {
let mut tmp = Ro::zeros(ring_size);
RandomUniformDist::random_fill(p_rng, &q, tmp.as_mut());
RandomFillUniformInModulus::random_fill(p_rng, &q, tmp.as_mut());
tmp
};
ntt_op.forward(a.as_mut());
@ -1439,7 +1443,7 @@ pub(crate) fn gen_rlwe_public_key<
ntt_op.backward(sa.as_mut());
// s*a + e
RandomGaussianDist::random_fill(rng, &q, part_b_out.as_mut());
RandomFillGaussianInModulus::random_fill(rng, &q, part_b_out.as_mut());
mod_op.elwise_add_mut(part_b_out.as_mut(), sa.as_ref());
}
@ -1449,7 +1453,7 @@ pub(crate) fn gen_rlwe_public_key<
pub(crate) fn decrypt_rlwe<
R: RowMut,
M: Matrix<MatElement = R::Element>,
ModOp: VectorOps<Element = R::Element>,
ModOp: VectorOps<Element = R::Element> + GetModulus<Element = R::Element>,
NttOp: Ntt<Element = R::Element>,
S,
>(
@ -1459,7 +1463,7 @@ pub(crate) fn decrypt_rlwe<
ntt_op: &NttOp,
mod_op: &ModOp,
) where
R: TryConvertFrom<[S], Parameters = R::Element>,
R: TryConvertFrom1<[S], ModOp::M>,
R::Element: Copy,
{
let ring_size = s.len();
@ -1471,7 +1475,7 @@ pub(crate) fn decrypt_rlwe<
ntt_op.forward(m_out.as_mut());
// -s*a
let mut s = R::try_convert_from(&s, &mod_op.modulus());
let mut s = R::try_convert_from(&s, mod_op.modulus());
ntt_op.forward(s.as_mut());
mod_op.elwise_mul_mut(m_out.as_mut(), s.as_ref());
mod_op.elwise_neg_mut(m_out.as_mut());
@ -1485,7 +1489,7 @@ pub(crate) fn decrypt_rlwe<
// encoded_m
pub(crate) fn measure_noise<
Mmut: MatrixMut + Matrix,
ModOp: VectorOps<Element = Mmut::MatElement>,
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
S,
>(
@ -1497,7 +1501,7 @@ pub(crate) fn measure_noise<
) -> f64
where
<Mmut as Matrix>::R: RowMut,
Mmut::R: RowEntity + TryConvertFrom<[S], Parameters = Mmut::MatElement>,
Mmut::R: RowEntity + TryConvertFrom1<[S], ModOp::M>,
Mmut::MatElement: PrimInt + ToPrimitive + Debug,
{
let ring_size = s.len();
@ -1505,7 +1509,7 @@ where
assert!(encoded_m_ideal.as_ref().len() == ring_size);
// -(s * a)
let q = VectorOps::modulus(mod_op);
let q = mod_op.modulus();
let mut s = Mmut::R::try_convert_from(s, &q);
ntt_op.forward(s.as_mut());
let mut a = Mmut::R::zeros(ring_size);
@ -1524,13 +1528,7 @@ where
let mut max_diff_bits = f64::MIN;
m_plus_e.as_ref().iter().for_each(|v| {
let mut v = *v;
if v >= (q >> 1) {
// v is -ve
v = q - v;
}
let bits = (v.to_f64().unwrap()).log2();
let bits = (q.to_i64(v).to_f64().unwrap()).log2();
if max_diff_bits < bits {
max_diff_bits = bits;
@ -1548,16 +1546,16 @@ pub(crate) mod tests {
use rand::{thread_rng, Rng};
use crate::{
backend::{ModInit, ModularOpsU64, VectorOps},
backend::{GetModulus, ModInit, ModularOpsU64, Modulus, VectorOps},
decomposer::{Decomposer, DefaultDecomposer, RlweDecomposer},
ntt::{self, Ntt, NttBackendU64, NttInit},
random::{DefaultSecureRng, NewWithSeed, RandomUniformDist},
random::{DefaultSecureRng, NewWithSeed, RandomFillUniformInModulus},
rgsw::{
gen_rlwe_public_key, measure_noise, public_key_encrypt_rgsw, AutoKeyEvaluationDomain,
RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, RlwePublicKey,
SeededAutoKey, SeededRgswCiphertext, SeededRlweCiphertext, SeededRlwePublicKey,
},
utils::{generate_prime, negacyclic_mul, Stats, TryConvertFrom},
utils::{generate_prime, negacyclic_mul, Stats, TryConvertFrom1},
Matrix, Secret,
};
@ -1567,11 +1565,11 @@ pub(crate) mod tests {
RlweSecret,
};
pub(crate) fn _sk_encrypt_rlwe(
pub(crate) fn _sk_encrypt_rlwe<T: Modulus<Element = u64> + Clone>(
m: &[u64],
s: &[i32],
ntt_op: &NttBackendU64,
mod_op: &ModularOpsU64,
mod_op: &ModularOpsU64<T>,
) -> RlweCiphertext<Vec<Vec<u64>>, DefaultSecureRng> {
let ring_size = m.len();
let q = mod_op.modulus();
@ -1581,7 +1579,7 @@ pub(crate) mod tests {
let mut rlwe_seed = [0u8; 32];
rng.fill_bytes(&mut rlwe_seed);
let mut seeded_rlwe_ct =
SeededRlweCiphertext::<_, [u8; 32]>::empty(ring_size as usize, rlwe_seed, q);
SeededRlweCiphertext::<_, [u8; 32], _>::empty(ring_size as usize, rlwe_seed, q.clone());
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed);
secret_key_encrypt_rlwe(
&m,
@ -1597,13 +1595,13 @@ pub(crate) mod tests {
}
// Encrypt m as RGSW ciphertext RGSW(m) using supplied public key
pub(crate) fn _pk_encrypt_rgsw(
pub(crate) fn _pk_encrypt_rgsw<T: Modulus<Element = u64> + Clone>(
m: &[u64],
public_key: &RlwePublicKey<Vec<Vec<u64>>, DefaultSecureRng>,
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
mod_op: &ModularOpsU64,
mod_op: &ModularOpsU64<T>,
ntt_op: &NttBackendU64,
) -> RgswCiphertext<Vec<Vec<u64>>> {
) -> RgswCiphertext<Vec<Vec<u64>>, T> {
let (_, ring_size) = Matrix::dimension(&public_key.data);
let gadget_vector_a = decomposer.a().gadget_vector();
let gadget_vector_b = decomposer.b().gadget_vector();
@ -1613,7 +1611,7 @@ pub(crate) mod tests {
assert!(m.len() == ring_size);
// public key encrypt RGSW(m1)
let mut rgsw_ct = RgswCiphertext::empty(ring_size, decomposer, mod_op.modulus());
let mut rgsw_ct = RgswCiphertext::empty(ring_size, decomposer, mod_op.modulus().clone());
public_key_encrypt_rgsw(
&mut rgsw_ct.data,
m,
@ -1630,13 +1628,13 @@ pub(crate) mod tests {
/// Encrypts m as RGSW ciphertext RGSW(m) using supplied secret key. Returns
/// unseeded RGSW ciphertext in coefficient domain
pub(crate) fn _sk_encrypt_rgsw(
pub(crate) fn _sk_encrypt_rgsw<T: Modulus<Element = u64> + Clone>(
m: &[u64],
s: &[i32],
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
mod_op: &ModularOpsU64,
mod_op: &ModularOpsU64<T>,
ntt_op: &NttBackendU64,
) -> SeededRgswCiphertext<Vec<Vec<u64>>, [u8; 32]> {
) -> SeededRgswCiphertext<Vec<Vec<u64>>, [u8; 32], T> {
let ring_size = s.len();
assert!(m.len() == s.len());
@ -1648,11 +1646,11 @@ pub(crate) mod tests {
let mut rng = DefaultSecureRng::new();
let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw_ct = SeededRgswCiphertext::<Vec<Vec<u64>>, [u8; 32]>::empty(
let mut seeded_rgsw_ct = SeededRgswCiphertext::<Vec<Vec<u64>>, [u8; 32], T>::empty(
ring_size as usize,
decomposer,
rgsw_seed,
q,
q.clone(),
);
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
secret_key_encrypt_rgsw(
@ -1672,12 +1670,12 @@ pub(crate) mod tests {
/// Prints noise in RGSW ciphertext RGSW(m).
///
/// - rgsw_ct: RGSW ciphertext in coefficient domain
pub(crate) fn _measure_noise_rgsw(
pub(crate) fn _measure_noise_rgsw<T: Modulus<Element = u64> + Clone>(
rgsw_ct: &[Vec<u64>],
m: &[u64],
s: &[i32],
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
q: u64,
q: &T,
) {
let gadget_vector_a = decomposer.a().gadget_vector();
let gadget_vector_b = decomposer.b().gadget_vector();
@ -1687,14 +1685,15 @@ pub(crate) mod tests {
assert!(Matrix::dimension(&rgsw_ct) == (d_a * 2 + d_b * 2, ring_size));
assert!(m.len() == ring_size);
let mod_op = ModularOpsU64::new(q);
let mod_op = ModularOpsU64::new(q.clone());
let ntt_op = NttBackendU64::new(q, ring_size);
let mul_mod = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % q as u128) as u64;
let s_poly = Vec::<u64>::try_convert_from(s, &q);
let mul_mod =
|a: &u64, b: &u64| ((*a as u128 * *b as u128) % q.q().unwrap() as u128) as u64;
let s_poly = Vec::<u64>::try_convert_from(s, q);
let mut neg_s = s_poly.clone();
mod_op.elwise_neg_mut(neg_s.as_mut());
let neg_sm0m1 = negacyclic_mul(&neg_s, &m, mul_mod, q);
let neg_sm0m1 = negacyclic_mul(&neg_s, &m, mul_mod, q.q().unwrap());
// RLWE(\beta^j -s * m)
for j in 0..d_a {
@ -1745,9 +1744,9 @@ pub(crate) mod tests {
// sample m0
let mut m0 = vec![0u64; ring_size as usize];
RandomUniformDist::<[u64]>::random_fill(&mut rng, &(1u64 << logp), m0.as_mut_slice());
RandomFillUniformInModulus::<[u64], u64>::random_fill(&mut rng, &(1u64 << logp), m0.as_mut_slice());
let ntt_op = NttBackendU64::new(q, ring_size as usize);
let ntt_op = NttBackendU64::new(&q, ring_size as usize);
let mod_op = ModularOpsU64::new(q);
// encrypt m0
@ -1788,11 +1787,11 @@ pub(crate) mod tests {
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
let mut m0 = vec![0u64; ring_size as usize];
RandomUniformDist::<[u64]>::random_fill(&mut rng, &(1u64 << logp), m0.as_mut_slice());
RandomFillUniformInModulus::<[u64], _>::random_fill(&mut rng, &(1u64 << logp), m0.as_mut_slice());
let mut m1 = vec![0u64; ring_size as usize];
m1[thread_rng().gen_range(0..ring_size) as usize] = 1;
let ntt_op = NttBackendU64::new(q, ring_size as usize);
let ntt_op = NttBackendU64::new(&q, ring_size as usize);
let mod_op = ModularOpsU64::new(q);
let d_rgsw = 10;
let logb = 5;
@ -1911,13 +1910,13 @@ pub(crate) mod tests {
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
let mut m = vec![0u64; ring_size as usize];
RandomUniformDist::random_fill(&mut rng, &p, m.as_mut_slice());
RandomFillUniformInModulus::random_fill(&mut rng, &p, m.as_mut_slice());
let encoded_m = m
.iter()
.map(|v| (((*v as f64 * q as f64) / (p as f64)).round() as u64))
.collect_vec();
let ntt_op = NttBackendU64::new(q, ring_size as usize);
let ntt_op = NttBackendU64::new(&q, ring_size as usize);
let mod_op = ModularOpsU64::new(q);
// RLWE_{s}(m)
@ -2029,7 +2028,7 @@ pub(crate) mod tests {
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
let mut rng = DefaultSecureRng::new();
let ntt_op = NttBackendU64::new(q, ring_size as usize);
let ntt_op = NttBackendU64::new(&q, ring_size as usize);
let mod_op = ModularOpsU64::new(q);
let decomposer = (
DefaultDecomposer::new(q, logb, d_rgsw),
@ -2065,7 +2064,7 @@ pub(crate) mod tests {
)
];
_measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &decomposer, q);
_measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &decomposer, &q);
for i in 0..2 {
let mut m = vec![0u64; ring_size as usize];
@ -2085,12 +2084,12 @@ pub(crate) mod tests {
// measure noise
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
_measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &decomposer, q);
_measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &decomposer, &q);
}
{
// RLWE(m) x RGSW(carry_m)
let mut m = vec![0u64; ring_size as usize];
RandomUniformDist::random_fill(&mut rng, &q, m.as_mut_slice());
RandomFillUniformInModulus::random_fill(&mut rng, &q, m.as_mut_slice());
let mut rlwe_ct = _sk_encrypt_rlwe(&m, s.values(), &ntt_op, &mod_op);
// send rgsw to evaluation domain
@ -2124,7 +2123,7 @@ pub(crate) mod tests {
DefaultDecomposer::new(q, logb, d_rgsw),
);
let ntt_op = NttBackendU64::new(q, ring_size as usize);
let ntt_op = NttBackendU64::new(&q, ring_size as usize);
let mod_op = ModularOpsU64::new(q);
let mut rng = DefaultSecureRng::new_seeded([0u8; 32]);
@ -2180,7 +2179,7 @@ pub(crate) mod tests {
// Sample m2, encrypt it as RLWE(m2) and multiply RLWE(m2)xRGSW(m0m1)
let mut m2 = vec![0u64; ring_size as usize];
RandomUniformDist::random_fill(&mut rng, &q, m2.as_mut_slice());
RandomFillUniformInModulus::random_fill(&mut rng, &q, m2.as_mut_slice());
let mut rlwe_in_ct = { _sk_encrypt_rlwe(&m2, s.values(), &ntt_op, &mod_op) };
let mut scratch_space = vec![
vec![0u64; ring_size as usize];

+ 110
- 83
src/utils.rs

@ -1,9 +1,12 @@
use std::{fmt::Debug, usize};
use itertools::Itertools;
use num_traits::{FromPrimitive, PrimInt, Signed};
use num_traits::{FromPrimitive, PrimInt, Signed, Unsigned};
use crate::RandomUniformDist;
use crate::{
backend::Modulus,
random::{RandomElement, RandomElementInModulus, RandomFill},
};
pub trait WithLocal {
fn with_local<F, R>(func: F) -> R
where
@ -16,22 +19,21 @@ pub trait WithLocal {
pub fn fill_random_ternary_secret_with_hamming_weight<
T: Signed,
R: RandomUniformDist<[u8], Parameters = u8> + RandomUniformDist<usize, Parameters = usize>,
R: RandomFill<[u8]> + RandomElementInModulus<usize, usize>,
>(
out: &mut [T],
hamming_weight: usize,
rng: &mut R,
) {
let mut bytes = vec![0u8; hamming_weight.div_ceil(8)];
RandomUniformDist::<[u8]>::random_fill(rng, &0, &mut bytes);
RandomFill::<[u8]>::random_fill(rng, &mut bytes);
let size = out.len();
let mut secret_indices = (0..size).into_iter().map(|i| i).collect_vec();
let mut bit_index = 0;
let mut byte_index = 0;
for _ in 0..hamming_weight {
let mut s_index = 0usize;
RandomUniformDist::<usize>::random_fill(rng, &secret_indices.len(), &mut s_index);
let s_index = RandomElementInModulus::<usize, usize>::random(rng, &secret_indices.len());
let curr_bit = (bytes[byte_index] >> bit_index) & 1;
if curr_bit == 1 {
@ -138,97 +140,122 @@ pub fn negacyclic_mul T>(
return r;
}
pub trait TryConvertFrom<T: ?Sized> {
type Parameters: ?Sized;
fn try_convert_from(value: &T, parameters: &Self::Parameters) -> Self;
pub trait TryConvertFrom1<T: ?Sized, P> {
fn try_convert_from(value: &T, parameters: &P) -> Self;
}
impl TryConvertFrom<[i32]> for Vec<Vec<u32>> {
type Parameters = u32;
fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self {
let row0 = value
.iter()
.map(|v| {
let is_neg = v.is_negative();
let v_u32 = v.abs() as u32;
assert!(v_u32 < *parameters);
if is_neg {
parameters - v_u32
} else {
v_u32
}
})
.collect_vec();
vec![row0]
}
}
impl TryConvertFrom<[i32]> for Vec<Vec<u64>> {
type Parameters = u64;
fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self {
let row0 = value
.iter()
.map(|v| {
let is_neg = v.is_negative();
let v_u64 = v.abs() as u64;
assert!(v_u64 < *parameters);
if is_neg {
parameters - v_u64
} else {
v_u64
}
})
.collect_vec();
vec![row0]
impl<P: Modulus<Element = u64>> TryConvertFrom1<[i64], P> for Vec<u64> {
fn try_convert_from(value: &[i64], parameters: &P) -> Self {
value.iter().map(|v| parameters.from_i64(*v)).collect_vec()
}
}
impl TryConvertFrom<[i32]> for Vec<u64> {
type Parameters = u64;
fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self {
impl<P: Modulus<Element = u64>> TryConvertFrom1<[i32], P> for Vec<u64> {
fn try_convert_from(value: &[i32], parameters: &P) -> Self {
value
.iter()
.map(|v| {
let is_neg = v.is_negative();
let v_u64 = v.abs() as u64;
assert!(v_u64 < *parameters);
if is_neg {
parameters - v_u64
} else {
v_u64
}
})
.map(|v| parameters.from_i64(*v as i64))
.collect_vec()
}
}
impl TryConvertFrom<[u64]> for Vec<i64> {
type Parameters = u64;
fn try_convert_from(value: &[u64], parameters: &Self::Parameters) -> Self {
let q = *parameters;
let qby2 = q / 2;
value
.iter()
.map(|v| {
if *v > qby2 {
-((q - v) as i64)
} else {
*v as i64
}
})
.collect_vec()
impl<P: Modulus> TryConvertFrom1<[P::Element], P> for Vec<i64> {
fn try_convert_from(value: &[P::Element], parameters: &P) -> Self {
value.iter().map(|v| parameters.to_i64(v)).collect_vec()
}
}
// pub trait TryConvertFrom<T: ?Sized> {
// type Parameters: ?Sized;
// fn try_convert_from(value: &T, parameters: &Self::Parameters) -> Self;
// }
// impl TryConvertFrom1<[i32]> for Vec<Vec<u32>> {
// type Parameters = u32;
// fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
// { let row0 = value
// .iter()
// .map(|v| {
// let is_neg = v.is_negative();
// let v_u32 = v.abs() as u32;
// assert!(v_u32 < *parameters);
// if is_neg {
// parameters - v_u32
// } else {
// v_u32
// }
// })
// .collect_vec();
// vec![row0]
// }
// }
// impl TryConvertFrom1<[i32]> for Vec<Vec<u64>> {
// type Parameters = u64;
// fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
// { let row0 = value
// .iter()
// .map(|v| {
// let is_neg = v.is_negative();
// let v_u64 = v.abs() as u64;
// assert!(v_u64 < *parameters);
// if is_neg {
// parameters - v_u64
// } else {
// v_u64
// }
// })
// .collect_vec();
// vec![row0]
// }
// }
// impl TryConvertFrom1<[i32]> for Vec<u64> {
// type Parameters = u64;
// fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
// { value
// .iter()
// .map(|v| {
// let is_neg = v.is_negative();
// let v_u64 = v.abs() as u64;
// assert!(v_u64 < *parameters);
// if is_neg {
// parameters - v_u64
// } else {
// v_u64
// }
// })
// .collect_vec()
// }
// }
// impl TryConvertFrom1<[u64]> for Vec<i64> {
// type Parameters = u64;
// fn try_convert_from(value: &[u64], parameters: &Self::Parameters) -> Self
// { let q = *parameters;
// let qby2 = q / 2;
// value
// .iter()
// .map(|v| {
// if *v > qby2 {
// -((q - v) as i64)
// } else {
// *v as i64
// }
// })
// .collect_vec()
// }
// }
pub(crate) struct Stats<T> {
pub(crate) samples: Vec<T>,
}

Loading…
Cancel
Save