Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions tfhe/src/core_crypto/algorithms/glwe_secret_key_generation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Module containing primitives pertaining to the generation of
//! [`GLWE secret keys`](`GlweSecretKey`).

use std::ops::RangeInclusive;

use crate::core_crypto::commons::generators::SecretRandomGenerator;
use crate::core_crypto::commons::math::random::{RandomGenerable, UniformBinary};
use crate::core_crypto::commons::parameters::*;
Expand Down Expand Up @@ -67,3 +69,77 @@ pub fn generate_binary_glwe_secret_key<Scalar, InCont, Gen>(
{
generator.fill_slice_with_random_uniform_binary(glwe_secret_key.as_mut());
}

/// Fill a [`GLWE secret key`](`GlweSecretKey`) with uniformly random binary coefficients.
///
/// The hamming weight of the secret key will be in: `(1-pmax)*len..=pmax*len`
/// where pmax is in ]0.5, 1.0]
///
/// # Panics
///
/// Panics if pmax <= 0.5 or pmax > 1.0
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for GlweSecretKey creation
/// let glwe_size = GlweSize(2);
/// let polynomial_size = PolynomialSize(1024);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut secret_generator = SecretRandomGenerator::<DefaultRandomGenerator>::new(seeder.seed());
/// let pmax = 0.7;
///
/// let mut glwe_secret_key =
/// GlweSecretKey::new_empty_key(0u64, glwe_size.to_glwe_dimension(), polynomial_size);
///
/// generate_binary_glwe_secret_key_with_bounded_hamming_weight(
/// &mut glwe_secret_key,
/// &mut secret_generator,
/// pmax,
/// );
///
/// // Check all coefficients are not zero as we just generated a new key
/// assert!(!glwe_secret_key.as_ref().iter().all(|&elt| elt == 0));
/// ```
pub fn generate_binary_glwe_secret_key_with_bounded_hamming_weight<Scalar, InCont, Gen>(
glwe_secret_key: &mut GlweSecretKey<InCont>,
generator: &mut SecretRandomGenerator<Gen>,
pmax: f64,
) where
Scalar: UnsignedInteger + RandomGenerable<UniformBinary>,
InCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
0.5 < pmax && pmax <= 1.0,
"pmax parameter must be in ]0.5, 1.0]"
);

let bounds = RangeInclusive::new(
((1.0 - pmax) * glwe_secret_key.polynomial_size().0 as f64) as u128,
(pmax * glwe_secret_key.polynomial_size().0 as f64) as u128,
);

for mut secret_poly in glwe_secret_key.as_mut_polynomial_list().iter_mut() {
loop {
generator.fill_slice_with_random_uniform_binary_bits(secret_poly.as_mut());
let hamming_weight = secret_poly
.as_ref()
.iter()
.copied()
.map(|bit| -> u128 { bit.cast_into() })
.sum::<u128>();

if bounds.contains(&hamming_weight) {
break;
}
}
}
}
71 changes: 71 additions & 0 deletions tfhe/src/core_crypto/algorithms/lwe_secret_key_generation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Module containing primitives pertaining to the generation of
//! [`LWE secret keys`](`LweSecretKey`).

use std::ops::RangeInclusive;

use crate::core_crypto::commons::generators::SecretRandomGenerator;
use crate::core_crypto::commons::math::random::{RandomGenerable, UniformBinary};
use crate::core_crypto::commons::parameters::*;
Expand Down Expand Up @@ -62,3 +64,72 @@ pub fn generate_binary_lwe_secret_key<Scalar, InCont, Gen>(
{
generator.fill_slice_with_random_uniform_binary(lwe_secret_key.as_mut());
}

/// Fill an [`LWE secret key`](`LweSecretKey`) with uniformly random binary coefficients.
///
/// The hamming weight of the secret key will be in: `(1-pmax)*len..=pmax*len`
/// where pmax is in ]0.5, 1.0]
///
/// # Panics
///
/// Panics if pmax <= 0.5 or pmax > 1.0
///
/// # Example
///
/// ```rust
/// use tfhe::core_crypto::prelude::*;
///
/// // DISCLAIMER: these toy example parameters are not guaranteed to be secure or yield correct
/// // computations
/// // Define parameters for LweCiphertext creation
/// let lwe_dimension = LweDimension(742);
///
/// // Create the PRNG
/// let mut seeder = new_seeder();
/// let seeder = seeder.as_mut();
/// let mut secret_generator = SecretRandomGenerator::<DefaultRandomGenerator>::new(seeder.seed());
/// let pmax = 0.7;
/// let mut lwe_secret_key = LweSecretKey::new_empty_key(0u64, lwe_dimension);
///
/// generate_binary_lwe_secret_key_with_bounded_hamming_weight(
/// &mut lwe_secret_key,
/// &mut secret_generator,
/// pmax,
/// );
///
/// // Check all coefficients are not zero as we just generated a new key
/// assert!(!lwe_secret_key.as_ref().iter().all(|&elt| elt == 0));
/// ```
pub fn generate_binary_lwe_secret_key_with_bounded_hamming_weight<Scalar, InCont, Gen>(
lwe_secret_key: &mut LweSecretKey<InCont>,
generator: &mut SecretRandomGenerator<Gen>,
pmax: f64,
) where
Scalar: RandomGenerable<UniformBinary> + UnsignedInteger,
InCont: ContainerMut<Element = Scalar>,
Gen: ByteRandomGenerator,
{
assert!(
0.5 < pmax && pmax <= 1.0,
"pmax parameter must be in ]0.5, 1.0]"
);

let bounds = RangeInclusive::new(
((1.0 - pmax) * lwe_secret_key.lwe_dimension().0 as f64) as u128,
(pmax * lwe_secret_key.lwe_dimension().0 as f64) as u128,
);

loop {
generator.fill_slice_with_random_uniform_binary_bits(lwe_secret_key.as_mut());
let hamming_weight = lwe_secret_key
.as_ref()
.iter()
.copied()
.map(|bit| -> u128 { bit.cast_into() })
.sum::<u128>();

if bounds.contains(&hamming_weight) {
break;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl<G: ByteRandomGenerator> EncryptionRandomGenerator<G> {
}
}

#[cfg(all(feature = "integer", test))]
#[cfg(feature = "integer")]
pub(crate) fn from_raw_parts(
mask: MaskRandomGenerator<G>,
noise: NoiseRandomGenerator<G>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ impl<G: ByteRandomGenerator> NoiseRandomGenerator<G> {
}
}

pub fn from_raw_parts(gen: RandomGenerator<G>) -> Self {
Self { gen }
}

/// Create a new [`NoiseRandomGenerator`], using the provided seed
pub fn new_from_seed(seed: impl Into<SeedKind>) -> Self {
Self {
Expand Down
22 changes: 20 additions & 2 deletions tfhe/src/core_crypto/commons/generators/secret.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
//! Module containing primitives pertaining to random generation in the context of secret key
//! generation.

use tfhe_csprng::seeders::SeedKind;

use crate::core_crypto::commons::math::random::{
ByteRandomGenerator, RandomGenerable, RandomGenerator, Seed, UniformBinary,
ByteRandomGenerator, RandomGenerable, RandomGenerator, UniformBinary,
};
use crate::core_crypto::prelude::UnsignedInteger;

/// A random number generator which can be used to generate secret keys.
pub struct SecretRandomGenerator<G: ByteRandomGenerator>(RandomGenerator<G>);

impl<G: ByteRandomGenerator> SecretRandomGenerator<G> {
/// Create a new generator, optionally seeding it with the given value.
pub fn new(seed: Seed) -> Self {
pub fn new(seed: impl Into<SeedKind>) -> Self {
Self(RandomGenerator::new(seed))
}

pub fn from_raw_parts(inner: RandomGenerator<G>) -> Self {
Self(inner)
}

pub fn into_raw_parts(self) -> RandomGenerator<G> {
self.0
}

/// Return the number of remaining bytes, if the generator is bounded.
pub fn remaining_bytes(&self) -> Option<usize> {
self.0.remaining_bytes()
Expand All @@ -32,4 +43,11 @@ impl<G: ByteRandomGenerator> SecretRandomGenerator<G> {
{
self.0.random_uniform_binary()
}

pub fn fill_slice_with_random_uniform_binary_bits<Scalar>(&mut self, output: &mut [Scalar])
where
Scalar: UnsignedInteger,
{
self.0.fill_slice_with_random_uniform_binary_bits(output);
}
}
6 changes: 6 additions & 0 deletions tfhe/src/core_crypto/entities/glwe_secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GlweSecretKey<C
let polynomial_size = self.polynomial_size;
GlweSecretKey::from_container(self.as_mut(), polynomial_size)
}

/// Interpret the [`GlweSecretKey`] as a [`PolynomialListMutView`].
pub fn as_mut_polynomial_list(&mut self) -> PolynomialListMutView<'_, C::Element> {
let poly_size = self.polynomial_size;
PolynomialListMutView::from_container(self.as_mut(), poly_size)
}
}

/// A [`GlweSecretKey`] owning the memory for its own storage.
Expand Down
Loading
Loading