add block frequency test
All checks were successful
Hydra x86_64-linux.checks.rand_testsuite Hydra build #2758 of procyos:rand_testsuite-pr3:x86_64-linux.checks.rand_testsuite
Hydra x86_64-linux.packages.rand_testsuite Hydra build #2757 of procyos:rand_testsuite-pr3:x86_64-linux.packages.rand_testsuite

This commit is contained in:
Charlotte 🦝 Delenk 2024-09-06 22:03:14 +02:00
parent b56d1b1314
commit badc11aac5
6 changed files with 99 additions and 1 deletions

View file

@ -9,5 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added a simple monobit test.
- Added a block frequency test.
[Unreleased]: https://git.chir.rs/ProcyOS/rand_testsuite

10
Cargo.lock generated
View file

@ -32,6 +32,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "extra-math"
version = "0.1.0"
source = "git+https://git.chir.rs/ProcyOS/extra_math.git#38d6abf85718d053f45c6b77c88607f245be55e0"
dependencies = [
"libm",
"num-traits",
]
[[package]]
name = "funty"
version = "2.0.0"
@ -139,6 +148,7 @@ name = "rand_testsuite"
version = "0.1.0"
dependencies = [
"bitvec",
"extra-math",
"libm",
"num-traits",
"rand",

View file

@ -22,7 +22,7 @@ args @ {
workspaceSrc,
ignoreLockHash,
}: let
nixifiedLockHash = "0c97699175df8652eb6708b342caa7bcc3794d5a6bd83ecc4362d8cf3b262349";
nixifiedLockHash = "a2b590ebe54f290db87e552bf935f4bb11098b9ba02841e8ed499aad10c57419";
workspaceSrc =
if args.workspaceSrc == null
then ./.
@ -113,6 +113,25 @@ in
};
});
"git+https://git.chir.rs/ProcyOS/extra_math.git".extra-math."0.1.0" = overridableMkRustCrate (profileName: rec {
name = "extra-math";
version = "0.1.0";
registry = "git+https://git.chir.rs/ProcyOS/extra_math.git";
src = fetchCrateGit {
url = "https://git.chir.rs/ProcyOS/extra_math.git";
name = "extra-math";
version = "0.1.0";
rev = "38d6abf85718d053f45c6b77c88607f245be55e0";
};
features = builtins.concatLists [
["default"]
];
dependencies = {
libm = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libm."0.2.8" {inherit profileName;}).out;
num_traits = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".num-traits."0.2.19" {inherit profileName;}).out;
};
});
"registry+https://github.com/rust-lang/crates.io-index".funty."2.0.0" = overridableMkRustCrate (profileName: rec {
name = "funty";
version = "2.0.0";
@ -332,6 +351,7 @@ in
];
dependencies = {
bitvec = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bitvec."1.0.1" {inherit profileName;}).out;
extra_math = (rustPackages."git+https://git.chir.rs/ProcyOS/extra_math.git".extra-math."0.1.0" {inherit profileName;}).out;
libm = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libm."0.2.8" {inherit profileName;}).out;
num_traits = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".num-traits."0.2.19" {inherit profileName;}).out;
${

View file

@ -11,6 +11,7 @@ categories = ["development-tools::testing", "no-std", "no-std::no-alloc"]
[dependencies]
bitvec = { version = "1.0.1", default-features = false }
extra-math = { git = "https://git.chir.rs/ProcyOS/extra_math.git", version = "0.1.0" }
libm = "0.2.8"
num-traits = { version = "0.2.19", default-features = false, features = [
"libm",

View file

@ -1,5 +1,6 @@
//! All supported tests are available in this module.
mod block_frequency;
mod monobit;
use bitvec::prelude::{BitOrder, BitSlice, BitStore};

View file

@ -0,0 +1,65 @@
//! Block Frequency Test
use bitvec::prelude::{BitOrder, BitSlice, BitStore};
use extra_math::gamma::Gamma;
#[allow(unused_imports, reason = "redundant in std use cases")]
use num_traits::Float;
use crate::RandomTest;
/// The Block Frequency Test splits the input data into multiple blocks, counts the frequency 1s and 0s within these blocks, and determines whether these are distributed well.
///
/// The amount of blocks is chosen such that a block is at least 1% of the size of the total input, or at least 20.
///
/// This test is defined in the [NIST Special Publication 800-22](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-22r1a.pdf).
#[derive(Copy, Clone, Debug)]
pub struct BlockFrequency;
impl RandomTest for BlockFrequency {
const RECOMMENDED_BIT_SIZE: usize = 100;
const MINIMUM_BIT_SIZE: usize = 0;
fn evaluate<T: BitStore, O: BitOrder>(&self, bs: &BitSlice<T, O>) -> Option<f64> {
let block_size = (bs.len() / 100).max(20);
let block_count = bs.len() / block_size;
let mut statistic = 0.0;
for i in 0..block_count {
let one_count: usize = bs[i * block_size..(i + 1) * block_size]
.into_iter()
.map(|v| if *v { 1 } else { 0 })
.sum();
let pi = (one_count as f64) / (block_size as f64);
statistic += (pi - 0.5).powi(2);
}
statistic *= (4 * block_size) as f64;
Some(Gamma::upper_gamma_regularized(
block_size as f64 / 2.0,
statistic / 2.0,
))
}
}
#[cfg(test)]
mod tests {
use bitvec::prelude::*;
use crate::RandomTest;
use super::BlockFrequency;
#[test]
fn block_frequency_test_vector() {
let epsilon = bitvec![
1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0,
1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1,
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0
];
let res = BlockFrequency.evaluate(epsilon.as_bitslice());
assert!(res.is_some());
let res = res.unwrap();
assert!(res > 0.01, "Data should be evaluated as random");
}
}