Skip to content

Commit cdc25d6

Browse files
committed
chore(core): add more sanity checks on RNG
1 parent ab59514 commit cdc25d6

File tree

2 files changed

+201
-8
lines changed

2 files changed

+201
-8
lines changed

tfhe/src/core_crypto/commons/generators/encryption.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,4 +629,180 @@ mod test {
629629
fn noise_gen_native_u128() {
630630
noise_gen_native::<u128>();
631631
}
632+
633+
fn noise_gen_custom_mod<Scalar: UnsignedTorus>(ciphertext_modulus: CiphertextModulus<Scalar>) {
634+
let mut gen = new_encryption_random_generator();
635+
636+
let bits = (Scalar::BITS / 2) as i32;
637+
638+
for _ in 0..1000 {
639+
let val: Scalar =
640+
gen.random_noise_custom_mod(StandardDev(2.0f64.powi(-bits)), ciphertext_modulus);
641+
assert!(val != Scalar::ZERO);
642+
}
643+
}
644+
645+
#[test]
646+
fn noise_gen_custom_mod_u32() {
647+
noise_gen_custom_mod::<u32>(CiphertextModulus::try_new_power_of_2(31).unwrap());
648+
}
649+
650+
#[test]
651+
fn noise_gen_custom_mod_u64() {
652+
noise_gen_custom_mod::<u64>(CiphertextModulus::try_new_power_of_2(63).unwrap());
653+
}
654+
655+
#[test]
656+
fn noise_gen_custom_mod_u128() {
657+
noise_gen_custom_mod::<u128>(CiphertextModulus::try_new_power_of_2(127).unwrap());
658+
}
659+
660+
#[test]
661+
fn noise_gen_native_custom_mod_u32() {
662+
noise_gen_custom_mod::<u32>(CiphertextModulus::new_native());
663+
}
664+
665+
#[test]
666+
fn noise_gen_native_custom_mod_u64() {
667+
noise_gen_custom_mod::<u64>(CiphertextModulus::new_native());
668+
}
669+
670+
#[test]
671+
fn noise_gen_native_custom_mod_u128() {
672+
noise_gen_custom_mod::<u128>(CiphertextModulus::new_native());
673+
}
674+
675+
fn noise_gen_slice_native<Scalar: UnsignedTorus>() {
676+
let mut gen = new_encryption_random_generator();
677+
678+
let bits = (Scalar::BITS / 2) as i32;
679+
680+
let mut slice = vec![Scalar::ZERO; 1000];
681+
gen.fill_slice_with_random_noise(&mut slice, StandardDev(2.0f64.powi(-bits)));
682+
assert!(slice.iter().all(|&x| x != Scalar::ZERO))
683+
}
684+
685+
#[test]
686+
fn noise_gen_slice_native_u32() {
687+
noise_gen_slice_native::<u32>();
688+
}
689+
690+
#[test]
691+
fn noise_gen_slice_native_u64() {
692+
noise_gen_slice_native::<u64>();
693+
}
694+
695+
#[test]
696+
fn noise_gen_slice_native_u128() {
697+
noise_gen_slice_native::<u128>();
698+
}
699+
700+
fn noise_gen_slice_custom_mod<Scalar: UnsignedTorus>(
701+
ciphertext_modulus: CiphertextModulus<Scalar>,
702+
) {
703+
let mut gen = new_encryption_random_generator();
704+
705+
let bits = (Scalar::BITS / 2) as i32;
706+
707+
let mut slice = vec![Scalar::ZERO; 1000];
708+
gen.fill_slice_with_random_noise_custom_mod(
709+
&mut slice,
710+
StandardDev(2.0f64.powi(-bits)),
711+
ciphertext_modulus,
712+
);
713+
assert!(slice.iter().all(|&x| x != Scalar::ZERO))
714+
}
715+
716+
#[test]
717+
fn noise_gen_slice_custom_mod_u32() {
718+
noise_gen_slice_custom_mod::<u32>(CiphertextModulus::try_new_power_of_2(31).unwrap());
719+
}
720+
721+
#[test]
722+
fn noise_gen_slice_custom_mod_u64() {
723+
noise_gen_slice_custom_mod::<u64>(CiphertextModulus::try_new_power_of_2(63).unwrap());
724+
}
725+
726+
#[test]
727+
fn noise_gen_slice_custom_mod_u128() {
728+
noise_gen_slice_custom_mod::<u128>(CiphertextModulus::try_new_power_of_2(127).unwrap());
729+
}
730+
731+
#[test]
732+
fn noise_gen_slice_native_custom_mod_u32() {
733+
noise_gen_slice_custom_mod::<u32>(CiphertextModulus::new_native());
734+
}
735+
736+
#[test]
737+
fn noise_gen_slice_native_custom_mod_u64() {
738+
noise_gen_slice_custom_mod::<u64>(CiphertextModulus::new_native());
739+
}
740+
741+
#[test]
742+
fn noise_gen_slice_native_custom_mod_u128() {
743+
noise_gen_slice_custom_mod::<u128>(CiphertextModulus::new_native());
744+
}
745+
746+
fn mask_gen_slice_native<Scalar: UnsignedTorus>() {
747+
let mut gen = new_encryption_random_generator();
748+
749+
let mut slice = vec![Scalar::ZERO; 1000];
750+
gen.fill_slice_with_random_mask(&mut slice);
751+
assert!(slice.iter().all(|&x| x != Scalar::ZERO))
752+
}
753+
754+
#[test]
755+
fn mask_gen_native_u32() {
756+
mask_gen_slice_native::<u32>();
757+
}
758+
759+
#[test]
760+
fn mask_gen_native_u64() {
761+
mask_gen_slice_native::<u64>();
762+
}
763+
764+
#[test]
765+
fn mask_gen_native_u128() {
766+
mask_gen_slice_native::<u128>();
767+
}
768+
769+
fn mask_gen_slice_custom_mod<Scalar: UnsignedTorus>(
770+
ciphertext_modulus: CiphertextModulus<Scalar>,
771+
) {
772+
let mut gen = new_encryption_random_generator();
773+
774+
let mut slice = vec![Scalar::ZERO; 1000];
775+
gen.fill_slice_with_random_mask_custom_mod(&mut slice, ciphertext_modulus);
776+
assert!(slice.iter().all(|&x| x != Scalar::ZERO))
777+
}
778+
779+
#[test]
780+
fn mask_gen_slice_custom_mod_u32() {
781+
mask_gen_slice_custom_mod::<u32>(CiphertextModulus::try_new_power_of_2(31).unwrap());
782+
}
783+
784+
#[test]
785+
fn mask_gen_slice_custom_mod_u64() {
786+
mask_gen_slice_custom_mod::<u64>(CiphertextModulus::try_new_power_of_2(63).unwrap());
787+
}
788+
789+
#[test]
790+
fn mask_gen_slice_custom_mod_u128() {
791+
mask_gen_slice_custom_mod::<u128>(CiphertextModulus::try_new_power_of_2(127).unwrap());
792+
}
793+
794+
#[test]
795+
fn mask_gen_slice_native_custom_mod_u32() {
796+
mask_gen_slice_custom_mod::<u32>(CiphertextModulus::new_native());
797+
}
798+
799+
#[test]
800+
fn mask_gen_slice_native_custom_mod_u64() {
801+
mask_gen_slice_custom_mod::<u64>(CiphertextModulus::new_native());
802+
}
803+
804+
#[test]
805+
fn mask_gen_slice_native_custom_mod_u128() {
806+
mask_gen_slice_custom_mod::<u128>(CiphertextModulus::new_native());
807+
}
632808
}

tfhe/src/core_crypto/commons/math/random/generator.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,9 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
175175
/// use concrete_csprng::seeders::Seed;
176176
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
177177
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
178-
/// let mut vec = vec![1u32; 100];
178+
/// let mut vec = vec![0u32; 1000];
179179
/// generator.fill_slice_with_random_uniform(&mut vec);
180+
/// assert!(vec.iter().all(|&x| x != 0));
180181
/// ```
181182
pub fn fill_slice_with_random_uniform<Scalar>(&mut self, output: &mut [Scalar])
182183
where
@@ -196,11 +197,12 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
196197
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
197198
/// use tfhe::core_crypto::commons::parameters::CiphertextModulus;
198199
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
199-
/// let mut vec = vec![1u32; 100];
200+
/// let mut vec = vec![0u32; 1000];
200201
/// generator.fill_slice_with_random_uniform_custom_mod(
201202
/// &mut vec,
202203
/// CiphertextModulus::try_new_power_of_2(31).unwrap(),
203204
/// );
205+
/// assert!(vec.iter().all(|&x| x != 0));
204206
/// ```
205207
pub fn fill_slice_with_random_uniform_custom_mod<Scalar>(
206208
&mut self,
@@ -243,8 +245,9 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
243245
/// use concrete_csprng::seeders::Seed;
244246
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
245247
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
246-
/// let mut vec = vec![2u32; 100];
248+
/// let mut vec = vec![0u32; 1000];
247249
/// generator.fill_slice_with_random_uniform_binary(&mut vec);
250+
/// assert!(vec.iter().any(|&x| x != 0));
248251
/// ```
249252
pub fn fill_slice_with_random_uniform_binary<Scalar>(&mut self, output: &mut [Scalar])
250253
where
@@ -348,11 +351,15 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
348351
/// // check that both samples are in 6 sigmas.
349352
/// assert!(g1.abs() <= 6.);
350353
/// assert!(g2.abs() <= 6.);
354+
/// assert!(g1 != 0.);
355+
/// assert!(g2 != 0.);
351356
/// // for f64
352357
/// let (g1, g2): (f64, f64) = generator.random_gaussian(0. as f64, 1. as f64);
353358
/// // check that both samples are in 6 sigmas.
354359
/// assert!(g1.abs() <= 6.);
355360
/// assert!(g2.abs() <= 6.);
361+
/// assert!(g1 != 0.);
362+
/// assert!(g2 != 0.);
356363
/// ```
357364
pub fn random_gaussian<Float, Scalar>(&mut self, mean: Float, std: Float) -> (Scalar, Scalar)
358365
where
@@ -371,8 +378,9 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
371378
/// use concrete_csprng::seeders::Seed;
372379
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
373380
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
374-
/// let mut vec = vec![1000f32; 100];
381+
/// let mut vec = vec![0f32; 1000];
375382
/// generator.fill_slice_with_random_gaussian(&mut vec, 0., 1.);
383+
/// assert!(vec.iter().all(|&x| x != 0.));
376384
/// ```
377385
pub fn fill_slice_with_random_gaussian<Float, Scalar>(
378386
&mut self,
@@ -404,13 +412,14 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
404412
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
405413
/// use tfhe::core_crypto::commons::parameters::CiphertextModulus;
406414
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
407-
/// let mut vec = vec![1000u64; 100];
415+
/// let mut vec = vec![0u64; 1000];
408416
/// generator.fill_slice_with_random_gaussian_custom_mod(
409417
/// &mut vec,
410418
/// 0.,
411419
/// 1.,
412420
/// CiphertextModulus::try_new_power_of_2(63).unwrap(),
413421
/// );
422+
/// assert!(vec.iter().all(|&x| x != 0));
414423
/// ```
415424
pub fn fill_slice_with_random_gaussian_custom_mod<Float, Scalar>(
416425
&mut self,
@@ -453,8 +462,9 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
453462
/// use concrete_csprng::seeders::Seed;
454463
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
455464
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
456-
/// let mut vec = vec![1000u32; 100];
465+
/// let mut vec = vec![0u32; 1000];
457466
/// generator.unsigned_torus_slice_wrapping_add_random_gaussian_assign(&mut vec, 0., 1.);
467+
/// assert!(vec.iter().all(|&x| x != 0));
458468
/// ```
459469
pub fn unsigned_torus_slice_wrapping_add_random_gaussian_assign<Float, Scalar>(
460470
&mut self,
@@ -484,9 +494,16 @@ impl<G: ByteRandomGenerator> RandomGenerator<G> {
484494
/// use concrete_csprng::generators::SoftwareRandomGenerator;
485495
/// use concrete_csprng::seeders::Seed;
486496
/// use tfhe::core_crypto::commons::math::random::RandomGenerator;
497+
/// use tfhe::core_crypto::commons::parameters::CiphertextModulus;
487498
/// let mut generator = RandomGenerator::<SoftwareRandomGenerator>::new(Seed(0));
488-
/// let mut vec = vec![1000u32; 100];
489-
/// generator.unsigned_torus_slice_wrapping_add_random_gaussian_assign(&mut vec, 0., 1.);
499+
/// let mut vec = vec![0u32; 1000];
500+
/// generator.unsigned_torus_slice_wrapping_add_random_gaussian_custom_mod_assign(
501+
/// &mut vec,
502+
/// 0.,
503+
/// 1.,
504+
/// CiphertextModulus::try_new_power_of_2(31).unwrap(),
505+
/// );
506+
/// assert!(vec.iter().all(|&x| x != 0));
490507
/// ```
491508
pub fn unsigned_torus_slice_wrapping_add_random_gaussian_custom_mod_assign<Float, Scalar>(
492509
&mut self,

0 commit comments

Comments
 (0)