From 6fce7f09e97aee6b849cb28e6df17ef0fa3b1b15 Mon Sep 17 00:00:00 2001 From: Gabry022003 Date: Mon, 18 Aug 2025 10:33:40 +0200 Subject: [PATCH] =?UTF-8?q?feat(dsa):=20implement=20DSA=20digital=20signat?= =?UTF-8?q?ure=20scheme=20with=20key=20generation=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 11 ++ Cargo.lock | 35 ++++ Cargo.toml | 9 + README.md | 2 + benches/dsa.rs | 44 +++++ examples/dsa_example.rs | 69 +++++++ src/dsa.rs | 2 + src/dsa/algorithms.rs | 334 ++++++++++++++++++++++++++++++++ src/dsa/keys.rs | 44 +++++ src/lib.rs | 2 + src/traits.rs | 1 + src/traits/digital_signature.rs | 24 +++ src/utils/mod.rs | 1 + src/utils/rand.rs | 55 ++++++ 14 files changed, 633 insertions(+) create mode 100644 benches/dsa.rs create mode 100644 examples/dsa_example.rs create mode 100644 src/dsa.rs create mode 100644 src/dsa/algorithms.rs create mode 100644 src/dsa/keys.rs create mode 100644 src/traits/digital_signature.rs create mode 100644 src/utils/mod.rs create mode 100644 src/utils/rand.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..71fa378 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,12 @@ /target +*.pdb +.vscode/ +.idea/ +*~ +*.swp +*.tmp + +.dockerignore +docker-compose.yml +Dockerfile + diff --git a/Cargo.lock b/Cargo.lock index 0eab7ef..a93067a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "bitflags" version = "2.8.0" @@ -141,6 +147,7 @@ dependencies = [ "ff", "group", "rand_core", + "rug", ] [[package]] @@ -187,6 +194,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "gmp-mpfr-sys" +version = "1.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66d61197a68f6323b9afa616cf83d55d69191e1bf364d4eb7d35ae18defe776" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "group" version = "0.13.0" @@ -212,6 +229,12 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -294,6 +317,18 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +[[package]] +name = "rug" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4207e8d668e5b8eb574bda8322088ccd0d7782d3d03c7e8d562e82ed82bdcbc3" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", + "libm", +] + [[package]] name = "rustix" version = "0.38.43" diff --git a/Cargo.toml b/Cargo.toml index 9f8a6cc..1d91288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ blstrs = "0.7.1" ff = "0.13.0" group = { version = "0.13.0", features = ["rand"] } rand_core = { version = "0.6.4", features = ["getrandom"] } +rug = { version = "1.24", features = ["rand"] } [dev-dependencies] divan = "0.1.17" @@ -15,3 +16,11 @@ divan = "0.1.17" [[bench]] name = "bls" harness = false + +[[bench]] +name = "dsa" +harness = false + +[[example]] +name = "dsa_example" +path = "examples/dsa_example.rs" \ No newline at end of file diff --git a/README.md b/README.md index b487cd3..675a03d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ Collection of digital signature schemes written in Rust for the University of Ca ## Schemes - [BLS on the BLS12-381 elliptic curve](./src/bls/) +- [DSA (FIPS 186-4)](./src/dsa/) ## Libraries - [blstrs](https://github.com/filecoin-project/blstrs) +- [rug](https://gitlab.com/tspiteri/rug) - [divan](https://github.com/nvzqz/divan) diff --git a/benches/dsa.rs b/benches/dsa.rs new file mode 100644 index 0000000..c9dbf2c --- /dev/null +++ b/benches/dsa.rs @@ -0,0 +1,44 @@ +use divan::black_box; +use divan::Bencher; +use ds_rust::dsa::algorithms::DSA; +use ds_rust::traits::digital_signature::DigitalSignature; +use rug::rand::RandState; +use ds_rust::utils::rand::rug_randseed_os_rng; + +const SECURITY_LEVEL: u64 = 80; + +#[divan::bench] +fn dsa_keygen() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + let _ = DSA::keygen(black_box(SECURITY_LEVEL), black_box(&mut rng)).unwrap(); +} + +#[divan::bench] +fn dsa_sign(bencher: Bencher) { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + let (sk, _) = DSA::keygen(SECURITY_LEVEL, &mut rng).unwrap(); + let message = b"benchmark message for DSA signing"; + + bencher.bench_local(|| { + let _ = DSA::sign(black_box(&sk), black_box(message), black_box(&mut rng)).unwrap(); + }); +} + +#[divan::bench] +fn dsa_verify(bencher: Bencher) { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + let (sk, pk) = DSA::keygen(SECURITY_LEVEL, &mut rng).unwrap(); + let message = b"benchmark message for DSA verification"; + let signature = DSA::sign(&sk, message, &mut rng).unwrap(); + + bencher.bench_local(|| { + let _ = DSA::verify(black_box(&pk), black_box(message), black_box(&signature)).unwrap(); + }); +} + +fn main() { + divan::main(); +} diff --git a/examples/dsa_example.rs b/examples/dsa_example.rs new file mode 100644 index 0000000..a849be4 --- /dev/null +++ b/examples/dsa_example.rs @@ -0,0 +1,69 @@ +use ds_rust::dsa::algorithms::DSA; +use ds_rust::traits::digital_signature::DigitalSignature; +use ds_rust::utils::rand::rug_randseed_os_rng; +use rug::rand::RandState; +use rug::integer::IntegerExt64; + +fn main() -> Result<(), Box> { + println!("=== DSA Digital Signature Example ===\n"); + + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng)?; + + println!("1. Generating DSA key pair (this may take a moment)..."); + let (secret_key, public_key) = DSA::keygen(80, &mut rng)?; + println!(" Key pair generated successfully"); + println!(" Domain parameters:"); + println!(" p ({} bits): {}...", public_key.p.significant_bits_64(), + public_key.p.to_string().chars().take(50).collect::()); + println!(" q ({} bits): {}...", public_key.q.significant_bits_64(), + public_key.q.to_string().chars().take(50).collect::()); + println!(" g: {}...", public_key.g.to_string().chars().take(50).collect::()); + + let message = b"Hello, this is a test message for DSA digital signature!"; + println!("\n2. Message to sign: {:?}", String::from_utf8_lossy(message)); + + println!("\n3. Signing the message..."); + let signature = DSA::sign(&secret_key, message, &mut rng)?; + println!(" Message signed successfully"); + println!(" Signature:"); + println!(" r: {}...", signature.r.to_string().chars().take(50).collect::()); + println!(" s: {}...", signature.s.to_string().chars().take(50).collect::()); + + println!("\n4. Verifying the signature..."); + let is_valid = DSA::verify(&public_key, message, &signature)?; + println!(" Signature valid: {}", is_valid); + + if is_valid { + println!(" Signature verification successful!"); + } else { + println!(" Signature verification failed!"); + return Err(" Signature verification failed".into()); + } + + println!("\n5. Testing with tampered message..."); + let tampered_message = b"Hello, this is a TAMPERED message for DSA digital signature!"; + let is_tampered_valid = DSA::verify(&public_key, tampered_message, &signature)?; + println!(" Tampered message signature valid: {}", is_tampered_valid); + + if !is_tampered_valid { + println!(" Correctly detected tampered message!"); + } else { + println!(" Failed to detect tampered message!"); + } + + println!("\n6. Testing with tampered signature..."); + let mut tampered_signature = signature.clone(); + tampered_signature.r = &tampered_signature.r + rug::Integer::from(1); + let is_tampered_sig_valid = DSA::verify(&public_key, message, &tampered_signature)?; + println!(" Tampered signature valid: {}", is_tampered_sig_valid); + + if !is_tampered_sig_valid { + println!(" Correctly detected tampered signature!"); + } else { + println!(" Failed to detect tampered signature!"); + } + + println!("\n=== DSA Example Complete ==="); + Ok(()) +} diff --git a/src/dsa.rs b/src/dsa.rs new file mode 100644 index 0000000..966e86e --- /dev/null +++ b/src/dsa.rs @@ -0,0 +1,2 @@ +pub mod algorithms; +pub mod keys; diff --git a/src/dsa/algorithms.rs b/src/dsa/algorithms.rs new file mode 100644 index 0000000..7fcc9d9 --- /dev/null +++ b/src/dsa/algorithms.rs @@ -0,0 +1,334 @@ +use rug::{ + integer::{IntegerExt64, IsPrime}, + Assign, Complete, Integer, +}; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +use crate::traits::digital_signature::DigitalSignature; + +use super::keys::{DSAPublicKey, DSASecretKey, DSASignature}; + +pub struct DSA; + +impl DSA { + + fn get_dsa_params(sec_level: u64) -> Result<(u64, u64), &'static str> { + let (l, n) = match sec_level { + 80 => (1024, 160), + 112 => (2048, 224), + 128 => (2048, 256), + 192 => (3072, 256), + 256 => (3072, 256), + _ => return Err("Invalid security level for DSA."), + }; + Ok((l, n)) + } + + fn generate_domain_params(l: u64, n: u64, rng: &mut rug::rand::RandState) -> Result<(Integer, Integer, Integer), &'static str> { + + let mut q = Integer::new(); + loop { + q.assign(Integer::random_bits_64(n, rng)); + q.set_bit((n - 1) as u32, true); + q.set_bit(0, true); + + if q.is_probably_prime(20) == IsPrime::Probably { + break; + } + } + + let mut p; + let mut counter = 0; + let max_counter = 4 * l; + + loop { + if counter > max_counter { + return Err("Failed to generate suitable p parameter"); + } + + let temp: Integer = Integer::random_bits_64(l, rng).into(); + let mut temp = temp; + temp.set_bit((l - 1) as u32, true); + temp.set_bit(0, true); + + let k: Integer = (&temp / &q).complete(); + p = &k * &q + Integer::from(1); + + if p.significant_bits_64() == l && p.is_probably_prime(20) == IsPrime::Probably { + break; + } + counter += 1; + } + + let p_minus_one = &p - Integer::from(1); + let h_exp = (&p_minus_one / &q).complete(); + + let g; + loop { + let h = Integer::from(2) + Integer::random_below_ref(&p_minus_one, rng).complete(); + let temp_g = h.pow_mod_ref(&h_exp, &p).unwrap().into(); + + if temp_g > 1 { + g = temp_g; + break; + } + } + + Ok((p, q, g)) + } + + fn hash_message(message: &[u8]) -> Integer { + let mut hasher = DefaultHasher::new(); + message.hash(&mut hasher); + Integer::from(hasher.finish()) + } +} + +impl DigitalSignature for DSA { + type SecretKey = DSASecretKey; + type PublicKey = DSAPublicKey; + type Signature = DSASignature; + + fn keygen( + sec_level: u64, + rng: &mut rug::rand::RandState, + ) -> Result<(DSASecretKey, DSAPublicKey), &'static str> { + let (l, n) = DSA::get_dsa_params(sec_level)?; + + let (p, q, g) = DSA::generate_domain_params(l, n, rng)?; + + let mut x = Integer::new(); + loop { + x.assign(q.random_below_ref(rng).complete()); + if x > 1 { + break; + } + } + + let y = g.pow_mod_ref(&x, &p).unwrap().into(); + + let sk = DSASecretKey::new(x, p.clone(), q.clone(), g.clone()); + let pk = DSAPublicKey::new(p, q, g, y); + + Ok((sk, pk)) + } + + fn sign( + sk: &DSASecretKey, + message: &[u8], + rng: &mut rug::rand::RandState, + ) -> Result { + let h = DSA::hash_message(message); + + let h = h.modulo(&sk.q); + + loop { + let mut k = Integer::new(); + loop { + k.assign(sk.q.random_below_ref(rng).complete()); + if k > Integer::ZERO { + break; + } + } + + let r = sk.g.pow_mod_ref(&k, &sk.p).unwrap().complete().modulo(&sk.q); + + if r.is_zero() { + continue; + } + + if let Some(k_inv) = k.invert_ref(&sk.q) { + let s = (k_inv.complete() * (&h + &sk.x * &r).complete()).modulo(&sk.q); + + if !s.is_zero() { + return Ok(DSASignature::new(r, s)); + } + } + + } + } + + fn verify( + pk: &DSAPublicKey, + message: &[u8], + signature: &DSASignature, + ) -> Result { + + if signature.r.is_zero() || signature.r >= pk.q || + signature.s.is_zero() || signature.s >= pk.q { + return Ok(false); + } + + let h = DSA::hash_message(message); + + let h = h.modulo(&pk.q); + + let w = match signature.s.invert_ref(&pk.q) { + Some(inv) => inv.complete(), + None => return Ok(false), + }; + + let h_w = (&h * &w).complete(); + let u1: Integer = h_w.modulo(&pk.q); + + let r_w = (&signature.r * &w).complete(); + let u2: Integer = r_w.modulo(&pk.q); + + let g_u1 = pk.g.pow_mod_ref(&u1, &pk.p).unwrap().complete(); + let y_u2 = pk.y.pow_mod_ref(&u2, &pk.p).unwrap().complete(); + let product: Integer = (&g_u1 * &y_u2).complete(); + let v = product.modulo(&pk.p).modulo(&pk.q); + + Ok(v == signature.r) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rug::rand::RandState; + use crate::utils::rand::rug_randseed_os_rng; + + #[test] + fn test_dsa_keygen() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + + let result = DSA::keygen(112, &mut rng); + assert!(result.is_ok()); + + let (sk, pk) = result.unwrap(); + + assert!(pk.p > Integer::ZERO); + assert!(pk.q > Integer::ZERO); + assert!(pk.g > 1); + assert!(pk.y > 1); + assert!(sk.x > Integer::ZERO); + assert!(sk.x < pk.q); + } + + #[test] + fn test_domain_params_generation() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + + let result = DSA::generate_domain_params(1024, 160, &mut rng); + assert!(result.is_ok()); + + let (p, q, g) = result.unwrap(); + + assert_eq!(p.significant_bits_64(), 1024); + assert_eq!(q.significant_bits_64(), 160); + assert!(g > 1); + + let p_minus_one = &p - Integer::from(1); + let remainder = p_minus_one % &q; + assert_eq!(remainder, Integer::ZERO); + } + + #[test] + fn test_dsa_sign_verify() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + let result = DSA::keygen(80, &mut rng); + assert!(result.is_ok()); + + let (sk, pk) = result.unwrap(); + let message = b"Test message for DSA signing"; + + let signature = DSA::sign(&sk, message, &mut rng); + assert!(signature.is_ok(), "Signing should succeed"); + + let sig = signature.unwrap(); + + assert!(sig.r > Integer::ZERO && sig.r < pk.q); + assert!(sig.s > Integer::ZERO && sig.s < pk.q); + + let verification = DSA::verify(&pk, message, &sig); + assert!(verification.is_ok(), "Verification should not error"); + assert!(verification.unwrap(), "Signature should be valid"); + + let wrong_message = b"Wrong message for DSA signing"; + let wrong_verification = DSA::verify(&pk, wrong_message, &sig); + assert!(wrong_verification.is_ok(), "Verification should not error"); + assert!(!wrong_verification.unwrap(), "Wrong message should fail verification"); + } + + #[test] + fn test_dsa_invalid_signature() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + + let (_, pk) = DSA::keygen(80, &mut rng).unwrap(); + let message = b"Test message"; + + let invalid_sig1 = DSASignature::new(Integer::ZERO, Integer::from(123)); + let result1 = DSA::verify(&pk, message, &invalid_sig1).unwrap(); + assert!(!result1, "Signature with r=0 should be invalid"); + + let invalid_sig2 = DSASignature::new(Integer::from(123), Integer::ZERO); + let result2 = DSA::verify(&pk, message, &invalid_sig2).unwrap(); + assert!(!result2, "Signature with s=0 should be invalid"); + + let invalid_sig3 = DSASignature::new(pk.q.clone(), Integer::from(123)); + let result3 = DSA::verify(&pk, message, &invalid_sig3).unwrap(); + assert!(!result3, "Signature with r>=q should be invalid"); + } + + #[test] + fn test_dsa_mathematical_properties() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + + let (sk, pk) = DSA::keygen(80, &mut rng).unwrap(); + + let g_q: Integer = pk.g.pow_mod_ref(&pk.q, &pk.p).unwrap().complete(); + assert_eq!(g_q, Integer::from(1), "g^q should be 1 mod p"); + + let p_minus_one = &pk.p - Integer::from(1); + let remainder = (&p_minus_one % &pk.q).complete(); + assert_eq!(remainder, Integer::ZERO, "q should divide (p-1)"); + + assert_eq!(pk.p.is_probably_prime(50), IsPrime::Probably, "p should be prime"); + assert_eq!(pk.q.is_probably_prime(50), IsPrime::Probably, "q should be prime"); + + let calculated_y: Integer = pk.g.pow_mod_ref(&sk.x, &pk.p).unwrap().complete(); + assert_eq!(calculated_y, pk.y, "y should equal g^x mod p"); + + assert!(sk.x > Integer::ZERO && sk.x < pk.q, "Private key should be in range (0, q)"); + + println!(" Tutte le proprietà matematiche DSA sono verificate!"); + } + + #[test] + fn test_dsa_deterministic_verification() { + let mut rng = RandState::new(); + rug_randseed_os_rng(128, &mut rng).unwrap(); + + let (sk, pk) = DSA::keygen(80, &mut rng).unwrap(); + let message = b"Test message for deterministic verification"; + + let mut signatures = Vec::new(); + for _ in 0..5 { + let sig = DSA::sign(&sk, message, &mut rng).unwrap(); + signatures.push(sig); + } + + for (i, sig) in signatures.iter().enumerate() { + let is_valid = DSA::verify(&pk, message, sig).unwrap(); + assert!(is_valid, "Signature {} should be valid", i); + } + + for i in 0..signatures.len() { + for j in i+1..signatures.len() { + assert!( + signatures[i].r != signatures[j].r || signatures[i].s != signatures[j].s, + "Signatures {} and {} should be different due to randomness", i, j + ); + } + } + + println!("Deterministic verification completed: all signatures are valid and unique!"); + } +} diff --git a/src/dsa/keys.rs b/src/dsa/keys.rs new file mode 100644 index 0000000..4e0517f --- /dev/null +++ b/src/dsa/keys.rs @@ -0,0 +1,44 @@ +use rug::Integer; + +#[derive(Debug, Clone)] +pub struct DSAPublicKey { + + pub p: Integer, + pub q: Integer, + pub g: Integer, + pub y: Integer, +} + +#[derive(Debug)] +pub struct DSASecretKey { + + pub x: Integer, + pub p: Integer, + pub q: Integer, + pub g: Integer, +} + +#[derive(Debug, Clone)] +pub struct DSASignature { + + pub r: Integer, + pub s: Integer, +} + +impl DSAPublicKey { + pub fn new(p: Integer, q: Integer, g: Integer, y: Integer) -> Self { + Self { p, q, g, y } + } +} + +impl DSASecretKey { + pub fn new(x: Integer, p: Integer, q: Integer, g: Integer) -> Self { + Self { x, p, q, g } + } +} + +impl DSASignature { + pub fn new(r: Integer, s: Integer) -> Self { + Self { r, s } + } +} diff --git a/src/lib.rs b/src/lib.rs index a837c3b..8b7688e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ pub mod bls; pub mod traits; +pub mod dsa; +pub mod utils; \ No newline at end of file diff --git a/src/traits.rs b/src/traits.rs index 420cec0..9567f9c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1 +1,2 @@ pub mod ds; +pub mod digital_signature; \ No newline at end of file diff --git a/src/traits/digital_signature.rs b/src/traits/digital_signature.rs new file mode 100644 index 0000000..ff0823b --- /dev/null +++ b/src/traits/digital_signature.rs @@ -0,0 +1,24 @@ +use rug::rand::RandState; + +pub trait DigitalSignature { + type SecretKey; + type PublicKey; + type Signature; + + fn keygen( + sec_level: u64, + rng: &mut RandState, + ) -> Result<(Self::SecretKey, Self::PublicKey), &'static str>; + + fn sign( + sk: &Self::SecretKey, + message: &[u8], + rng: &mut RandState, + ) -> Result; + + fn verify( + pk: &Self::PublicKey, + message: &[u8], + signature: &Self::Signature, + ) -> Result; +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..63945bc --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod rand; diff --git a/src/utils/rand.rs b/src/utils/rand.rs new file mode 100644 index 0000000..7a97428 --- /dev/null +++ b/src/utils/rand.rs @@ -0,0 +1,55 @@ +use rand_core::{OsRng, RngCore}; +use rug::integer::Order::MsfBe; +use rug::{rand::RandState, Integer}; + +pub fn get_randseed_os_rng(seed_bits: usize) -> Result { + let seed_bytes: usize = seed_bits / 8; + + if seed_bytes < 1 { + return Err("seed_bytes < 1"); + } + + let mut seed: Vec = vec![0; seed_bytes]; + OsRng.fill_bytes(&mut seed); + + let seed: Integer = Integer::from_digits(&seed, MsfBe); + Ok(seed) +} + +pub fn rug_randseed_os_rng(seed_bits: usize, rng: &mut RandState) -> Result<(), &'static str> { + let seed = get_randseed_os_rng(seed_bits)?; + rng.seed(&seed); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn get_randseed_os_rng_seed_bits_error() { + for i in 0..8 { + let r = get_randseed_os_rng(i); + assert!(r.is_err()); + } + } + + #[test] + fn get_randseed_os_rng_works_as_expected() { + for seed_bits in [1024, 2048, 3072, 4096] { + let mut v: Vec = Vec::new(); + + for _ in 0..100 { + match get_randseed_os_rng(seed_bits) { + Ok(s) => v.push(s), + Err(e) => panic!("{}", e), + } + } + + for s in v.windows(2) { + assert_ne!(s[0], s[1]); + } + } + } +}