use crate::{
integer::Z,
integer_mod_q::MatZq,
macros::seeded::seedable_function,
traits::{MatrixDimensions, MatrixSetEntry},
utils::sample::uniform::UniformIntegerSampler,
};
use std::fmt::Display;
impl MatZq {
seedable_function!(
#[unseeded]
#[seeded]
#[optionally_seeded]
#[optionally_seeded]
#[seeded]
#[optionally_seeded]
#[optionally_seeded]
#[unseeded]
#[seeded]
pub(crate) fn sample_uniform(
num_rows: impl TryInto<i64> + Display,
num_cols: impl TryInto<i64> + Display,
modulus: impl Into<Z>,
seed: Option<[u8; 32]>,
) -> Self {
let modulus: Z = modulus.into();
let mut uis = UniformIntegerSampler::init(&modulus, seed).unwrap();
let mut matrix = MatZq::new(num_rows, num_cols, modulus);
for row in 0..matrix.get_num_rows() {
for col in 0..matrix.get_num_columns() {
let sample = uis.sample();
unsafe { matrix.set_entry_unchecked(row, col, sample) };
}
}
matrix
}
);
}
#[cfg(test)]
mod test_sample_uniform {
use crate::traits::{MatrixDimensions, MatrixGetEntry};
use crate::utils::sample::test_seed;
use crate::{
integer::Z,
integer_mod_q::{MatZq, Modulus},
};
#[test]
fn boundaries_kept_small() {
for seeded in [false, true] {
for _ in 0..32 {
let matrix =
MatZq::sample_uniform_optionally_seeded(1, 1, 17, seeded.then(test_seed));
let sample: Z = matrix.get_entry(0, 0).unwrap();
assert!(Z::ZERO <= sample);
assert!(sample < 17);
}
}
}
#[test]
fn boundaries_kept_large() {
for seeded in [false, true] {
let modulus = Z::from(u64::MAX);
for _ in 0..256 {
let matrix =
MatZq::sample_uniform_optionally_seeded(1, 1, &modulus, seeded.then(test_seed));
let sample: Z = matrix.get_entry(0, 0).unwrap();
assert!(Z::ZERO <= sample);
assert!(sample < modulus);
}
}
}
#[test]
fn false_size() {
for seeded in [false, true] {
let result = std::panic::catch_unwind(|| {
let modulus = Z::from(15);
let _ =
MatZq::sample_uniform_optionally_seeded(0, 3, &modulus, seeded.then(test_seed));
});
assert!(result.is_err());
}
}
#[test]
fn invalid_modulus() {
for seeded in [false, true] {
let result = std::panic::catch_unwind(|| {
let _ = MatZq::sample_uniform_optionally_seeded(4, 1, 1, seeded.then(test_seed));
});
assert!(result.is_err());
}
}
#[test]
fn availability() {
for seeded in [false, true] {
let modulus = Modulus::from(7);
let z = Z::from(7);
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7u8, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7u16, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7u32, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7u64, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7i8, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7i16, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7i32, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, 7i64, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, &modulus, seeded.then(test_seed));
let _ = MatZq::sample_uniform_optionally_seeded(1, 1, &z, seeded.then(test_seed));
if seeded {
let _ = MatZq::sample_uniform_seeded(1, 1, 7u8, test_seed());
} else {
let _ = MatZq::sample_uniform(1, 1, 7u8);
}
}
}
#[test]
fn matrix_size() {
for seeded in [false, true] {
let modulus = Z::from(15);
let mat_0 =
MatZq::sample_uniform_optionally_seeded(3, 3, &modulus, seeded.then(test_seed));
let mat_1 =
MatZq::sample_uniform_optionally_seeded(4, 1, &modulus, seeded.then(test_seed));
let mat_2 =
MatZq::sample_uniform_optionally_seeded(1, 5, &modulus, seeded.then(test_seed));
let mat_3 =
MatZq::sample_uniform_optionally_seeded(15, 20, &modulus, seeded.then(test_seed));
assert_eq!(3, mat_0.get_num_rows());
assert_eq!(3, mat_0.get_num_columns());
assert_eq!(4, mat_1.get_num_rows());
assert_eq!(1, mat_1.get_num_columns());
assert_eq!(1, mat_2.get_num_rows());
assert_eq!(5, mat_2.get_num_columns());
assert_eq!(15, mat_3.get_num_rows());
assert_eq!(20, mat_3.get_num_columns());
}
}
#[test]
fn same_seed_same_sample() {
use crate::integer_mod_q::MatZq;
let sample_0 = MatZq::sample_uniform_seeded(3, 3, 17, [42; 32]);
let sample_1 = MatZq::sample_uniform_seeded(3, 3, 17, [42; 32]);
assert_eq!(sample_0, sample_1);
}
#[test]
fn known_answer() {
use crate::integer_mod_q::MatZq;
let sample = MatZq::sample_uniform_seeded(3, 3, 17, [42; 32]);
assert_eq!(
"[[2, 16, 3],[7, 7, 16],[4, 13, 0]] mod 17",
sample.to_string()
);
}
}