mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-07 22:51:29 +01:00
add support for word-size modulus
This commit is contained in:
239
src/backend.rs
239
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: 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> 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 modulus(&self) -> Self::Element {
|
||||
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> 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 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
|
||||
// }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<El> BoolParameters<El> {
|
||||
&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<u64> = BoolParameters::<u64> {
|
||||
};
|
||||
|
||||
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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
73
src/lwe.rs
73
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<M, R> {
|
||||
|
||||
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)]
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
29
src/noise.rs
29
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]
|
||||
|
||||
24
src/ntt.rs
24
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);
|
||||
|
||||
186
src/random.rs
186
src/random.rs
@@ -17,26 +17,45 @@ pub(crate) trait NewWithSeed {
|
||||
fn new_with_seed(seed: Self::Seed) -> Self;
|
||||
}
|
||||
|
||||
pub trait RandomGaussianDist<M>
|
||||
where
|
||||
M: ?Sized,
|
||||
{
|
||||
type Parameters: ?Sized;
|
||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
|
||||
pub trait RandomElement<T> {
|
||||
/// Sample Random element of type T
|
||||
fn random(&mut self) -> T;
|
||||
}
|
||||
|
||||
pub trait RandomUniformDist<M>
|
||||
where
|
||||
M: ?Sized,
|
||||
{
|
||||
type Parameters: ?Sized;
|
||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
|
||||
pub trait RandomElementInModulus<T, M> {
|
||||
/// Sample Random element of type T in range [0, modulus)
|
||||
fn random(&mut self, modulus: &M) -> T;
|
||||
}
|
||||
|
||||
pub trait RandomUniformDist1<M, P>
|
||||
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,
|
||||
{
|
||||
/// Fill container with random elements of type of its elements
|
||||
fn random_fill(&mut self, container: &mut M);
|
||||
}
|
||||
|
||||
pub trait RandomFillUniformInModulus<M, P>
|
||||
where
|
||||
M: ?Sized,
|
||||
{
|
||||
/// Fill container with random elements in range [0, modulus)
|
||||
fn random_fill(&mut self, modulus: &P, container: &mut M);
|
||||
}
|
||||
|
||||
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,34 +86,7 @@ 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]) {
|
||||
izip!(
|
||||
(&mut self.rng).sample_iter(Uniform::new(0, parameters)),
|
||||
container.iter_mut()
|
||||
)
|
||||
.for_each(|(from, to)| {
|
||||
*to = from;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, C> RandomUniformDist1<[T], C> for DefaultSecureRng
|
||||
impl<T, C> RandomFillUniformInModulus<[T], C> for DefaultSecureRng
|
||||
where
|
||||
T: PrimInt + SampleUniform,
|
||||
C: Modulus<Element = T>,
|
||||
@@ -113,11 +105,31 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomUniformDist<[u64]> for DefaultSecureRng {
|
||||
type Parameters = u64;
|
||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
|
||||
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(0, parameters)),
|
||||
rand_distr::Normal::new(0.0, 3.19f64)
|
||||
.unwrap()
|
||||
.sample_iter(&mut self.rng),
|
||||
container.iter_mut()
|
||||
)
|
||||
.for_each(|(from, to)| {
|
||||
*to = modulus.from_f64(from);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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_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()
|
||||
.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 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()
|
||||
)
|
||||
.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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
305
src/rgsw.rs
305
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<M, R, N> {
|
||||
|
||||
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<M: MatrixEntity> RgswCiphertext<M> {
|
||||
}
|
||||
}
|
||||
|
||||
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<M, R, N> {
|
||||
|
||||
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<M: Matrix, R, N> AsRef<[M::R]> for RgswCiphertextEvaluationDomain<M, R, N>
|
||||
}
|
||||
}
|
||||
|
||||
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<M, Rng> IsTrivial for RlweCiphertext<M, Rng> {
|
||||
}
|
||||
}
|
||||
|
||||
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<M, R> {
|
||||
|
||||
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];
|
||||
|
||||
193
src/utils.rs
193
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: PrimInt, F: Fn(&T, &T) -> 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<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<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 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>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user