radamsa/
lib.rs

1use std::sync::atomic::{AtomicU32, Ordering::Relaxed};
2use std::sync::Once;
3
4static DEFAULT_SEED: AtomicU32 = AtomicU32::new(0);
5static INIT: Once = Once::new();
6
7const DEFAULT_BUF_SIZE: usize = 1024 * 1024;
8
9mod bindings;
10
11// Internal library call to make sure radamsa's C library is initialized
12// before making any calls into it.
13fn init() {
14    unsafe {
15        bindings::radamsa_init();
16    }
17}
18
19/// This function generates a new buffer from an existing buffer.
20///
21/// # Arguments
22/// * `input` - A vector of bytes used as input to radamsa.
23/// * `seed`  - An optional seeded value to pass to radamsa. If left as None it increments from 0 after each call.
24/// * `maxsize` - An optional maximum value for the output buffer size. Default: DEFAULT_BUF_SIZE.
25pub fn generate(
26    input: &Vec<u8>,
27    seed: Option<u32>,
28    maxsize: Option<usize>,
29) -> Vec<u8> {
30    INIT.call_once(init);
31    let max_size_val = maxsize.unwrap_or(DEFAULT_BUF_SIZE);
32    let mut out_vec = vec![0u8; max_size_val];
33    let seed_val = match seed {
34        Some(seed) => seed,
35        None => DEFAULT_SEED.fetch_add(1, Relaxed),
36    };
37    let outlen = unsafe {
38        bindings::radamsa(
39            input.as_ptr(),
40            input.len(),
41            out_vec.as_mut_ptr(),
42            max_size_val,
43            seed_val,
44        )
45    };
46    assert!(outlen <= max_size_val);
47    out_vec.truncate(outlen);
48    out_vec
49}
50
51/// This function mutates a buffer in-place
52///
53/// # Arguments
54/// * `input` - A vector of bytes to mutate.
55/// * `seed` - An optional seed value to pass to radamsa. If left as None it increments on each call from 0.
56///
57/// # Return
58/// * `usize` representing the number of filled bytes.
59///
60/// NOTE: Unlike `generate` mutated does not truncate the buffer to the returned size.
61pub fn mutate(input: &mut Vec<u8>, seed: Option<u32>) -> usize {
62    INIT.call_once(init);
63    let seed_val = match seed {
64        Some(seed) => seed,
65        None => DEFAULT_SEED.fetch_add(1, Relaxed),
66    };
67    let outlen = unsafe {
68        bindings::radamsa_inplace(
69            input.as_mut_ptr(),
70            input.len(),
71            input.len(),
72            seed_val,
73        )
74    };
75    outlen
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    #[test]
82    fn test_generator() {
83        let start_val = "hello world".as_bytes().to_vec();
84        for i in 0..100 {
85            let output = generate(&start_val, None, None);
86            println!("output {} {}", i, String::from_utf8_lossy(&output));
87        }
88    }
89
90    #[test]
91    fn test_mutator() {
92        let mut mut_vec = "hello world".as_bytes().to_vec();
93        mut_vec.extend(vec![0u8; 1000].iter().copied());
94        for i in 0..100 {
95            mutate(&mut mut_vec, None);
96            println!("output {} \"{}\"", i, String::from_utf8_lossy(&mut_vec));
97        }
98    }
99}