mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-10 08:01:30 +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 std::marker::PhantomData;
|
||||||
|
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
use num_traits::{WrappingAdd, WrappingMul, WrappingSub};
|
use num_traits::{PrimInt, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingSub, Zero};
|
||||||
|
|
||||||
pub trait Modulus {
|
pub trait Modulus {
|
||||||
type Element;
|
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
|
/// -1 in signed representaiton
|
||||||
fn neg_one(&self) -> Self::Element;
|
fn neg_one(&self) -> Self::Element;
|
||||||
/// Largest unsigned value that fits in the modulus. That is, q - 1.
|
/// 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
|
/// Smallest unsigned value that fits in the modulus
|
||||||
/// Always assmed to be 0.
|
/// Always assmed to be 0.
|
||||||
fn smallest_unsigned_value(&self) -> Self::Element;
|
fn smallest_unsigned_value(&self) -> Self::Element;
|
||||||
/// Max +value in signed representation
|
/// Convert unsigned value in signed represetation to i64
|
||||||
fn signed_max(&self) -> Self::Element;
|
fn to_i64(&self, v: &Self::Element) -> i64;
|
||||||
/// Min -value in signed representation
|
/// Convert f64 to signed represented in modulus
|
||||||
fn signed_min(&self) -> Self::Element;
|
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 {
|
pub trait ModInit {
|
||||||
|
type M;
|
||||||
|
fn new(modulus: Self::M) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetModulus {
|
||||||
type Element;
|
type Element;
|
||||||
fn new(q: Self::Element) -> Self;
|
type M: Modulus<Element = Self::Element>;
|
||||||
|
fn modulus(&self) -> &Self::M;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VectorOps {
|
pub trait VectorOps {
|
||||||
@@ -44,7 +102,7 @@ pub trait VectorOps {
|
|||||||
c: &Self::Element,
|
c: &Self::Element,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn modulus(&self) -> Self::Element;
|
// fn modulus(&self) -> Self::Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ArithmeticOps {
|
pub trait ArithmeticOps {
|
||||||
@@ -55,20 +113,28 @@ pub trait ArithmeticOps {
|
|||||||
fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
|
fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element;
|
||||||
fn neg(&self, a: &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,
|
q: u64,
|
||||||
logq: usize,
|
logq: usize,
|
||||||
barrett_mu: u128,
|
barrett_mu: u128,
|
||||||
barrett_alpha: usize,
|
barrett_alpha: usize,
|
||||||
|
modulus: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModInit for ModularOpsU64 {
|
impl<T> ModInit for ModularOpsU64<T>
|
||||||
type Element = u64;
|
where
|
||||||
fn new(q: u64) -> ModularOpsU64 {
|
T: Modulus<Element = u64>,
|
||||||
let logq = 64 - q.leading_zeros();
|
{
|
||||||
|
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
|
// barrett calculation
|
||||||
let mu = (1u128 << (logq * 2 + 3)) / (q as u128);
|
let mu = (1u128 << (logq * 2 + 3)) / (q as u128);
|
||||||
@@ -79,11 +145,12 @@ impl ModInit for ModularOpsU64 {
|
|||||||
logq: logq as usize,
|
logq: logq as usize,
|
||||||
barrett_alpha: alpha as usize,
|
barrett_alpha: alpha as usize,
|
||||||
barrett_mu: mu,
|
barrett_mu: mu,
|
||||||
|
modulus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModularOpsU64 {
|
impl<T> ModularOpsU64<T> {
|
||||||
fn add_mod_fast(&self, a: u64, b: u64) -> u64 {
|
fn add_mod_fast(&self, a: u64, b: u64) -> u64 {
|
||||||
debug_assert!(a < self.q);
|
debug_assert!(a < self.q);
|
||||||
debug_assert!(b < 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;
|
type Element = u64;
|
||||||
|
|
||||||
fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
|
fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
|
||||||
@@ -155,12 +222,12 @@ impl ArithmeticOps for ModularOpsU64 {
|
|||||||
self.q - *a
|
self.q - *a
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulus(&self) -> Self::Element {
|
// fn modulus(&self) -> Self::Element {
|
||||||
self.q
|
// self.q
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VectorOps for ModularOpsU64 {
|
impl<T> VectorOps for ModularOpsU64<T> {
|
||||||
type Element = u64;
|
type Element = u64;
|
||||||
|
|
||||||
fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
|
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 {
|
// fn modulus(&self) -> Self::Element {
|
||||||
self.q
|
// 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> {
|
pub struct WordSizeModulus<T> {
|
||||||
_phantom: PhantomData<T>,
|
modulus: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ModInit for WordSizeModulus<T> {
|
impl<T> ModInit for WordSizeModulus<T>
|
||||||
type Element = T;
|
where
|
||||||
fn new<M>(q: M) -> Self {
|
T: Modulus,
|
||||||
|
{
|
||||||
|
type M = T;
|
||||||
|
fn new(modulus: T) -> Self {
|
||||||
|
assert!(modulus.is_native());
|
||||||
// For now assume ModulusOpsU64 is only used for u64
|
// For now assume ModulusOpsU64 is only used for u64
|
||||||
Self {
|
Self { modulus: modulus }
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<T: WrappingAdd + WrappingSub + WrappingMul> ArithmeticOps for
|
impl<T> ArithmeticOps for WordSizeModulus<T>
|
||||||
// WordSizeModulus<T> { fn add(&self, a: &Self::Element, b: &Self::Element)
|
where
|
||||||
// -> Self::Element { T::wrapping_add(*a, *b)
|
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)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub(super) struct BoolParameters<El> {
|
pub(super) struct BoolParameters<El> {
|
||||||
rlwe_q: CiphertextModulus<El>,
|
rlwe_q: CiphertextModulus<El>,
|
||||||
lwe_q: CiphertextModulus<El>,
|
lwe_q: CiphertextModulus<El>,
|
||||||
br_q: CiphertextModulus<El>,
|
br_q: usize,
|
||||||
rlwe_n: PolynomialSize,
|
rlwe_n: PolynomialSize,
|
||||||
lwe_n: LweDimension,
|
lwe_n: LweDimension,
|
||||||
lwe_decomposer_base: DecompostionLogBase,
|
lwe_decomposer_base: DecompostionLogBase,
|
||||||
@@ -30,7 +32,7 @@ impl<El> BoolParameters<El> {
|
|||||||
&self.lwe_q
|
&self.lwe_q
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn br_q(&self) -> &CiphertextModulus<El> {
|
pub(crate) fn br_q(&self) -> &usize {
|
||||||
&self.br_q
|
&self.br_q
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,12 +166,72 @@ pub(crate) struct LweDimension(pub(crate) usize);
|
|||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub(crate) struct PolynomialSize(pub(crate) usize);
|
pub(crate) struct PolynomialSize(pub(crate) usize);
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[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> {
|
pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
||||||
rlwe_q: CiphertextModulus(268369921u64),
|
rlwe_q: CiphertextModulus::new_non_native(268369921u64),
|
||||||
lwe_q: CiphertextModulus(1 << 16),
|
lwe_q: CiphertextModulus::new_non_native(1 << 16),
|
||||||
br_q: CiphertextModulus(1 << 10),
|
br_q: 1 << 10,
|
||||||
rlwe_n: PolynomialSize(1 << 10),
|
rlwe_n: PolynomialSize(1 << 10),
|
||||||
lwe_n: LweDimension(493),
|
lwe_n: LweDimension(493),
|
||||||
lwe_decomposer_base: DecompostionLogBase(4),
|
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> {
|
pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
||||||
rlwe_q: CiphertextModulus(1152921504606830593),
|
rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
|
||||||
lwe_q: CiphertextModulus(1 << 20),
|
lwe_q: CiphertextModulus::new_non_native(1 << 20),
|
||||||
br_q: CiphertextModulus(1 << 11),
|
br_q: 1 << 10,
|
||||||
rlwe_n: PolynomialSize(1 << 11),
|
rlwe_n: PolynomialSize(1 << 11),
|
||||||
lwe_n: LweDimension(500),
|
lwe_n: LweDimension(500),
|
||||||
lwe_decomposer_base: DecompostionLogBase(4),
|
lwe_decomposer_base: DecompostionLogBase(4),
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ use itertools::{izip, Itertools};
|
|||||||
use num::UnsignedInteger;
|
use num::UnsignedInteger;
|
||||||
use num_traits::{abs, Zero};
|
use num_traits::{abs, Zero};
|
||||||
use rand::CryptoRng;
|
use rand::CryptoRng;
|
||||||
use random::{RandomGaussianDist, RandomUniformDist};
|
use utils::TryConvertFrom1;
|
||||||
use utils::TryConvertFrom;
|
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod bool;
|
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 num_traits::{abs, PrimInt, ToPrimitive, Zero};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ArithmeticOps, VectorOps},
|
backend::{ArithmeticOps, GetModulus, Modulus, VectorOps},
|
||||||
decomposer::Decomposer,
|
decomposer::Decomposer,
|
||||||
lwe,
|
random::{
|
||||||
num::UnsignedInteger,
|
DefaultSecureRng, NewWithSeed, RandomFillGaussianInModulus, RandomGaussianElementInModulus,
|
||||||
random::{DefaultSecureRng, NewWithSeed, RandomGaussianDist, RandomUniformDist, DEFAULT_RNG},
|
RandomFillUniformInModulus, DEFAULT_RNG,
|
||||||
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal},
|
},
|
||||||
|
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1, WithLocal},
|
||||||
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
|
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ struct LweKeySwitchingKey<M, R> {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: MatrixMut + MatrixEntity,
|
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>
|
> From<&SeededLweKeySwitchingKey<M::R, R::Seed>> for LweKeySwitchingKey<M, R>
|
||||||
where
|
where
|
||||||
M::R: RowMut,
|
M::R: RowMut,
|
||||||
@@ -64,7 +65,7 @@ where
|
|||||||
let mut p_rng = R::new_with_seed(value.seed.clone());
|
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);
|
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)| {
|
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;
|
lwe_i.as_mut()[0] = *bi;
|
||||||
});
|
});
|
||||||
LweKeySwitchingKey {
|
LweKeySwitchingKey {
|
||||||
@@ -132,9 +133,11 @@ pub(crate) fn lwe_key_switch<
|
|||||||
pub fn lwe_ksk_keygen<
|
pub fn lwe_ksk_keygen<
|
||||||
Ro: Row + RowMut + RowEntity,
|
Ro: Row + RowMut + RowEntity,
|
||||||
S,
|
S,
|
||||||
Op: VectorOps<Element = Ro::Element> + ArithmeticOps<Element = Ro::Element>,
|
Op: VectorOps<Element = Ro::Element>
|
||||||
R: RandomGaussianDist<Ro::Element, Parameters = Ro::Element>,
|
+ ArithmeticOps<Element = Ro::Element>
|
||||||
PR: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
|
+ GetModulus<Element = Ro::Element>,
|
||||||
|
R: RandomGaussianElementInModulus<Ro::Element, Op::M>,
|
||||||
|
PR: RandomFillUniformInModulus<[Ro::Element], Op::M>,
|
||||||
>(
|
>(
|
||||||
from_lwe_sk: &[S],
|
from_lwe_sk: &[S],
|
||||||
to_lwe_sk: &[S],
|
to_lwe_sk: &[S],
|
||||||
@@ -144,17 +147,17 @@ pub fn lwe_ksk_keygen<
|
|||||||
p_rng: &mut PR,
|
p_rng: &mut PR,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
|
Ro: TryConvertFrom1<[S], Op::M>,
|
||||||
Ro::Element: Zero + Debug,
|
Ro::Element: Zero + Debug,
|
||||||
{
|
{
|
||||||
assert!(ksk_out.as_ref().len() == (from_lwe_sk.len() * gadget.len()));
|
assert!(ksk_out.as_ref().len() == (from_lwe_sk.len() * gadget.len()));
|
||||||
|
|
||||||
let d = gadget.len();
|
let d = gadget.len();
|
||||||
|
|
||||||
let modulus = VectorOps::modulus(operator);
|
let modulus = operator.modulus();
|
||||||
let mut neg_sk_in_m = Ro::try_convert_from(from_lwe_sk, &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());
|
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());
|
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)| {
|
|(neg_sk_in_si, d_lwes_partb)| {
|
||||||
izip!(gadget.iter(), d_lwes_partb.into_iter()).for_each(|(f, lwe_b)| {
|
izip!(gadget.iter(), d_lwes_partb.into_iter()).for_each(|(f, lwe_b)| {
|
||||||
// sample `a`
|
// sample `a`
|
||||||
RandomUniformDist::random_fill(p_rng, &modulus, scratch.as_mut());
|
RandomFillUniformInModulus::random_fill(p_rng, &modulus, scratch.as_mut());
|
||||||
|
|
||||||
// a * z
|
// a * z
|
||||||
let mut az = Ro::Element::zero();
|
let mut az = Ro::Element::zero();
|
||||||
@@ -173,8 +176,7 @@ pub fn lwe_ksk_keygen<
|
|||||||
|
|
||||||
// a*z + (-s_i)*\beta^j + e
|
// a*z + (-s_i)*\beta^j + e
|
||||||
let mut b = operator.add(&az, &operator.mul(f, neg_sk_in_si));
|
let mut b = operator.add(&az, &operator.mul(f, neg_sk_in_si));
|
||||||
let mut e = Ro::Element::zero();
|
let e = RandomGaussianElementInModulus::random(rng, &modulus);
|
||||||
RandomGaussianDist::random_fill(rng, &modulus, &mut e);
|
|
||||||
b = operator.add(&b, &e);
|
b = operator.add(&b, &e);
|
||||||
|
|
||||||
*lwe_b = b;
|
*lwe_b = b;
|
||||||
@@ -186,10 +188,9 @@ pub fn lwe_ksk_keygen<
|
|||||||
/// Encrypts encoded message m as LWE ciphertext
|
/// Encrypts encoded message m as LWE ciphertext
|
||||||
pub fn encrypt_lwe<
|
pub fn encrypt_lwe<
|
||||||
Ro: Row + RowMut,
|
Ro: Row + RowMut,
|
||||||
R: RandomGaussianDist<Ro::Element, Parameters = Ro::Element>
|
Op: ArithmeticOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
|
||||||
+ RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
|
R: RandomGaussianElementInModulus<Ro::Element, Op::M> + RandomFillUniformInModulus<[Ro::Element], Op::M>,
|
||||||
S,
|
S,
|
||||||
Op: ArithmeticOps<Element = Ro::Element>,
|
|
||||||
>(
|
>(
|
||||||
lwe_out: &mut Ro,
|
lwe_out: &mut Ro,
|
||||||
m: &Ro::Element,
|
m: &Ro::Element,
|
||||||
@@ -197,14 +198,14 @@ pub fn encrypt_lwe<
|
|||||||
operator: &Op,
|
operator: &Op,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
|
Ro: TryConvertFrom1<[S], Op::M>,
|
||||||
Ro::Element: Zero,
|
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));
|
assert!(s.as_ref().len() == (lwe_out.as_ref().len() - 1));
|
||||||
|
|
||||||
// a*s
|
// 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();
|
let mut sa = Ro::Element::zero();
|
||||||
izip!(lwe_out.as_mut().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
|
izip!(lwe_out.as_mut().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
|
||||||
let tmp = operator.mul(ai, si);
|
let tmp = operator.mul(ai, si);
|
||||||
@@ -212,22 +213,25 @@ pub fn encrypt_lwe<
|
|||||||
});
|
});
|
||||||
|
|
||||||
// b = a*s + e + m
|
// b = a*s + e + m
|
||||||
let mut e = Ro::Element::zero();
|
let e = RandomGaussianElementInModulus::random(rng, operator.modulus());
|
||||||
RandomGaussianDist::random_fill(rng, &operator.modulus(), &mut e);
|
|
||||||
let b = operator.add(&operator.add(&sa, &e), m);
|
let b = operator.add(&operator.add(&sa, &e), m);
|
||||||
lwe_out.as_mut()[0] = b;
|
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,
|
lwe_ct: &Ro,
|
||||||
s: &[S],
|
s: &[S],
|
||||||
operator: &Op,
|
operator: &Op,
|
||||||
) -> Ro::Element
|
) -> Ro::Element
|
||||||
where
|
where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
|
Ro: TryConvertFrom1<[S], Op::M>,
|
||||||
Ro::Element: Zero,
|
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();
|
let mut sa = Ro::Element::zero();
|
||||||
izip!(lwe_ct.as_ref().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
|
izip!(lwe_ct.as_ref().iter().skip(1), s.as_ref()).for_each(|(ai, si)| {
|
||||||
@@ -244,14 +248,18 @@ where
|
|||||||
/// - ct: Input LWE ciphertext
|
/// - ct: Input LWE ciphertext
|
||||||
/// - s: corresponding secret
|
/// - s: corresponding secret
|
||||||
/// - ideal_m: Ideal `encoded` message
|
/// - 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,
|
ct: &Ro,
|
||||||
s: &[S],
|
s: &[S],
|
||||||
operator: &Op,
|
operator: &Op,
|
||||||
ideal_m: &Ro::Element,
|
ideal_m: &Ro::Element,
|
||||||
) -> f64
|
) -> f64
|
||||||
where
|
where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
|
Ro: TryConvertFrom1<[S], Op::M>,
|
||||||
Ro::Element: Zero + ToPrimitive + PrimInt + Display,
|
Ro::Element: Zero + ToPrimitive + PrimInt + Display,
|
||||||
{
|
{
|
||||||
assert!(s.len() == ct.as_ref().len() - 1,);
|
assert!(s.len() == ct.as_ref().len() - 1,);
|
||||||
@@ -265,10 +273,7 @@ where
|
|||||||
|
|
||||||
let mut diff = operator.sub(&m, ideal_m);
|
let mut diff = operator.sub(&m, ideal_m);
|
||||||
let q = operator.modulus();
|
let q = operator.modulus();
|
||||||
if diff > (q >> 1) {
|
return q.to_i64(&diff).to_f64().unwrap().abs().log2();
|
||||||
diff = q - diff;
|
|
||||||
}
|
|
||||||
return diff.to_f64().unwrap().log2();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::VectorOps,
|
backend::{GetModulus, VectorOps},
|
||||||
ntt::Ntt,
|
ntt::Ntt,
|
||||||
random::{NewWithSeed, RandomGaussianDist, RandomUniformDist},
|
random::{NewWithSeed, RandomFillGaussianInModulus, RandomFillUniformInModulus},
|
||||||
utils::TryConvertFrom,
|
utils::TryConvertFrom1,
|
||||||
Matrix, Row, RowEntity, RowMut,
|
Matrix, Row, RowEntity, RowMut,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn public_key_share<
|
pub(crate) fn public_key_share<
|
||||||
R: Row + RowMut + RowEntity,
|
R: Row + RowMut + RowEntity,
|
||||||
S,
|
S,
|
||||||
ModOp: VectorOps<Element = R::Element>,
|
ModOp: VectorOps<Element = R::Element> + GetModulus<Element = R::Element>,
|
||||||
NttOp: Ntt<Element = R::Element>,
|
NttOp: Ntt<Element = R::Element>,
|
||||||
Rng: RandomGaussianDist<[R::Element], Parameters = R::Element>,
|
Rng: RandomFillGaussianInModulus<[R::Element], ModOp::M>,
|
||||||
PRng: RandomUniformDist<[R::Element], Parameters = R::Element>,
|
PRng: RandomFillUniformInModulus<[R::Element], ModOp::M>,
|
||||||
>(
|
>(
|
||||||
share_out: &mut R,
|
share_out: &mut R,
|
||||||
s_i: &[S],
|
s_i: &[S],
|
||||||
@@ -21,7 +21,7 @@ pub(crate) fn public_key_share<
|
|||||||
p_rng: &mut PRng,
|
p_rng: &mut PRng,
|
||||||
rng: &mut Rng,
|
rng: &mut Rng,
|
||||||
) where
|
) where
|
||||||
R: TryConvertFrom<[S], Parameters = R::Element>,
|
R: TryConvertFrom1<[S], ModOp::M>,
|
||||||
{
|
{
|
||||||
let ring_size = share_out.as_ref().len();
|
let ring_size = share_out.as_ref().len();
|
||||||
assert!(s_i.len() == ring_size);
|
assert!(s_i.len() == ring_size);
|
||||||
@@ -31,7 +31,7 @@ pub(crate) fn public_key_share<
|
|||||||
// sample a
|
// sample a
|
||||||
let mut a = {
|
let mut a = {
|
||||||
let mut a = R::zeros(ring_size);
|
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
|
a
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,6 +42,6 @@ pub(crate) fn public_key_share<
|
|||||||
modop.elwise_mul_mut(s.as_mut(), a.as_ref());
|
modop.elwise_mul_mut(s.as_mut(), a.as_ref());
|
||||||
nttop.backward(s.as_mut());
|
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
|
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 {
|
mod tests {
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::{
|
// use crate::{
|
||||||
backend::{ArithmeticOps, ModInit, ModularOpsU64},
|
// backend::{ArithmeticOps, ModInit, ModularOpsU64},
|
||||||
decomposer::{Decomposer, DefaultDecomposer},
|
// decomposer::{Decomposer, DefaultDecomposer},
|
||||||
ntt::{Ntt, NttBackendU64, NttInit},
|
// ntt::{Ntt, NttBackendU64, NttInit},
|
||||||
random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist},
|
// random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist},
|
||||||
rgsw::{
|
// rgsw::{
|
||||||
less1_rlwe_by_rgsw, measure_noise, rgsw_by_rgsw_inplace, rlwe_by_rgsw,
|
// less1_rlwe_by_rgsw, measure_noise, rgsw_by_rgsw_inplace,
|
||||||
secret_key_encrypt_rgsw, secret_key_encrypt_rlwe, RgswCiphertext,
|
// rlwe_by_rgsw, secret_key_encrypt_rgsw,
|
||||||
RgswCiphertextEvaluationDomain, RlweCiphertext, RlweSecret, SeededRgswCiphertext,
|
// secret_key_encrypt_rlwe, RgswCiphertext,
|
||||||
SeededRlweCiphertext,
|
// RgswCiphertextEvaluationDomain, RlweCiphertext, RlweSecret,
|
||||||
},
|
// SeededRgswCiphertext, SeededRlweCiphertext,
|
||||||
utils::{generate_prime, negacyclic_mul},
|
// },
|
||||||
Matrix, Row, Secret,
|
// utils::{generate_prime, negacyclic_mul},
|
||||||
};
|
// Matrix, Row, Secret,
|
||||||
|
// };
|
||||||
|
|
||||||
// // Test B part with limbd -1 when variance of m is 1
|
// // Test B part with limbd -1 when variance of m is 1
|
||||||
// #[test]
|
// #[test]
|
||||||
|
|||||||
24
src/ntt.rs
24
src/ntt.rs
@@ -3,15 +3,14 @@ use rand::{thread_rng, Rng, RngCore, SeedableRng};
|
|||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ArithmeticOps, ModInit, ModularOpsU64},
|
backend::{ArithmeticOps, ModInit, ModularOpsU64, Modulus},
|
||||||
utils::{mod_exponent, mod_inverse, shoup_representation_fq},
|
utils::{mod_exponent, mod_inverse, shoup_representation_fq},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait NttInit {
|
pub trait NttInit<M> {
|
||||||
type Element;
|
|
||||||
/// Ntt istance must be compatible across different instances with same `q`
|
/// Ntt istance must be compatible across different instances with same `q`
|
||||||
/// and `n`
|
/// and `n`
|
||||||
fn new(q: Self::Element, n: usize) -> Self;
|
fn new(q: &M, n: usize) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Ntt {
|
pub trait Ntt {
|
||||||
@@ -204,9 +203,8 @@ pub struct NttBackendU64 {
|
|||||||
psi_inv_powers_bo_shoup: Box<[u64]>,
|
psi_inv_powers_bo_shoup: Box<[u64]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NttInit for NttBackendU64 {
|
impl NttBackendU64 {
|
||||||
type Element = u64;
|
fn _new(q: u64, n: usize) -> Self {
|
||||||
fn new(q: u64, n: usize) -> Self {
|
|
||||||
// \psi = 2n^{th} primitive root of unity in F_q
|
// \psi = 2n^{th} primitive root of unity in F_q
|
||||||
let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
|
let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
|
||||||
let psi = find_primitive_root(q, (n * 2) as u64, &mut rng)
|
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 {
|
impl NttBackendU64 {
|
||||||
fn reduce_from_lazy(&self, a: &mut [u64]) {
|
fn reduce_from_lazy(&self, a: &mut [u64]) {
|
||||||
let q = self.q;
|
let q = self.q;
|
||||||
@@ -356,7 +362,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn native_ntt_backend_works() {
|
fn native_ntt_backend_works() {
|
||||||
// TODO(Jay): Improve tests. Add tests for different primes and ring size.
|
// 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 {
|
for _ in 0..K {
|
||||||
let mut a = random_vec_in_fq(N, Q_60_BITS);
|
let mut a = random_vec_in_fq(N, Q_60_BITS);
|
||||||
let a_clone = a.clone();
|
let a_clone = a.clone();
|
||||||
@@ -391,7 +397,7 @@ mod tests {
|
|||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
for p in primes.into_iter() {
|
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);
|
let modulus_backend = ModularOpsU64::new(p);
|
||||||
for _ in 0..K {
|
for _ in 0..K {
|
||||||
let a = random_vec_in_fq(N, p);
|
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;
|
fn new_with_seed(seed: Self::Seed) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RandomGaussianDist<M>
|
pub trait RandomElement<T> {
|
||||||
where
|
/// Sample Random element of type T
|
||||||
M: ?Sized,
|
fn random(&mut self) -> T;
|
||||||
{
|
|
||||||
type Parameters: ?Sized;
|
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RandomUniformDist<M>
|
pub trait RandomElementInModulus<T, M> {
|
||||||
where
|
/// Sample Random element of type T in range [0, modulus)
|
||||||
M: ?Sized,
|
fn random(&mut self, modulus: &M) -> T;
|
||||||
{
|
|
||||||
type Parameters: ?Sized;
|
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut M);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
M: ?Sized,
|
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);
|
fn random_fill(&mut self, modulus: &P, container: &mut M);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,34 +86,7 @@ impl NewWithSeed for DefaultSecureRng {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomUniformDist<usize> for DefaultSecureRng {
|
impl<T, C> RandomFillUniformInModulus<[T], C> 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
|
|
||||||
where
|
where
|
||||||
T: PrimInt + SampleUniform,
|
T: PrimInt + SampleUniform,
|
||||||
C: Modulus<Element = T>,
|
C: Modulus<Element = T>,
|
||||||
@@ -113,11 +105,31 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomUniformDist<[u64]> for DefaultSecureRng {
|
impl<T, C> RandomFillGaussianInModulus<[T], C> for DefaultSecureRng
|
||||||
type Parameters = u64;
|
where
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
|
T: PrimInt + SampleUniform,
|
||||||
|
C: Modulus<Element = T>,
|
||||||
|
{
|
||||||
|
fn random_fill(&mut self, modulus: &C, container: &mut [T]) {
|
||||||
izip!(
|
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()
|
container.iter_mut()
|
||||||
)
|
)
|
||||||
.for_each(|(from, to)| {
|
.for_each(|(from, to)| {
|
||||||
@@ -126,83 +138,31 @@ impl RandomUniformDist<[u64]> for DefaultSecureRng {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomGaussianDist<u64> for DefaultSecureRng {
|
impl<T> RandomElement<T> for DefaultSecureRng
|
||||||
type Parameters = u64;
|
where
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u64) {
|
T: PrimInt + SampleUniform,
|
||||||
let o = rand_distr::Normal::new(0.0, 3.19f64)
|
{
|
||||||
.unwrap()
|
fn random(&mut self) -> T {
|
||||||
.sample(&mut self.rng)
|
Uniform::new_inclusive(T::zero(), T::max_value()).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 RandomGaussianDist<u32> for DefaultSecureRng {
|
impl<T> RandomElementInModulus<T, T> for DefaultSecureRng
|
||||||
type Parameters = u32;
|
where
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut u32) {
|
T: PrimInt + SampleUniform,
|
||||||
let o = rand_distr::Normal::new(0.0, 3.19f32)
|
{
|
||||||
.unwrap()
|
fn random(&mut self, modulus: &T) -> T {
|
||||||
.sample(&mut self.rng)
|
Uniform::new_inclusive(T::zero(), modulus).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 RandomGaussianDist<[u64]> for DefaultSecureRng {
|
impl<T, M: Modulus<Element = T>> RandomGaussianElementInModulus<T, M> for DefaultSecureRng {
|
||||||
type Parameters = u64;
|
fn random(&mut self, modulus: &M) -> T {
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
|
modulus.from_f64(
|
||||||
izip!(
|
|
||||||
rand_distr::Normal::new(0.0, 3.19f64)
|
rand_distr::Normal::new(0.0, 3.19f64)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.sample_iter(&mut self.rng),
|
.sample(&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()
|
|
||||||
)
|
|
||||||
.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 num_traits::{PrimInt, Signed, ToPrimitive, Zero};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ArithmeticOps, VectorOps},
|
backend::{ArithmeticOps, GetModulus, Modulus, VectorOps},
|
||||||
decomposer::{self, Decomposer, RlweDecomposer},
|
decomposer::{self, Decomposer, RlweDecomposer},
|
||||||
ntt::{self, Ntt, NttInit},
|
ntt::{self, Ntt, NttInit},
|
||||||
random::{DefaultSecureRng, NewWithSeed, RandomGaussianDist, RandomUniformDist},
|
random::{
|
||||||
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal},
|
DefaultSecureRng, NewWithSeed, RandomElementInModulus, RandomFill, RandomFillGaussianInModulus,
|
||||||
|
RandomFillUniformInModulus,
|
||||||
|
},
|
||||||
|
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1, WithLocal},
|
||||||
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
|
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SeededAutoKey<M, S>
|
pub struct SeededAutoKey<M, S, Mod>
|
||||||
where
|
where
|
||||||
M: Matrix,
|
M: Matrix,
|
||||||
{
|
{
|
||||||
data: M,
|
data: M,
|
||||||
seed: S,
|
seed: S,
|
||||||
modulus: M::MatElement,
|
modulus: Mod,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Matrix + MatrixEntity, S> SeededAutoKey<M, S> {
|
impl<M: Matrix + MatrixEntity, S, Mod: Modulus<Element = M::MatElement>> SeededAutoKey<M, S, Mod> {
|
||||||
fn empty<D: Decomposer>(
|
fn empty<D: Decomposer>(ring_size: usize, auto_decomposer: &D, seed: S, modulus: Mod) -> Self {
|
||||||
ring_size: usize,
|
|
||||||
auto_decomposer: &D,
|
|
||||||
seed: S,
|
|
||||||
modulus: M::MatElement,
|
|
||||||
) -> Self {
|
|
||||||
SeededAutoKey {
|
SeededAutoKey {
|
||||||
data: M::zeros(auto_decomposer.decomposition_count(), ring_size),
|
data: M::zeros(auto_decomposer.decomposition_count(), ring_size),
|
||||||
seed,
|
seed,
|
||||||
modulus: modulus,
|
modulus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,22 +46,23 @@ pub struct AutoKeyEvaluationDomain<M, R, N> {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: MatrixMut + MatrixEntity,
|
M: MatrixMut + MatrixEntity,
|
||||||
R: RandomUniformDist<[M::MatElement], Parameters = M::MatElement> + NewWithSeed,
|
Mod: Modulus<Element = M::MatElement> + Clone,
|
||||||
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement>,
|
R: RandomFillUniformInModulus<[M::MatElement], Mod> + NewWithSeed,
|
||||||
> From<&SeededAutoKey<M, R::Seed>> for AutoKeyEvaluationDomain<M, R, N>
|
N: NttInit<Mod> + Ntt<Element = M::MatElement>,
|
||||||
|
> From<&SeededAutoKey<M, R::Seed, Mod>> for AutoKeyEvaluationDomain<M, R, N>
|
||||||
where
|
where
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
M::MatElement: Copy,
|
M::MatElement: Copy,
|
||||||
R::Seed: Clone,
|
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 (d, ring_size) = value.data.dimension();
|
||||||
let mut data = M::zeros(2 * d, ring_size);
|
let mut data = M::zeros(2 * d, ring_size);
|
||||||
|
|
||||||
// sample RLWE'_A(-s(X^k))
|
// sample RLWE'_A(-s(X^k))
|
||||||
let mut p_rng = R::new_with_seed(value.seed.clone());
|
let mut p_rng = R::new_with_seed(value.seed.clone());
|
||||||
data.iter_rows_mut().take(d).for_each(|r| {
|
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))
|
// copy over RLWE'_B(-s(X^k))
|
||||||
@@ -72,7 +71,7 @@ where
|
|||||||
});
|
});
|
||||||
|
|
||||||
// send RLWE'(-s(X^k)) polynomials to evaluation domain
|
// 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()
|
data.iter_rows_mut()
|
||||||
.for_each(|r| ntt_op.forward(r.as_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
|
/// Rgsw ciphertext polynomials
|
||||||
pub(crate) data: M,
|
pub(crate) data: M,
|
||||||
modulus: M::MatElement,
|
modulus: Mod,
|
||||||
/// Decomposition for RLWE part A
|
/// Decomposition for RLWE part A
|
||||||
d_a: usize,
|
d_a: usize,
|
||||||
/// Decomposition for RLWE part B
|
/// Decomposition for RLWE part B
|
||||||
d_b: usize,
|
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>(
|
pub(crate) fn empty<D: RlweDecomposer>(
|
||||||
ring_size: usize,
|
ring_size: usize,
|
||||||
decomposer: &D,
|
decomposer: &D,
|
||||||
modulus: M::MatElement,
|
modulus: Mod,
|
||||||
) -> RgswCiphertext<M> {
|
) -> RgswCiphertext<M, Mod> {
|
||||||
RgswCiphertext {
|
RgswCiphertext {
|
||||||
data: M::zeros(
|
data: M::zeros(
|
||||||
decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count() * 2,
|
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
|
where
|
||||||
M: Matrix,
|
M: Matrix,
|
||||||
{
|
{
|
||||||
pub(crate) data: M,
|
pub(crate) data: M,
|
||||||
seed: S,
|
seed: S,
|
||||||
modulus: M::MatElement,
|
modulus: Mod,
|
||||||
/// Decomposition for RLWE part A
|
/// Decomposition for RLWE part A
|
||||||
d_a: usize,
|
d_a: usize,
|
||||||
/// Decomposition for RLWE part B
|
/// Decomposition for RLWE part B
|
||||||
d_b: usize,
|
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>(
|
pub(crate) fn empty<D: RlweDecomposer>(
|
||||||
ring_size: usize,
|
ring_size: usize,
|
||||||
decomposer: &D,
|
decomposer: &D,
|
||||||
seed: S,
|
seed: S,
|
||||||
modulus: M::MatElement,
|
modulus: Mod,
|
||||||
) -> SeededRgswCiphertext<M, S> {
|
) -> SeededRgswCiphertext<M, S, Mod> {
|
||||||
SeededRgswCiphertext {
|
SeededRgswCiphertext {
|
||||||
data: M::zeros(
|
data: M::zeros(
|
||||||
decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count(),
|
decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count(),
|
||||||
ring_size,
|
ring_size,
|
||||||
),
|
),
|
||||||
seed,
|
seed,
|
||||||
modulus: modulus,
|
modulus,
|
||||||
d_a: decomposer.a().decomposition_count(),
|
d_a: decomposer.a().decomposition_count(),
|
||||||
d_b: decomposer.b().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
|
where
|
||||||
M::MatElement: Debug,
|
M::MatElement: Debug,
|
||||||
{
|
{
|
||||||
@@ -164,16 +163,17 @@ pub struct RgswCiphertextEvaluationDomain<M, R, N> {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: MatrixMut + MatrixEntity,
|
M: MatrixMut + MatrixEntity,
|
||||||
R: NewWithSeed + RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
|
Mod: Modulus<Element = M::MatElement>,
|
||||||
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement> + Debug,
|
R: NewWithSeed + RandomFillUniformInModulus<[M::MatElement], Mod>,
|
||||||
> From<&SeededRgswCiphertext<M, R::Seed>> for RgswCiphertextEvaluationDomain<M, R, N>
|
N: NttInit<Mod> + Ntt<Element = M::MatElement> + Debug,
|
||||||
|
> From<&SeededRgswCiphertext<M, R::Seed, Mod>> for RgswCiphertextEvaluationDomain<M, R, N>
|
||||||
where
|
where
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
M::MatElement: Copy,
|
M::MatElement: Copy,
|
||||||
R::Seed: Clone,
|
R::Seed: Clone,
|
||||||
M: Debug,
|
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);
|
let mut data = M::zeros(value.d_a * 2 + value.d_b * 2, value.data.dimension().1);
|
||||||
|
|
||||||
// copy RLWE'(-sm)
|
// copy RLWE'(-sm)
|
||||||
@@ -203,7 +203,7 @@ where
|
|||||||
|
|
||||||
// Send polynomials to evaluation domain
|
// Send polynomials to evaluation domain
|
||||||
let ring_size = data.dimension().1;
|
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()
|
data.iter_rows_mut()
|
||||||
.for_each(|ri| nttop.forward(ri.as_mut()));
|
.for_each(|ri| nttop.forward(ri.as_mut()));
|
||||||
|
|
||||||
@@ -216,15 +216,16 @@ where
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: MatrixMut + MatrixEntity,
|
M: MatrixMut + MatrixEntity,
|
||||||
|
Mod: Modulus<Element = M::MatElement>,
|
||||||
R,
|
R,
|
||||||
N: NttInit<Element = M::MatElement> + Ntt<Element = M::MatElement>,
|
N: NttInit<Mod> + Ntt<Element = M::MatElement>,
|
||||||
> From<&RgswCiphertext<M>> for RgswCiphertextEvaluationDomain<M, R, N>
|
> From<&RgswCiphertext<M, Mod>> for RgswCiphertextEvaluationDomain<M, R, N>
|
||||||
where
|
where
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
M::MatElement: Copy,
|
M::MatElement: Copy,
|
||||||
M: Debug,
|
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);
|
let mut data = M::zeros(value.d_a * 2 + value.d_b * 2, value.data.dimension().1);
|
||||||
|
|
||||||
// copy RLWE'(-sm)
|
// copy RLWE'(-sm)
|
||||||
@@ -247,7 +248,7 @@ where
|
|||||||
|
|
||||||
// Send polynomials to evaluation domain
|
// Send polynomials to evaluation domain
|
||||||
let ring_size = data.dimension().1;
|
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()
|
data.iter_rows_mut()
|
||||||
.for_each(|ri| nttop.forward(ri.as_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>
|
pub struct SeededRlweCiphertext<R, S, Mod> {
|
||||||
where
|
|
||||||
R: Row,
|
|
||||||
{
|
|
||||||
pub(crate) data: R,
|
pub(crate) data: R,
|
||||||
pub(crate) seed: S,
|
pub(crate) seed: S,
|
||||||
pub(crate) modulus: R::Element,
|
pub(crate) modulus: Mod,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RowEntity, S> SeededRlweCiphertext<R, S> {
|
impl<R: RowEntity, S, Mod> SeededRlweCiphertext<R, S, Mod> {
|
||||||
pub(crate) fn empty(ring_size: usize, seed: S, modulus: R::Element) -> Self {
|
pub(crate) fn empty(ring_size: usize, seed: S, modulus: Mod) -> Self {
|
||||||
SeededRlweCiphertext {
|
SeededRlweCiphertext {
|
||||||
data: R::zeros(ring_size),
|
data: R::zeros(ring_size),
|
||||||
seed,
|
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>
|
impl<
|
||||||
From<&SeededRlweCiphertext<R, Rng::Seed>> for RlweCiphertext<M, Rng>
|
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
|
where
|
||||||
Rng::Seed: Clone,
|
Rng::Seed: Clone,
|
||||||
Rng: RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
|
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
R::Element: Copy,
|
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());
|
let mut data = M::zeros(2, value.data.as_ref().len());
|
||||||
|
|
||||||
// sample a
|
// sample a
|
||||||
let mut p_rng = Rng::new_with_seed(value.seed.clone());
|
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());
|
data.get_row_mut(1).copy_from_slice(value.data.as_ref());
|
||||||
|
|
||||||
@@ -413,7 +414,7 @@ pub struct RlwePublicKey<M, R> {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
M: MatrixMut + MatrixEntity,
|
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>
|
> From<&SeededRlwePublicKey<M::R, Rng::Seed>> for RlwePublicKey<M, Rng>
|
||||||
where
|
where
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
@@ -425,7 +426,7 @@ where
|
|||||||
|
|
||||||
// sample a
|
// sample a
|
||||||
let mut p_rng = Rng::new_with_seed(value.seed);
|
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
|
// copy over b
|
||||||
data.get_row_mut(1).copy_from_slice(value.data.as_ref());
|
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<
|
pub(crate) fn secret_key_encrypt_rgsw<
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
Mmut: MatrixMut + MatrixEntity,
|
||||||
S,
|
S,
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>
|
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>
|
||||||
+ RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
+ RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
ModOp: VectorOps<Element = Mmut::MatElement>,
|
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
|
||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
>(
|
>(
|
||||||
out_rgsw: &mut Mmut,
|
out_rgsw: &mut Mmut,
|
||||||
@@ -972,8 +973,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
|
|||||||
p_rng: &mut PR,
|
p_rng: &mut PR,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
<Mmut as Matrix>::R:
|
<Mmut as Matrix>::R: RowMut + RowEntity + TryConvertFrom1<[S], ModOp::M> + Debug,
|
||||||
RowMut + RowEntity + TryConvertFrom<[S], Parameters = Mmut::MatElement> + Debug,
|
|
||||||
Mmut::MatElement: Copy + Debug,
|
Mmut::MatElement: Copy + Debug,
|
||||||
{
|
{
|
||||||
let d_a = gadget_a.len();
|
let d_a = gadget_a.len();
|
||||||
@@ -1000,7 +1000,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
|
|||||||
)
|
)
|
||||||
.for_each(|(ai, bi, beta_i)| {
|
.for_each(|(ai, bi, beta_i)| {
|
||||||
// Sample a_i
|
// Sample a_i
|
||||||
RandomUniformDist::random_fill(rng, &q, ai.as_mut());
|
RandomFillUniformInModulus::random_fill(rng, &q, ai.as_mut());
|
||||||
|
|
||||||
// a_i * s
|
// a_i * s
|
||||||
scratch_space.as_mut().copy_from_slice(ai.as_ref());
|
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());
|
ntt_op.backward(scratch_space.as_mut());
|
||||||
|
|
||||||
// b_i = e_i + a_i * s
|
// 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());
|
mod_op.elwise_add_mut(bi.as_mut(), scratch_space.as_ref());
|
||||||
|
|
||||||
// a_i + \beta_i * m
|
// 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
|
// polynomials of part A of RLWE'(m) are sampled from seed
|
||||||
let mut a = Mmut::zeros(d_b, ring_size);
|
let mut a = Mmut::zeros(d_b, ring_size);
|
||||||
a.iter_rows_mut()
|
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
|
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);
|
mod_op.elwise_scalar_mul(scratch_space.as_mut(), m.as_ref(), beta_i);
|
||||||
|
|
||||||
// Sample e_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
|
// 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(), scratch_space.as_ref());
|
||||||
mod_op.elwise_add_mut(bi.as_mut(), ai.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<
|
pub(crate) fn public_key_encrypt_rgsw<
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
Mmut: MatrixMut + MatrixEntity,
|
||||||
M: Matrix<MatElement = Mmut::MatElement>,
|
M: Matrix<MatElement = Mmut::MatElement>,
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>
|
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>
|
||||||
+ RandomUniformDist<[u8], Parameters = u8>
|
+ RandomFill<[u8]>
|
||||||
+ RandomUniformDist<usize, Parameters = usize>,
|
+ RandomElementInModulus<usize, usize>,
|
||||||
ModOp: VectorOps<Element = Mmut::MatElement>,
|
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
|
||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
>(
|
>(
|
||||||
out_rgsw: &mut Mmut,
|
out_rgsw: &mut Mmut,
|
||||||
@@ -1066,7 +1066,7 @@ pub(crate) fn public_key_encrypt_rgsw<
|
|||||||
ntt_op: &NttOp,
|
ntt_op: &NttOp,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) 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,
|
Mmut::MatElement: Copy,
|
||||||
{
|
{
|
||||||
let ring_size = public_key.dimension().1;
|
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());
|
ntt_op.backward(u_eval_copy.as_mut());
|
||||||
|
|
||||||
// sample error
|
// sample error
|
||||||
RandomGaussianDist::random_fill(rng, &q, ai.as_mut());
|
RandomFillGaussianInModulus::random_fill(rng, &q, ai.as_mut());
|
||||||
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
|
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
|
||||||
|
|
||||||
// a = p0*u+e0
|
// a = p0*u+e0
|
||||||
mod_op.elwise_add_mut(ai.as_mut(), u_eval.as_ref());
|
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());
|
ntt_op.backward(u_eval_copy.as_mut());
|
||||||
|
|
||||||
// sample error
|
// sample error
|
||||||
RandomGaussianDist::random_fill(rng, &q, ai.as_mut());
|
RandomFillGaussianInModulus::random_fill(rng, &q, ai.as_mut());
|
||||||
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
|
RandomFillGaussianInModulus::random_fill(rng, &q, bi.as_mut());
|
||||||
|
|
||||||
// a = p0*u+e0
|
// a = p0*u+e0
|
||||||
mod_op.elwise_add_mut(ai.as_mut(), u_eval.as_ref());
|
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.
|
/// - to_s: secret polynomial to key switch to.
|
||||||
pub(crate) fn rlwe_ksk_gen<
|
pub(crate) fn rlwe_ksk_gen<
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
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>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
>(
|
>(
|
||||||
ksk_out: &mut Mmut,
|
ksk_out: &mut Mmut,
|
||||||
neg_from_s: Mmut::R,
|
neg_from_s: Mmut::R,
|
||||||
@@ -1202,7 +1204,7 @@ pub(crate) fn rlwe_ksk_gen<
|
|||||||
let d = gadget_vector.len();
|
let d = gadget_vector.len();
|
||||||
assert!(ksk_out.dimension() == (d, ring_size));
|
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());
|
ntt_op.forward(to_s.as_mut());
|
||||||
|
|
||||||
@@ -1210,7 +1212,7 @@ pub(crate) fn rlwe_ksk_gen<
|
|||||||
let mut part_a = {
|
let mut part_a = {
|
||||||
let mut a = Mmut::zeros(d, ring_size);
|
let mut a = Mmut::zeros(d, ring_size);
|
||||||
a.iter_rows_mut()
|
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
|
a
|
||||||
};
|
};
|
||||||
izip!(
|
izip!(
|
||||||
@@ -1225,7 +1227,7 @@ pub(crate) fn rlwe_ksk_gen<
|
|||||||
ntt_op.backward(ai.as_mut());
|
ntt_op.backward(ai.as_mut());
|
||||||
|
|
||||||
// ei + to_s*ai
|
// 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());
|
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
|
||||||
|
|
||||||
// beta_i * -from_s
|
// beta_i * -from_s
|
||||||
@@ -1239,11 +1241,13 @@ pub(crate) fn rlwe_ksk_gen<
|
|||||||
|
|
||||||
pub(crate) fn galois_key_gen<
|
pub(crate) fn galois_key_gen<
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
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>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
S,
|
S,
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
R: RandomFillGaussianInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
PR: RandomFillUniformInModulus<[Mmut::MatElement], ModOp::M>,
|
||||||
>(
|
>(
|
||||||
ksk_out: &mut Mmut,
|
ksk_out: &mut Mmut,
|
||||||
s: &[S],
|
s: &[S],
|
||||||
@@ -1255,23 +1259,23 @@ pub(crate) fn galois_key_gen<
|
|||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
<Mmut as Matrix>::R: RowMut,
|
<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>,
|
Mmut::MatElement: Copy + Sub<Output = Mmut::MatElement>,
|
||||||
{
|
{
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
let (auto_map_index, auto_map_sign) = generate_auto_map(ring_size, auto_k);
|
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)
|
// 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());
|
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(
|
izip!(s.as_ref(), auto_map_index.iter(), auto_map_sign.iter()).for_each(
|
||||||
|(el, to_index, sign)| {
|
|(el, to_index, sign)| {
|
||||||
// if sign is +ve (true), then negate because we need -s(X) (i.e. do the
|
// if sign is +ve (true), then negate because we need -s(X) (i.e. do the
|
||||||
// opposite than the usual case)
|
// opposite than the usual case)
|
||||||
if *sign {
|
if *sign {
|
||||||
neg_s_auto.as_mut()[*to_index] = q - *el;
|
neg_s_auto.as_mut()[*to_index] = mod_op.neg(el);
|
||||||
} else {
|
} else {
|
||||||
neg_s_auto.as_mut()[*to_index] = *el;
|
neg_s_auto.as_mut()[*to_index] = *el;
|
||||||
}
|
}
|
||||||
@@ -1298,11 +1302,11 @@ pub(crate) fn galois_key_gen<
|
|||||||
/// second rows consting polynomial `b`
|
/// second rows consting polynomial `b`
|
||||||
pub(crate) fn secret_key_encrypt_rlwe<
|
pub(crate) fn secret_key_encrypt_rlwe<
|
||||||
Ro: Row + RowMut + RowEntity,
|
Ro: Row + RowMut + RowEntity,
|
||||||
ModOp: VectorOps<Element = Ro::Element>,
|
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
|
||||||
NttOp: Ntt<Element = Ro::Element>,
|
NttOp: Ntt<Element = Ro::Element>,
|
||||||
S,
|
S,
|
||||||
R: RandomGaussianDist<[Ro::Element], Parameters = Ro::Element>,
|
R: RandomFillGaussianInModulus<[Ro::Element], ModOp::M>,
|
||||||
PR: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
|
PR: RandomFillUniformInModulus<[Ro::Element], ModOp::M>,
|
||||||
>(
|
>(
|
||||||
m: &[Ro::Element],
|
m: &[Ro::Element],
|
||||||
b_rlwe_out: &mut Ro,
|
b_rlwe_out: &mut Ro,
|
||||||
@@ -1312,7 +1316,7 @@ pub(crate) fn secret_key_encrypt_rlwe<
|
|||||||
p_rng: &mut PR,
|
p_rng: &mut PR,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element> + Debug,
|
Ro: TryConvertFrom1<[S], ModOp::M> + Debug,
|
||||||
{
|
{
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
assert!(m.as_ref().len() == ring_size);
|
assert!(m.as_ref().len() == ring_size);
|
||||||
@@ -1323,19 +1327,19 @@ pub(crate) fn secret_key_encrypt_rlwe<
|
|||||||
// sample a
|
// sample a
|
||||||
let mut a = {
|
let mut a = {
|
||||||
let mut a = Ro::zeros(ring_size);
|
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
|
a
|
||||||
};
|
};
|
||||||
|
|
||||||
// s * 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(sa.as_mut());
|
||||||
ntt_op.forward(a.as_mut());
|
ntt_op.forward(a.as_mut());
|
||||||
mod_op.elwise_mul_mut(sa.as_mut(), a.as_ref());
|
mod_op.elwise_mul_mut(sa.as_mut(), a.as_ref());
|
||||||
ntt_op.backward(sa.as_mut());
|
ntt_op.backward(sa.as_mut());
|
||||||
|
|
||||||
// sample e
|
// 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(), m.as_ref());
|
||||||
mod_op.elwise_add_mut(b_rlwe_out.as_mut(), sa.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<
|
pub(crate) fn public_key_encrypt_rlwe<
|
||||||
M: Matrix,
|
M: Matrix,
|
||||||
Mmut: MatrixMut<MatElement = M::MatElement>,
|
Mmut: MatrixMut<MatElement = M::MatElement>,
|
||||||
ModOp: VectorOps<Element = M::MatElement>,
|
ModOp: VectorOps<Element = M::MatElement> + GetModulus<Element = M::MatElement>,
|
||||||
NttOp: Ntt<Element = M::MatElement>,
|
NttOp: Ntt<Element = M::MatElement>,
|
||||||
S,
|
S,
|
||||||
R: RandomGaussianDist<[M::MatElement], Parameters = M::MatElement>
|
R: RandomFillGaussianInModulus<[M::MatElement], ModOp::M>
|
||||||
+ RandomUniformDist<[M::MatElement], Parameters = M::MatElement>
|
+ RandomFillUniformInModulus<[M::MatElement], ModOp::M>
|
||||||
+ RandomUniformDist<[u8], Parameters = u8>
|
+ RandomFill<[u8]>
|
||||||
+ RandomUniformDist<usize, Parameters = usize>,
|
+ RandomElementInModulus<usize, usize>,
|
||||||
>(
|
>(
|
||||||
rlwe_out: &mut Mmut,
|
rlwe_out: &mut Mmut,
|
||||||
pk: &M,
|
pk: &M,
|
||||||
@@ -1358,7 +1362,7 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
ntt_op: &NttOp,
|
ntt_op: &NttOp,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) 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,
|
M::MatElement: Copy,
|
||||||
S: Zero + Signed + Copy,
|
S: Zero + Signed + Copy,
|
||||||
{
|
{
|
||||||
@@ -1369,7 +1373,7 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
|
|
||||||
let mut u = vec![S::zero(); ring_size];
|
let mut u = vec![S::zero(); ring_size];
|
||||||
fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
|
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());
|
ntt_op.forward(u.as_mut());
|
||||||
|
|
||||||
let mut ua = Mmut::R::zeros(ring_size);
|
let mut ua = Mmut::R::zeros(ring_size);
|
||||||
@@ -1389,7 +1393,7 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
|
|
||||||
// sample error
|
// sample error
|
||||||
rlwe_out.iter_rows_mut().for_each(|ri| {
|
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
|
// a*u + e0
|
||||||
@@ -1405,10 +1409,10 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
pub(crate) fn gen_rlwe_public_key<
|
pub(crate) fn gen_rlwe_public_key<
|
||||||
Ro: RowMut + RowEntity,
|
Ro: RowMut + RowEntity,
|
||||||
S,
|
S,
|
||||||
ModOp: VectorOps<Element = Ro::Element>,
|
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
|
||||||
NttOp: Ntt<Element = Ro::Element>,
|
NttOp: Ntt<Element = Ro::Element>,
|
||||||
PRng: RandomUniformDist<[Ro::Element], Parameters = Ro::Element>,
|
PRng: RandomFillUniformInModulus<[Ro::Element], ModOp::M>,
|
||||||
Rng: RandomGaussianDist<[Ro::Element], Parameters = Ro::Element>,
|
Rng: RandomFillGaussianInModulus<[Ro::Element], ModOp::M>,
|
||||||
>(
|
>(
|
||||||
part_b_out: &mut Ro,
|
part_b_out: &mut Ro,
|
||||||
s: &[S],
|
s: &[S],
|
||||||
@@ -1417,7 +1421,7 @@ pub(crate) fn gen_rlwe_public_key<
|
|||||||
p_rng: &mut PRng,
|
p_rng: &mut PRng,
|
||||||
rng: &mut Rng,
|
rng: &mut Rng,
|
||||||
) where
|
) where
|
||||||
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
|
Ro: TryConvertFrom1<[S], ModOp::M>,
|
||||||
{
|
{
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
assert!(part_b_out.as_ref().len() == ring_size);
|
assert!(part_b_out.as_ref().len() == ring_size);
|
||||||
@@ -1427,7 +1431,7 @@ pub(crate) fn gen_rlwe_public_key<
|
|||||||
// sample a
|
// sample a
|
||||||
let mut a = {
|
let mut a = {
|
||||||
let mut tmp = Ro::zeros(ring_size);
|
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
|
tmp
|
||||||
};
|
};
|
||||||
ntt_op.forward(a.as_mut());
|
ntt_op.forward(a.as_mut());
|
||||||
@@ -1439,7 +1443,7 @@ pub(crate) fn gen_rlwe_public_key<
|
|||||||
ntt_op.backward(sa.as_mut());
|
ntt_op.backward(sa.as_mut());
|
||||||
|
|
||||||
// s*a + e
|
// 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());
|
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<
|
pub(crate) fn decrypt_rlwe<
|
||||||
R: RowMut,
|
R: RowMut,
|
||||||
M: Matrix<MatElement = R::Element>,
|
M: Matrix<MatElement = R::Element>,
|
||||||
ModOp: VectorOps<Element = R::Element>,
|
ModOp: VectorOps<Element = R::Element> + GetModulus<Element = R::Element>,
|
||||||
NttOp: Ntt<Element = R::Element>,
|
NttOp: Ntt<Element = R::Element>,
|
||||||
S,
|
S,
|
||||||
>(
|
>(
|
||||||
@@ -1459,7 +1463,7 @@ pub(crate) fn decrypt_rlwe<
|
|||||||
ntt_op: &NttOp,
|
ntt_op: &NttOp,
|
||||||
mod_op: &ModOp,
|
mod_op: &ModOp,
|
||||||
) where
|
) where
|
||||||
R: TryConvertFrom<[S], Parameters = R::Element>,
|
R: TryConvertFrom1<[S], ModOp::M>,
|
||||||
R::Element: Copy,
|
R::Element: Copy,
|
||||||
{
|
{
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
@@ -1471,7 +1475,7 @@ pub(crate) fn decrypt_rlwe<
|
|||||||
ntt_op.forward(m_out.as_mut());
|
ntt_op.forward(m_out.as_mut());
|
||||||
|
|
||||||
// -s*a
|
// -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());
|
ntt_op.forward(s.as_mut());
|
||||||
mod_op.elwise_mul_mut(m_out.as_mut(), s.as_ref());
|
mod_op.elwise_mul_mut(m_out.as_mut(), s.as_ref());
|
||||||
mod_op.elwise_neg_mut(m_out.as_mut());
|
mod_op.elwise_neg_mut(m_out.as_mut());
|
||||||
@@ -1485,7 +1489,7 @@ pub(crate) fn decrypt_rlwe<
|
|||||||
// encoded_m
|
// encoded_m
|
||||||
pub(crate) fn measure_noise<
|
pub(crate) fn measure_noise<
|
||||||
Mmut: MatrixMut + Matrix,
|
Mmut: MatrixMut + Matrix,
|
||||||
ModOp: VectorOps<Element = Mmut::MatElement>,
|
ModOp: VectorOps<Element = Mmut::MatElement> + GetModulus<Element = Mmut::MatElement>,
|
||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
S,
|
S,
|
||||||
>(
|
>(
|
||||||
@@ -1497,7 +1501,7 @@ pub(crate) fn measure_noise<
|
|||||||
) -> f64
|
) -> f64
|
||||||
where
|
where
|
||||||
<Mmut as Matrix>::R: RowMut,
|
<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,
|
Mmut::MatElement: PrimInt + ToPrimitive + Debug,
|
||||||
{
|
{
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
@@ -1505,7 +1509,7 @@ where
|
|||||||
assert!(encoded_m_ideal.as_ref().len() == ring_size);
|
assert!(encoded_m_ideal.as_ref().len() == ring_size);
|
||||||
|
|
||||||
// -(s * a)
|
// -(s * a)
|
||||||
let q = VectorOps::modulus(mod_op);
|
let q = mod_op.modulus();
|
||||||
let mut s = Mmut::R::try_convert_from(s, &q);
|
let mut s = Mmut::R::try_convert_from(s, &q);
|
||||||
ntt_op.forward(s.as_mut());
|
ntt_op.forward(s.as_mut());
|
||||||
let mut a = Mmut::R::zeros(ring_size);
|
let mut a = Mmut::R::zeros(ring_size);
|
||||||
@@ -1524,13 +1528,7 @@ where
|
|||||||
|
|
||||||
let mut max_diff_bits = f64::MIN;
|
let mut max_diff_bits = f64::MIN;
|
||||||
m_plus_e.as_ref().iter().for_each(|v| {
|
m_plus_e.as_ref().iter().for_each(|v| {
|
||||||
let mut v = *v;
|
let bits = (q.to_i64(v).to_f64().unwrap()).log2();
|
||||||
if v >= (q >> 1) {
|
|
||||||
// v is -ve
|
|
||||||
v = q - v;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bits = (v.to_f64().unwrap()).log2();
|
|
||||||
|
|
||||||
if max_diff_bits < bits {
|
if max_diff_bits < bits {
|
||||||
max_diff_bits = bits;
|
max_diff_bits = bits;
|
||||||
@@ -1548,16 +1546,16 @@ pub(crate) mod tests {
|
|||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ModInit, ModularOpsU64, VectorOps},
|
backend::{GetModulus, ModInit, ModularOpsU64, Modulus, VectorOps},
|
||||||
decomposer::{Decomposer, DefaultDecomposer, RlweDecomposer},
|
decomposer::{Decomposer, DefaultDecomposer, RlweDecomposer},
|
||||||
ntt::{self, Ntt, NttBackendU64, NttInit},
|
ntt::{self, Ntt, NttBackendU64, NttInit},
|
||||||
random::{DefaultSecureRng, NewWithSeed, RandomUniformDist},
|
random::{DefaultSecureRng, NewWithSeed, RandomFillUniformInModulus},
|
||||||
rgsw::{
|
rgsw::{
|
||||||
gen_rlwe_public_key, measure_noise, public_key_encrypt_rgsw, AutoKeyEvaluationDomain,
|
gen_rlwe_public_key, measure_noise, public_key_encrypt_rgsw, AutoKeyEvaluationDomain,
|
||||||
RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, RlwePublicKey,
|
RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, RlwePublicKey,
|
||||||
SeededAutoKey, SeededRgswCiphertext, SeededRlweCiphertext, SeededRlwePublicKey,
|
SeededAutoKey, SeededRgswCiphertext, SeededRlweCiphertext, SeededRlwePublicKey,
|
||||||
},
|
},
|
||||||
utils::{generate_prime, negacyclic_mul, Stats, TryConvertFrom},
|
utils::{generate_prime, negacyclic_mul, Stats, TryConvertFrom1},
|
||||||
Matrix, Secret,
|
Matrix, Secret,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1567,11 +1565,11 @@ pub(crate) mod tests {
|
|||||||
RlweSecret,
|
RlweSecret,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn _sk_encrypt_rlwe(
|
pub(crate) fn _sk_encrypt_rlwe<T: Modulus<Element = u64> + Clone>(
|
||||||
m: &[u64],
|
m: &[u64],
|
||||||
s: &[i32],
|
s: &[i32],
|
||||||
ntt_op: &NttBackendU64,
|
ntt_op: &NttBackendU64,
|
||||||
mod_op: &ModularOpsU64,
|
mod_op: &ModularOpsU64<T>,
|
||||||
) -> RlweCiphertext<Vec<Vec<u64>>, DefaultSecureRng> {
|
) -> RlweCiphertext<Vec<Vec<u64>>, DefaultSecureRng> {
|
||||||
let ring_size = m.len();
|
let ring_size = m.len();
|
||||||
let q = mod_op.modulus();
|
let q = mod_op.modulus();
|
||||||
@@ -1581,7 +1579,7 @@ pub(crate) mod tests {
|
|||||||
let mut rlwe_seed = [0u8; 32];
|
let mut rlwe_seed = [0u8; 32];
|
||||||
rng.fill_bytes(&mut rlwe_seed);
|
rng.fill_bytes(&mut rlwe_seed);
|
||||||
let mut seeded_rlwe_ct =
|
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);
|
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed);
|
||||||
secret_key_encrypt_rlwe(
|
secret_key_encrypt_rlwe(
|
||||||
&m,
|
&m,
|
||||||
@@ -1597,13 +1595,13 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt m as RGSW ciphertext RGSW(m) using supplied public key
|
// 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],
|
m: &[u64],
|
||||||
public_key: &RlwePublicKey<Vec<Vec<u64>>, DefaultSecureRng>,
|
public_key: &RlwePublicKey<Vec<Vec<u64>>, DefaultSecureRng>,
|
||||||
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
||||||
mod_op: &ModularOpsU64,
|
mod_op: &ModularOpsU64<T>,
|
||||||
ntt_op: &NttBackendU64,
|
ntt_op: &NttBackendU64,
|
||||||
) -> RgswCiphertext<Vec<Vec<u64>>> {
|
) -> RgswCiphertext<Vec<Vec<u64>>, T> {
|
||||||
let (_, ring_size) = Matrix::dimension(&public_key.data);
|
let (_, ring_size) = Matrix::dimension(&public_key.data);
|
||||||
let gadget_vector_a = decomposer.a().gadget_vector();
|
let gadget_vector_a = decomposer.a().gadget_vector();
|
||||||
let gadget_vector_b = decomposer.b().gadget_vector();
|
let gadget_vector_b = decomposer.b().gadget_vector();
|
||||||
@@ -1613,7 +1611,7 @@ pub(crate) mod tests {
|
|||||||
assert!(m.len() == ring_size);
|
assert!(m.len() == ring_size);
|
||||||
|
|
||||||
// public key encrypt RGSW(m1)
|
// 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(
|
public_key_encrypt_rgsw(
|
||||||
&mut rgsw_ct.data,
|
&mut rgsw_ct.data,
|
||||||
m,
|
m,
|
||||||
@@ -1630,13 +1628,13 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
/// Encrypts m as RGSW ciphertext RGSW(m) using supplied secret key. Returns
|
/// Encrypts m as RGSW ciphertext RGSW(m) using supplied secret key. Returns
|
||||||
/// unseeded RGSW ciphertext in coefficient domain
|
/// 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],
|
m: &[u64],
|
||||||
s: &[i32],
|
s: &[i32],
|
||||||
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
||||||
mod_op: &ModularOpsU64,
|
mod_op: &ModularOpsU64<T>,
|
||||||
ntt_op: &NttBackendU64,
|
ntt_op: &NttBackendU64,
|
||||||
) -> SeededRgswCiphertext<Vec<Vec<u64>>, [u8; 32]> {
|
) -> SeededRgswCiphertext<Vec<Vec<u64>>, [u8; 32], T> {
|
||||||
let ring_size = s.len();
|
let ring_size = s.len();
|
||||||
assert!(m.len() == s.len());
|
assert!(m.len() == s.len());
|
||||||
|
|
||||||
@@ -1648,11 +1646,11 @@ pub(crate) mod tests {
|
|||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
let mut rgsw_seed = [0u8; 32];
|
let mut rgsw_seed = [0u8; 32];
|
||||||
rng.fill_bytes(&mut rgsw_seed);
|
rng.fill_bytes(&mut rgsw_seed);
|
||||||
let mut seeded_rgsw_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,
|
ring_size as usize,
|
||||||
decomposer,
|
decomposer,
|
||||||
rgsw_seed,
|
rgsw_seed,
|
||||||
q,
|
q.clone(),
|
||||||
);
|
);
|
||||||
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
|
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
|
||||||
secret_key_encrypt_rgsw(
|
secret_key_encrypt_rgsw(
|
||||||
@@ -1672,12 +1670,12 @@ pub(crate) mod tests {
|
|||||||
/// Prints noise in RGSW ciphertext RGSW(m).
|
/// Prints noise in RGSW ciphertext RGSW(m).
|
||||||
///
|
///
|
||||||
/// - rgsw_ct: RGSW ciphertext in coefficient domain
|
/// - 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>],
|
rgsw_ct: &[Vec<u64>],
|
||||||
m: &[u64],
|
m: &[u64],
|
||||||
s: &[i32],
|
s: &[i32],
|
||||||
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
decomposer: &(DefaultDecomposer<u64>, DefaultDecomposer<u64>),
|
||||||
q: u64,
|
q: &T,
|
||||||
) {
|
) {
|
||||||
let gadget_vector_a = decomposer.a().gadget_vector();
|
let gadget_vector_a = decomposer.a().gadget_vector();
|
||||||
let gadget_vector_b = decomposer.b().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!(Matrix::dimension(&rgsw_ct) == (d_a * 2 + d_b * 2, ring_size));
|
||||||
assert!(m.len() == 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 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 mul_mod =
|
||||||
let s_poly = Vec::<u64>::try_convert_from(s, &q);
|
|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();
|
let mut neg_s = s_poly.clone();
|
||||||
mod_op.elwise_neg_mut(neg_s.as_mut());
|
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)
|
// RLWE(\beta^j -s * m)
|
||||||
for j in 0..d_a {
|
for j in 0..d_a {
|
||||||
@@ -1745,9 +1744,9 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
// sample m0
|
// sample m0
|
||||||
let mut m0 = vec![0u64; 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], 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);
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
|
||||||
// encrypt m0
|
// encrypt m0
|
||||||
@@ -1788,11 +1787,11 @@ pub(crate) mod tests {
|
|||||||
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
let mut m0 = vec![0u64; 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];
|
let mut m1 = vec![0u64; ring_size as usize];
|
||||||
m1[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
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 mod_op = ModularOpsU64::new(q);
|
||||||
let d_rgsw = 10;
|
let d_rgsw = 10;
|
||||||
let logb = 5;
|
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 s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
let mut m = vec![0u64; 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
|
let encoded_m = m
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| (((*v as f64 * q as f64) / (p as f64)).round() as u64))
|
.map(|v| (((*v as f64 * q as f64) / (p as f64)).round() as u64))
|
||||||
.collect_vec();
|
.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);
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
|
||||||
// RLWE_{s}(m)
|
// 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 s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
let mut rng = DefaultSecureRng::new();
|
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 mod_op = ModularOpsU64::new(q);
|
||||||
let decomposer = (
|
let decomposer = (
|
||||||
DefaultDecomposer::new(q, logb, d_rgsw),
|
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 {
|
for i in 0..2 {
|
||||||
let mut m = vec![0u64; ring_size as usize];
|
let mut m = vec![0u64; ring_size as usize];
|
||||||
@@ -2085,12 +2084,12 @@ pub(crate) mod tests {
|
|||||||
// measure noise
|
// measure noise
|
||||||
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
||||||
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
|
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)
|
// RLWE(m) x RGSW(carry_m)
|
||||||
let mut m = vec![0u64; ring_size as usize];
|
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);
|
let mut rlwe_ct = _sk_encrypt_rlwe(&m, s.values(), &ntt_op, &mod_op);
|
||||||
|
|
||||||
// send rgsw to evaluation domain
|
// send rgsw to evaluation domain
|
||||||
@@ -2124,7 +2123,7 @@ pub(crate) mod tests {
|
|||||||
DefaultDecomposer::new(q, logb, d_rgsw),
|
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 mod_op = ModularOpsU64::new(q);
|
||||||
let mut rng = DefaultSecureRng::new_seeded([0u8; 32]);
|
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)
|
// Sample m2, encrypt it as RLWE(m2) and multiply RLWE(m2)xRGSW(m0m1)
|
||||||
let mut m2 = vec![0u64; ring_size as usize];
|
let mut m2 = vec![0u64; ring_size as usize];
|
||||||
RandomUniformDist::random_fill(&mut rng, &q, m2.as_mut_slice());
|
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 rlwe_in_ct = { _sk_encrypt_rlwe(&m2, s.values(), &ntt_op, &mod_op) };
|
||||||
let mut scratch_space = vec![
|
let mut scratch_space = vec![
|
||||||
vec![0u64; ring_size as usize];
|
vec![0u64; ring_size as usize];
|
||||||
|
|||||||
193
src/utils.rs
193
src/utils.rs
@@ -1,9 +1,12 @@
|
|||||||
use std::{fmt::Debug, usize};
|
use std::{fmt::Debug, usize};
|
||||||
|
|
||||||
use itertools::Itertools;
|
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 {
|
pub trait WithLocal {
|
||||||
fn with_local<F, R>(func: F) -> R
|
fn with_local<F, R>(func: F) -> R
|
||||||
where
|
where
|
||||||
@@ -16,22 +19,21 @@ pub trait WithLocal {
|
|||||||
|
|
||||||
pub fn fill_random_ternary_secret_with_hamming_weight<
|
pub fn fill_random_ternary_secret_with_hamming_weight<
|
||||||
T: Signed,
|
T: Signed,
|
||||||
R: RandomUniformDist<[u8], Parameters = u8> + RandomUniformDist<usize, Parameters = usize>,
|
R: RandomFill<[u8]> + RandomElementInModulus<usize, usize>,
|
||||||
>(
|
>(
|
||||||
out: &mut [T],
|
out: &mut [T],
|
||||||
hamming_weight: usize,
|
hamming_weight: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) {
|
) {
|
||||||
let mut bytes = vec![0u8; hamming_weight.div_ceil(8)];
|
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 size = out.len();
|
||||||
let mut secret_indices = (0..size).into_iter().map(|i| i).collect_vec();
|
let mut secret_indices = (0..size).into_iter().map(|i| i).collect_vec();
|
||||||
let mut bit_index = 0;
|
let mut bit_index = 0;
|
||||||
let mut byte_index = 0;
|
let mut byte_index = 0;
|
||||||
for _ in 0..hamming_weight {
|
for _ in 0..hamming_weight {
|
||||||
let mut s_index = 0usize;
|
let s_index = RandomElementInModulus::<usize, usize>::random(rng, &secret_indices.len());
|
||||||
RandomUniformDist::<usize>::random_fill(rng, &secret_indices.len(), &mut s_index);
|
|
||||||
|
|
||||||
let curr_bit = (bytes[byte_index] >> bit_index) & 1;
|
let curr_bit = (bytes[byte_index] >> bit_index) & 1;
|
||||||
if curr_bit == 1 {
|
if curr_bit == 1 {
|
||||||
@@ -138,97 +140,122 @@ pub fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TryConvertFrom<T: ?Sized> {
|
pub trait TryConvertFrom1<T: ?Sized, P> {
|
||||||
type Parameters: ?Sized;
|
fn try_convert_from(value: &T, parameters: &P) -> Self;
|
||||||
|
|
||||||
fn try_convert_from(value: &T, parameters: &Self::Parameters) -> Self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryConvertFrom<[i32]> for Vec<Vec<u32>> {
|
impl<P: Modulus<Element = u64>> TryConvertFrom1<[i64], P> for Vec<u64> {
|
||||||
type Parameters = u32;
|
fn try_convert_from(value: &[i64], parameters: &P) -> Self {
|
||||||
fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self {
|
value.iter().map(|v| parameters.from_i64(*v)).collect_vec()
|
||||||
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>> {
|
impl<P: Modulus<Element = u64>> TryConvertFrom1<[i32], P> for Vec<u64> {
|
||||||
type Parameters = u64;
|
fn try_convert_from(value: &[i32], parameters: &P) -> Self {
|
||||||
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 {
|
|
||||||
value
|
value
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| {
|
.map(|v| parameters.from_i64(*v as i64))
|
||||||
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()
|
.collect_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryConvertFrom<[u64]> for Vec<i64> {
|
impl<P: Modulus> TryConvertFrom1<[P::Element], P> for Vec<i64> {
|
||||||
type Parameters = u64;
|
fn try_convert_from(value: &[P::Element], parameters: &P) -> Self {
|
||||||
fn try_convert_from(value: &[u64], parameters: &Self::Parameters) -> Self {
|
value.iter().map(|v| parameters.to_i64(v)).collect_vec()
|
||||||
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 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) struct Stats<T> {
|
||||||
pub(crate) samples: Vec<T>,
|
pub(crate) samples: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user