diff --git a/Cargo.toml b/Cargo.toml index 27a518f..92a4af7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ thiserror = "1.0.30" [dev-dependencies] hex = "0.4.3" +quickcheck = "1" diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..1a45eee --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..962474a --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,129 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "monero-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "randomx-rs", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "randomx-rs" +version = "1.2.1" +dependencies = [ + "bitflags", + "libc", + "thiserror", +] + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..7c1bff9 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "monero-fuzz" +version = "0.0.0" +edition = "2021" +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.randomx-rs] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "randomx_alloc_cache" +path = "fuzz_targets/randomx_alloc_cache.rs" +test = false +doc = false + +[[bin]] +name = "randomx_create_vm_with_cache_only" +path = "fuzz_targets/randomx_create_vm_with_cache_only.rs" +test = false +doc = false + +[[bin]] +name = "randomx_create_vm_with_cache_and_dataset" +path = "fuzz_targets/randomx_create_vm_with_cache_and_dataset.rs" +test = false +doc = false + +[[bin]] +name = "randomx_vm_calculate_hash_with_cache_only" +path = "fuzz_targets/randomx_vm_calculate_hash_with_cache_only.rs" +test = false +doc = false + +[[bin]] +name = "randomx_vm_calculate_hash_with_cache_and_dataset" +path = "fuzz_targets/randomx_vm_calculate_hash_with_cache_and_dataset.rs" +test = false +doc = false diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 0000000..af2c4bc --- /dev/null +++ b/fuzz/README.md @@ -0,0 +1,22 @@ +# Fuzzing randomx-rs + +See https://rust-fuzz.github.io/book/cargo-fuzz.html for more information on fuzzing with cargo-fuzz. +Install `cargo-fuzz` as per [installation instructions](https://rust-fuzz.github.io/book/cargo-fuzz/setup.html). + + +**Note:** Fuzzing is not supported on Windows yet. + +To get a list of fuzz targets, from a terminal in the project root, run +``` +cargo fuzz list +``` + +To run a fuzz test, from a terminal in the project root, run +``` +cargo +nightly fuzz run --release +``` +To run fuzz tests involving a cache and dataset, on error `libFuzzer: out-of-memory (malloc(2181038016))`, pass +`-- -rss_limit_mb=` as argument to allow using more than 2 GB of RAM - 3GB recommended. +``` +cargo +nightly fuzz run --release -- -rss_limit_mb=3221225472 +``` diff --git a/fuzz/fuzz_targets/randomx_alloc_cache.rs b/fuzz/fuzz_targets/randomx_alloc_cache.rs new file mode 100644 index 0000000..77877a6 --- /dev/null +++ b/fuzz/fuzz_targets/randomx_alloc_cache.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use randomx_rs::test_utils::fuzz_randomx_alloc_cache; + +fuzz_target!(|data: &[u8]| { + fuzz_randomx_alloc_cache(data.to_vec()); +}); diff --git a/fuzz/fuzz_targets/randomx_create_vm_with_cache_and_dataset.rs b/fuzz/fuzz_targets/randomx_create_vm_with_cache_and_dataset.rs new file mode 100644 index 0000000..5a485d8 --- /dev/null +++ b/fuzz/fuzz_targets/randomx_create_vm_with_cache_and_dataset.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use randomx_rs::test_utils::fuzz_randomx_create_vm_with_cache_and_dataset; + +fuzz_target!(|data: &[u8]| { + fuzz_randomx_create_vm_with_cache_and_dataset(data.to_vec()); +}); diff --git a/fuzz/fuzz_targets/randomx_create_vm_with_cache_only.rs b/fuzz/fuzz_targets/randomx_create_vm_with_cache_only.rs new file mode 100644 index 0000000..686fe8f --- /dev/null +++ b/fuzz/fuzz_targets/randomx_create_vm_with_cache_only.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use randomx_rs::test_utils::fuzz_randomx_create_vm_with_cache_only; + +fuzz_target!(|data: &[u8]| { + fuzz_randomx_create_vm_with_cache_only(data.to_vec()); +}); diff --git a/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_and_dataset.rs b/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_and_dataset.rs new file mode 100644 index 0000000..be21873 --- /dev/null +++ b/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_and_dataset.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use randomx_rs::test_utils::fuzz_randomx_vm_calculate_hash_with_cache_and_dataset; + +fuzz_target!(|data: &[u8]| { + fuzz_randomx_vm_calculate_hash_with_cache_and_dataset(data.to_vec()); +}); diff --git a/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_only.rs b/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_only.rs new file mode 100644 index 0000000..533fe8f --- /dev/null +++ b/fuzz/fuzz_targets/randomx_vm_calculate_hash_with_cache_only.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use randomx_rs::test_utils::fuzz_randomx_vm_calculate_hash_with_cache_only; + +fuzz_target!(|data: &[u8]| { + fuzz_randomx_vm_calculate_hash_with_cache_only(data.to_vec()); +}); diff --git a/src/lib.rs b/src/lib.rs index d24c59b..dc198d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,9 @@ //! [RandomX github repo]: //! [design document]: mod bindings; +/// Test utilities for fuzzing +pub mod test_utils; + use std::{convert::TryFrom, num::TryFromIntError, ptr, sync::Arc}; use bindings::{ @@ -167,11 +170,11 @@ impl RandomXCache { if key.is_empty() { Err(RandomXError::ParameterError("key is empty".to_string())) } else { - let test = unsafe { randomx_alloc_cache(flags.bits) }; - if test.is_null() { + let cache_ptr = unsafe { randomx_alloc_cache(flags.bits) }; + if cache_ptr.is_null() { Err(RandomXError::CreationError("Could not allocate cache".to_string())) } else { - let inner = RandomXCacheInner { cache_ptr: test }; + let inner = RandomXCacheInner { cache_ptr }; let result = RandomXCache { inner: Arc::new(inner) }; let key_ptr = key.as_ptr() as *mut c_void; let key_size = key.len(); @@ -480,7 +483,9 @@ impl RandomXVM { #[cfg(test)] mod tests { - use crate::{RandomXCache, RandomXDataset, RandomXFlag, RandomXVM}; + use std::{ptr, sync::Arc}; + + use crate::{RandomXCache, RandomXCacheInner, RandomXDataset, RandomXDatasetInner, RandomXFlag, RandomXVM}; #[test] fn lib_alloc_cache() { @@ -522,12 +527,33 @@ mod tests { let dataset = RandomXDataset::new(flags, cache.clone(), 0).unwrap(); let memory = dataset.get_data().unwrap_or_else(|_| std::vec::Vec::new()); assert!(!memory.is_empty(), "Failed to get dataset memory"); - let vec = vec![0u8; memory.len() as usize]; + let vec = vec![0u8; memory.len()]; assert_ne!(memory, vec); drop(dataset); drop(cache); } + #[test] + fn test_null_assignments() { + let flags = RandomXFlag::get_recommended_flags(); + if let Ok(mut vm) = RandomXVM::new(flags, None, None) { + let cache = RandomXCache { + inner: Arc::new(RandomXCacheInner { + cache_ptr: ptr::null_mut(), + }), + }; + assert!(vm.reinit_cache(cache.clone()).is_err()); + let dataset = RandomXDataset { + inner: Arc::new(RandomXDatasetInner { + dataset_ptr: ptr::null_mut(), + dataset_count: 0, + cache, + }), + }; + assert!(vm.reinit_dataset(dataset.clone()).is_err()); + } + } + #[test] fn lib_calculate_hash() { let flags = RandomXFlag::get_recommended_flags(); @@ -537,7 +563,7 @@ mod tests { let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap(); let mut vm1 = RandomXVM::new(flags, Some(cache1.clone()), None).unwrap(); let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data"); - let vec = vec![0u8; hash1.len() as usize]; + let vec = vec![0u8; hash1.len()]; assert_ne!(hash1, vec); let reinit_cache = vm1.reinit_cache(cache1.clone()); assert!(reinit_cache.is_ok()); @@ -589,7 +615,7 @@ mod tests { assert_eq!(inputs.len(), hashes.len()); let mut prev_hash = Vec::new(); for (i, hash) in hashes.into_iter().enumerate() { - let vec = vec![0u8; hash.len() as usize]; + let vec = vec![0u8; hash.len()]; assert_ne!(hash, vec); assert_ne!(hash, prev_hash); let compare = vm.calculate_hash(inputs[i]).unwrap(); // sanity check diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 0000000..90ec4fb --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,253 @@ +// Copyright 2019. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use crate::{RandomXCache, RandomXDataset, RandomXFlag, RandomXVM}; + +/// Fuzzing: +/// - `pub fn randomx_alloc_cache` +/// - `pub fn randomx_get_flags` +/// - `pub fn randomx_init_cache` +/// - `pub fn randomx_release_cache` +#[allow(clippy::needless_pass_by_value)] // This is required by the `QuickCheck` fuzzing framework +pub fn fuzz_randomx_alloc_cache(data: Vec) -> bool { + let flags = if data.is_empty() { + RandomXFlag::default() + } else { + match data[0] % 10 { + 0 => RandomXFlag::get_recommended_flags(), + 1 => RandomXFlag::FLAG_DEFAULT, + 2 => RandomXFlag::FLAG_LARGE_PAGES, + 3 => RandomXFlag::FLAG_HARD_AES, + 4 => RandomXFlag::FLAG_FULL_MEM, + 5 => RandomXFlag::FLAG_JIT, + 6 => RandomXFlag::FLAG_SECURE, + 7 => RandomXFlag::FLAG_ARGON2_SSSE3, + 8 => RandomXFlag::FLAG_ARGON2_AVX2, + _ => RandomXFlag::FLAG_ARGON2, + } + }; + let _unused = RandomXCache::new(flags, &data); + true +} + +/// Fuzzing: +/// - `pub fn randomx_create_vm` +/// - `pub fn randomx_destroy_vm` +/// - `pub fn randomx_vm_set_cache` +/// - `pub fn randomx_alloc_cache` +/// - `pub fn randomx_get_flags` +/// - `pub fn randomx_init_cache` +/// - `pub fn randomx_release_cache` +#[allow(clippy::needless_pass_by_value)] // This is required by the `QuickCheck` fuzzing framework + +pub fn fuzz_randomx_create_vm_with_cache_only(data: Vec) -> bool { + let flags = RandomXFlag::get_recommended_flags(); + if let Ok(cache) = RandomXCache::new(flags, &data) { + if let Ok(mut vm) = RandomXVM::new(flags, Some(cache.clone()), None) { + let _unused = vm.reinit_cache(cache); + } + } + true +} + +/// Fuzzing: +/// - `pub fn randomx_get_flags` +/// - `pub fn randomx_create_vm` +/// - `pub fn randomx_destroy_vm` +/// - `pub fn randomx_dataset_item_count` +/// - `pub fn randomx_alloc_cache` +/// - `pub fn randomx_init_cache` +/// - `pub fn randomx_release_cache` +/// - `pub fn randomx_alloc_dataset` +/// - `pub fn randomx_init_dataset` +/// - `pub fn randomx_release_dataset` +/// - `pub fn randomx_vm_set_cache` +/// - `pub fn randomx_vm_set_dataset` +/// - `pub fn randomx_dataset_item_count` +/// - `pub fn randomx_get_dataset_memory` +#[allow(clippy::needless_pass_by_value)] // This is required by the `QuickCheck` fuzzing framework +pub fn fuzz_randomx_create_vm_with_cache_and_dataset(data: Vec) -> bool { + let flags = RandomXFlag::get_recommended_flags(); + if let Ok(cache) = RandomXCache::new(flags, &data) { + let start = if data.is_empty() { 0u32 } else { u32::from(data[0] % 3) }; + if let Ok(dataset) = RandomXDataset::new(flags, cache.clone(), start) { + for _ in 0..100 { + let _unused = dataset.get_data(); + } + if let Ok(mut vm) = RandomXVM::new(flags, Some(cache.clone()), Some(dataset.clone())) { + let _unused = vm.reinit_cache(cache); + let _unused = vm.reinit_dataset(dataset); + } + } + } + true +} + +// Helper function to calculate hashes +fn calculate_hashes(hash_data: &[u8], vm: &mut RandomXVM, iterations: u8) { + let mut hash_data = hash_data.to_vec(); + for _ in 0..iterations { + if hash_data.len() > 1 { + // Prepare hash input data + let hash_set_len = 12; + let mut hash_set = Vec::with_capacity(hash_set_len); + for _ in 0..hash_set_len { + let mut scratch_data = hash_data.clone(); + let last = scratch_data.pop().unwrap(); + scratch_data.insert(0, last); + hash_set.push(scratch_data); + } + let hash_set_ref = hash_set.iter().map(|v| v.as_slice()).collect::>(); + // Fuzz hash + let _unused = vm.calculate_hash(&hash_data); + let _unused = vm.calculate_hash_set(&hash_set_ref); + // Change data set + hash_data.pop(); + } else { + let _unused = vm.calculate_hash(&hash_data); + let _unused = vm.calculate_hash_set(&[&hash_data]); + } + } +} + +/// Fuzzing: +/// - `pub fn randomx_calculate_hash` +/// - `pub fn randomx_calculate_hash_last` +/// - `pub fn randomx_calculate_hash_first` +/// - `pub fn randomx_calculate_hash_next` +/// Secondary: +/// - `pub fn randomx_create_vm` +/// - `pub fn randomx_destroy_vm` +/// - `pub fn randomx_alloc_cache` +/// - `pub fn randomx_get_flags` +/// - `pub fn randomx_init_cache` +/// - `pub fn randomx_release_cache` +#[allow(clippy::needless_pass_by_value)] // This is required by the `QuickCheck` fuzzing framework +pub fn fuzz_randomx_vm_calculate_hash_with_cache_only(data: Vec) -> bool { + let flags = RandomXFlag::get_recommended_flags(); + if let Ok(cache) = RandomXCache::new(flags, &data) { + let vm = RandomXVM::new(flags, Some(cache), None); + if let Ok(mut vm) = vm { + calculate_hashes(&data, &mut vm, 100); + } + } + true +} + +/// Fuzzing: +/// - `pub fn randomx_calculate_hash` +/// - `pub fn randomx_calculate_hash_last` +/// - `pub fn randomx_calculate_hash_first` +/// - `pub fn randomx_calculate_hash_next` +/// Secondary: +/// - `pub fn randomx_create_vm` +/// - `pub fn randomx_destroy_vm` +/// - `pub fn randomx_alloc_cache` +/// - `pub fn randomx_get_flags` +/// - `pub fn randomx_init_cache` +/// - `pub fn randomx_release_cache` +/// - `pub fn randomx_alloc_dataset` +/// - `pub fn randomx_init_dataset` +/// - `pub fn randomx_dataset_item_count` +/// - `pub fn randomx_get_dataset_memory` +/// - `pub fn randomx_release_dataset` +#[allow(clippy::needless_pass_by_value)] // This is required by the `QuickCheck` fuzzing framework +pub fn fuzz_randomx_vm_calculate_hash_with_cache_and_dataset(data: Vec) -> bool { + let flags = RandomXFlag::get_recommended_flags(); + if let Ok(cache) = RandomXCache::new(flags, &data) { + if let Ok(dataset) = RandomXDataset::new(flags, cache.clone(), 0) { + let vm = RandomXVM::new(flags, Some(cache), Some(dataset.clone())); + if let Ok(mut vm) = vm { + calculate_hashes(&data, &mut vm, 100); + } + } + } + true +} + +#[cfg(test)] +mod tests { + use quickcheck::QuickCheck; + + use crate::test_utils::{ + fuzz_randomx_alloc_cache, + fuzz_randomx_create_vm_with_cache_and_dataset, + fuzz_randomx_create_vm_with_cache_only, + fuzz_randomx_vm_calculate_hash_with_cache_and_dataset, + fuzz_randomx_vm_calculate_hash_with_cache_only, + }; + + #[test] + fn test_fuzz_lib_alloc_cache() { + fuzz_randomx_alloc_cache(vec![]); + const TESTS: u64 = 25; + QuickCheck::new() + .min_tests_passed(TESTS) + .tests(TESTS) + .max_tests(TESTS) + .quickcheck(fuzz_randomx_alloc_cache as fn(Vec) -> bool); + } + + #[test] + fn test_fuzz_randomx_create_vm_with_cache_only() { + fuzz_randomx_create_vm_with_cache_only(vec![]); + const TESTS: u64 = 25; + QuickCheck::new() + .min_tests_passed(TESTS) + .tests(TESTS) + .max_tests(TESTS) + .quickcheck(fuzz_randomx_create_vm_with_cache_only as fn(Vec) -> bool); + } + + #[test] + fn test_fuzz_randomx_create_vm_with_cache_and_dataset() { + fuzz_randomx_create_vm_with_cache_and_dataset(vec![]); + const TESTS: u64 = 1; + QuickCheck::new() + .min_tests_passed(TESTS) + .tests(TESTS) + .max_tests(TESTS) + .quickcheck(fuzz_randomx_create_vm_with_cache_and_dataset as fn(Vec) -> bool); + } + + #[test] + fn test_fuzz_randomx_vm_calculate_hash_with_cache_only() { + fuzz_randomx_vm_calculate_hash_with_cache_only(vec![]); + const TESTS: u64 = 3; + QuickCheck::new() + .min_tests_passed(TESTS) + .tests(TESTS) + .max_tests(TESTS) + .quickcheck(fuzz_randomx_vm_calculate_hash_with_cache_only as fn(Vec) -> bool); + } + + #[test] + fn test_fuzz_randomx_vm_calculate_hash_with_cache_and_dataset() { + fuzz_randomx_vm_calculate_hash_with_cache_and_dataset(vec![]); + const TESTS: u64 = 1; + QuickCheck::new() + .min_tests_passed(TESTS) + .tests(TESTS) + .max_tests(TESTS) + .quickcheck(fuzz_randomx_vm_calculate_hash_with_cache_and_dataset as fn(Vec) -> bool); + } +}