1mod bindings;
38pub mod test_utils;
40
41use std::{convert::TryFrom, num::TryFromIntError, ptr, sync::Arc};
42
43use bindings::{
44 randomx_alloc_cache,
45 randomx_alloc_dataset,
46 randomx_cache,
47 randomx_calculate_hash,
48 randomx_create_vm,
49 randomx_dataset,
50 randomx_dataset_item_count,
51 randomx_destroy_vm,
52 randomx_get_dataset_memory,
53 randomx_init_cache,
54 randomx_init_dataset,
55 randomx_release_cache,
56 randomx_release_dataset,
57 randomx_vm,
58 randomx_vm_set_cache,
59 randomx_vm_set_dataset,
60 RANDOMX_HASH_SIZE,
61};
62use bitflags::bitflags;
63use libc::{c_ulong, c_void};
64use thiserror::Error;
65
66pub use crate::bindings::RANDOMX_DATASET_ITEM_SIZE;
69use crate::bindings::{
70 randomx_calculate_hash_first,
71 randomx_calculate_hash_last,
72 randomx_calculate_hash_next,
73 randomx_get_flags,
74};
75
76bitflags! {
77 pub struct RandomXFlag: u32 {
79 const FLAG_DEFAULT = 0b0000_0000;
81 const FLAG_LARGE_PAGES = 0b0000_0001;
83 const FLAG_HARD_AES = 0b0000_0010;
85 const FLAG_FULL_MEM = 0b0000_0100;
87 const FLAG_JIT = 0b0000_1000;
89 const FLAG_SECURE = 0b0001_0000;
92 const FLAG_ARGON2_SSSE3 = 0b0010_0000;
94 const FLAG_ARGON2_AVX2 = 0b0100_0000;
96 const FLAG_ARGON2 = 0b0110_0000;
98 }
99}
100
101impl RandomXFlag {
102 pub fn get_recommended_flags() -> RandomXFlag {
111 RandomXFlag {
112 bits: unsafe { randomx_get_flags() },
113 }
114 }
115}
116
117impl Default for RandomXFlag {
118 fn default() -> RandomXFlag {
120 RandomXFlag::FLAG_DEFAULT
121 }
122}
123
124#[derive(Debug, Clone, Error)]
125pub enum RandomXError {
127 #[error("Problem creating the RandomX object: {0}")]
128 CreationError(String),
129 #[error("Problem with configuration flags: {0}")]
130 FlagConfigError(String),
131 #[error("Problem with parameters supplied: {0}")]
132 ParameterError(String),
133 #[error("Failed to convert Int to usize")]
134 TryFromIntError(#[from] TryFromIntError),
135 #[error("Unknown problem running RandomX: {0}")]
136 Other(String),
137}
138
139#[derive(Debug)]
140struct RandomXCacheInner {
141 cache_ptr: *mut randomx_cache,
142}
143
144impl Drop for RandomXCacheInner {
145 fn drop(&mut self) {
147 unsafe {
148 randomx_release_cache(self.cache_ptr);
149 }
150 }
151}
152
153#[derive(Debug, Clone)]
154pub struct RandomXCache {
156 inner: Arc<RandomXCacheInner>,
157}
158
159impl RandomXCache {
160 pub fn new(flags: RandomXFlag, key: &[u8]) -> Result<RandomXCache, RandomXError> {
173 if key.is_empty() {
174 Err(RandomXError::ParameterError("key is empty".to_string()))
175 } else {
176 let cache_ptr = unsafe { randomx_alloc_cache(flags.bits) };
177 if cache_ptr.is_null() {
178 Err(RandomXError::CreationError("Could not allocate cache".to_string()))
179 } else {
180 let inner = RandomXCacheInner { cache_ptr };
181 let result = RandomXCache { inner: Arc::new(inner) };
182 let key_ptr = key.as_ptr() as *mut c_void;
183 let key_size = key.len();
184 unsafe {
185 randomx_init_cache(result.inner.cache_ptr, key_ptr, key_size);
186 }
187 Ok(result)
188 }
189 }
190 }
191}
192
193#[derive(Debug)]
194struct RandomXDatasetInner {
195 dataset_ptr: *mut randomx_dataset,
196 dataset_count: u32,
197 #[allow(dead_code)]
198 cache: RandomXCache,
199}
200
201impl Drop for RandomXDatasetInner {
202 fn drop(&mut self) {
204 unsafe {
205 randomx_release_dataset(self.dataset_ptr);
206 }
207 }
208}
209
210#[derive(Debug, Clone)]
211pub struct RandomXDataset {
213 inner: Arc<RandomXDatasetInner>,
214}
215
216impl RandomXDataset {
217 #[allow(clippy::useless_conversion)]
243 pub fn new(flags: RandomXFlag, cache: RandomXCache, start: u32) -> Result<RandomXDataset, RandomXError> {
244 let item_count = RandomXDataset::count()
245 .map_err(|e| RandomXError::CreationError(format!("Could not get dataset count: {e:?}")))?;
246
247 let test = unsafe { randomx_alloc_dataset(flags.bits) };
248 if test.is_null() {
249 Err(RandomXError::CreationError("Could not allocate dataset".to_string()))
250 } else {
251 let inner = RandomXDatasetInner {
252 dataset_ptr: test,
253 dataset_count: item_count,
254 cache,
255 };
256 let result = RandomXDataset { inner: Arc::new(inner) };
257
258 if start < item_count {
259 let remaining = item_count.saturating_sub(start);
264 if start > 0 {
269 let memory = unsafe { randomx_get_dataset_memory(result.inner.dataset_ptr) };
270 if memory.is_null() {
271 return Err(RandomXError::CreationError(
272 "Could not get dataset memory to zero the uninitialised prefix".to_string(),
273 ));
274 }
275 let prefix_len = usize::try_from(start)?
276 .checked_mul(RANDOMX_DATASET_ITEM_SIZE)
277 .ok_or_else(|| {
278 RandomXError::CreationError(format!("Dataset prefix size overflows: {start}"))
279 })?;
280 unsafe {
285 ptr::write_bytes(memory.cast::<u8>(), 0, prefix_len);
286 }
287 }
288 unsafe {
289 randomx_init_dataset(
290 result.inner.dataset_ptr,
291 result.inner.cache.inner.cache_ptr,
292 c_ulong::from(start),
293 c_ulong::from(remaining),
294 );
295 }
296 Ok(result)
297 } else {
298 Err(RandomXError::CreationError(format!(
299 "start must be less than item_count: start: {start}, item_count: {item_count}",
300 )))
301 }
302 }
303 }
304
305 pub fn count() -> Result<u32, RandomXError> {
307 match unsafe { randomx_dataset_item_count() } {
308 0 => Err(RandomXError::Other("Dataset item count was 0".to_string())),
309 x => {
310 #[cfg(target_os = "windows")]
312 return Ok(x);
313 #[cfg(not(target_os = "windows"))]
314 return Ok(u32::try_from(x)?);
315 },
316 }
317 }
318
319 pub fn get_data(&self) -> Result<Vec<u8>, RandomXError> {
329 let memory = unsafe { randomx_get_dataset_memory(self.inner.dataset_ptr) };
330 if memory.is_null() {
331 return Err(RandomXError::Other("Could not get dataset memory".into()));
332 }
333 let item_count = usize::try_from(self.inner.dataset_count)?;
335 let size_in_bytes = item_count.checked_mul(RANDOMX_DATASET_ITEM_SIZE).ok_or_else(|| {
336 RandomXError::Other(format!(
337 "Dataset size overflows usize: {item_count} items of {RANDOMX_DATASET_ITEM_SIZE} bytes each",
338 ))
339 })?;
340 let data = unsafe { std::slice::from_raw_parts(memory.cast::<u8>(), size_in_bytes) };
349 let mut result = Vec::new();
352 result.try_reserve_exact(size_in_bytes).map_err(|e| {
353 RandomXError::Other(format!(
354 "Could not allocate {size_in_bytes} bytes for the dataset copy: {e}"
355 ))
356 })?;
357 result.extend_from_slice(data);
358 Ok(result)
359 }
360}
361
362#[derive(Debug)]
363pub struct RandomXVM {
365 flags: RandomXFlag,
366 vm: *mut randomx_vm,
367 linked_cache: Option<RandomXCache>,
368 linked_dataset: Option<RandomXDataset>,
369}
370
371impl Drop for RandomXVM {
372 fn drop(&mut self) {
374 unsafe {
375 randomx_destroy_vm(self.vm);
376 }
377 }
378}
379
380impl RandomXVM {
381 pub fn new(
398 flags: RandomXFlag,
399 cache: Option<RandomXCache>,
400 dataset: Option<RandomXDataset>,
401 ) -> Result<RandomXVM, RandomXError> {
402 let is_full_mem = flags.contains(RandomXFlag::FLAG_FULL_MEM);
403 match (cache, dataset) {
404 (None, None) => Err(RandomXError::CreationError("Failed to allocate VM".to_string())),
405 (None, _) if !is_full_mem => Err(RandomXError::FlagConfigError(
406 "No cache and FLAG_FULL_MEM not set".to_string(),
407 )),
408 (_, None) if is_full_mem => Err(RandomXError::FlagConfigError(
409 "No dataset and FLAG_FULL_MEM set".to_string(),
410 )),
411 (cache, dataset) => {
412 let cache_ptr = cache
413 .as_ref()
414 .map(|stash| stash.inner.cache_ptr)
415 .unwrap_or_else(ptr::null_mut);
416 let dataset_ptr = dataset
417 .as_ref()
418 .map(|data| data.inner.dataset_ptr)
419 .unwrap_or_else(ptr::null_mut);
420 let vm = unsafe { randomx_create_vm(flags.bits, cache_ptr, dataset_ptr) };
421 Ok(RandomXVM {
422 vm,
423 flags,
424 linked_cache: cache,
425 linked_dataset: dataset,
426 })
427 },
428 }
429 }
430
431 pub fn reinit_cache(&mut self, cache: RandomXCache) -> Result<(), RandomXError> {
434 if self.flags.contains(RandomXFlag::FLAG_FULL_MEM) {
435 Err(RandomXError::FlagConfigError(
436 "Cannot reinit cache with FLAG_FULL_MEM set".to_string(),
437 ))
438 } else {
439 unsafe {
440 randomx_vm_set_cache(self.vm, cache.inner.cache_ptr);
441 }
442 self.linked_cache = Some(cache);
443 Ok(())
444 }
445 }
446
447 pub fn reinit_dataset(&mut self, dataset: RandomXDataset) -> Result<(), RandomXError> {
450 if self.flags.contains(RandomXFlag::FLAG_FULL_MEM) {
451 unsafe {
452 randomx_vm_set_dataset(self.vm, dataset.inner.dataset_ptr);
453 }
454 self.linked_dataset = Some(dataset);
455 Ok(())
456 } else {
457 Err(RandomXError::FlagConfigError(
458 "Cannot reinit dataset without FLAG_FULL_MEM set".to_string(),
459 ))
460 }
461 }
462
463 pub fn calculate_hash(&self, input: &[u8]) -> Result<Vec<u8>, RandomXError> {
467 if input.is_empty() {
468 Err(RandomXError::ParameterError("input was empty".to_string()))
469 } else {
470 let size_input = input.len();
471 let input_ptr = input.as_ptr() as *mut c_void;
472 let arr = [0; RANDOMX_HASH_SIZE as usize];
473 let output_ptr = arr.as_ptr() as *mut c_void;
474 unsafe {
475 randomx_calculate_hash(self.vm, input_ptr, size_input, output_ptr);
476 }
477 if arr == [0; RANDOMX_HASH_SIZE as usize] {
479 Err(RandomXError::Other("RandomX calculated hash was empty".to_string()))
480 } else {
481 let result = arr.to_vec();
482 Ok(result)
483 }
484 }
485 }
486
487 #[allow(clippy::needless_range_loop)] pub fn calculate_hash_set(&self, input: &[&[u8]]) -> Result<Vec<Vec<u8>>, RandomXError> {
492 if input.is_empty() {
493 return Err(RandomXError::ParameterError("input was empty".to_string()));
495 }
496
497 let mut result = Vec::new();
498 if input.len() == 1 {
500 let hash = self.calculate_hash(input[0])?;
501 result.push(hash);
502 return Ok(result);
503 }
504
505 let mut output_ptr: *mut c_void = ptr::null_mut();
507 let arr = [0; RANDOMX_HASH_SIZE as usize];
508
509 let iterations = input.len() + 1;
511 for i in 0..iterations {
512 if i == iterations - 1 {
513 unsafe {
515 randomx_calculate_hash_last(self.vm, output_ptr);
516 }
517 } else {
518 if input[i].is_empty() {
519 if arr != [0; RANDOMX_HASH_SIZE as usize] {
521 unsafe {
523 randomx_calculate_hash_last(self.vm, output_ptr);
524 }
525 }
526 return Err(RandomXError::ParameterError("input was empty".to_string()));
527 };
528 let size_input = input[i].len();
529 let input_ptr = input[i].as_ptr() as *mut c_void;
530 output_ptr = arr.as_ptr() as *mut c_void;
531 if i == 0 {
532 unsafe {
534 randomx_calculate_hash_first(self.vm, input_ptr, size_input);
535 }
536 } else {
537 unsafe {
538 randomx_calculate_hash_next(self.vm, input_ptr, size_input, output_ptr);
540 }
541 }
542 }
543
544 if i != 0 {
545 if arr == [0; RANDOMX_HASH_SIZE as usize] {
547 return Err(RandomXError::Other("RandomX hash was zero".to_string()));
548 }
549 let output: Vec<u8> = arr.to_vec();
550 result.push(output);
551 }
552 }
553 Ok(result)
554 }
555}
556
557#[cfg(test)]
558mod tests {
559 use std::{convert::TryFrom, ptr, sync::Arc};
560
561 use crate::{
562 bindings::randomx_get_dataset_memory,
563 RandomXCache,
564 RandomXCacheInner,
565 RandomXDataset,
566 RandomXDatasetInner,
567 RandomXFlag,
568 RandomXVM,
569 RANDOMX_DATASET_ITEM_SIZE,
570 };
571
572 #[test]
573 fn lib_alloc_cache() {
574 let flags = RandomXFlag::default();
575 let key = "Key";
576 let cache = RandomXCache::new(flags, key.as_bytes()).expect("Failed to allocate cache");
577 drop(cache);
578 }
579
580 #[test]
581 fn lib_alloc_dataset() {
582 let flags = RandomXFlag::default();
583 let key = "Key";
584 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
585 let dataset = RandomXDataset::new(flags, cache.clone(), 0).expect("Failed to allocate dataset");
586 drop(dataset);
587 drop(cache);
588 }
589
590 #[test]
591 fn lib_alloc_vm() {
592 let flags = RandomXFlag::default();
593 let key = "Key";
594 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
595 let mut vm = RandomXVM::new(flags, Some(cache.clone()), None).expect("Failed to allocate VM");
596 drop(vm);
597 let dataset = RandomXDataset::new(flags, cache.clone(), 0).unwrap();
598 vm = RandomXVM::new(flags, Some(cache.clone()), Some(dataset.clone())).expect("Failed to allocate VM");
599 drop(dataset);
600 drop(cache);
601 drop(vm);
602 }
603
604 #[test]
605 fn lib_dataset_memory() {
606 let flags = RandomXFlag::default();
607 let key = "Key";
608 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
609 let dataset = RandomXDataset::new(flags, cache.clone(), 0).unwrap();
610 let item_count = usize::try_from(RandomXDataset::count().unwrap()).unwrap();
611 let memory = dataset.get_data().expect("Failed to get dataset memory");
612 assert_eq!(
614 memory.len(),
615 item_count * RANDOMX_DATASET_ITEM_SIZE,
616 "get_data did not return the full dataset"
617 );
618 assert!(
621 memory[memory.len() - RANDOMX_DATASET_ITEM_SIZE..]
622 .iter()
623 .any(|&b| b != 0),
624 "The last dataset item was all zeroes"
625 );
626 drop(memory);
627 drop(dataset);
628 drop(cache);
629 }
630
631 #[test]
632 fn lib_dataset_non_zero_start() {
633 const START: u32 = 2;
634 let flags = RandomXFlag::default();
635 let key = "Key";
636 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
637 let item_count = RandomXDataset::count().unwrap();
638 let dataset = RandomXDataset::new(flags, cache.clone(), START).expect("Failed to allocate dataset");
639
640 let memory = unsafe { randomx_get_dataset_memory(dataset.inner.dataset_ptr) };
643 assert!(!memory.is_null());
644 let len = usize::try_from(item_count).unwrap() * RANDOMX_DATASET_ITEM_SIZE;
645 let data = unsafe { std::slice::from_raw_parts(memory.cast::<u8>(), len) };
648
649 let prefix = usize::try_from(START).unwrap() * RANDOMX_DATASET_ITEM_SIZE;
651 assert!(
652 data[..prefix].iter().all(|&b| b == 0),
653 "The uninitialised prefix was not zeroed"
654 );
655 assert!(
662 data[len - RANDOMX_DATASET_ITEM_SIZE..].iter().any(|&b| b != 0),
663 "The last dataset item was not initialised"
664 );
665
666 assert!(RandomXDataset::new(flags, cache.clone(), item_count).is_err());
668
669 drop(dataset);
670 drop(cache);
671 }
672
673 #[test]
674 fn test_null_assignments() {
675 let flags = RandomXFlag::get_recommended_flags();
676 if let Ok(mut vm) = RandomXVM::new(flags, None, None) {
677 let cache = RandomXCache {
678 inner: Arc::new(RandomXCacheInner {
679 cache_ptr: ptr::null_mut(),
680 }),
681 };
682 assert!(vm.reinit_cache(cache.clone()).is_err());
683 let dataset = RandomXDataset {
684 inner: Arc::new(RandomXDatasetInner {
685 dataset_ptr: ptr::null_mut(),
686 dataset_count: 0,
687 cache,
688 }),
689 };
690 assert!(vm.reinit_dataset(dataset.clone()).is_err());
691 }
692 }
693
694 #[test]
695 fn lib_calculate_hash() {
696 let flags = RandomXFlag::get_recommended_flags();
697 let flags2 = flags | RandomXFlag::FLAG_FULL_MEM;
698 let key = "Key";
699 let input = "Input";
700 let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap();
701 let mut vm1 = RandomXVM::new(flags, Some(cache1.clone()), None).unwrap();
702 let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data");
703 let vec = vec![0u8; hash1.len()];
704 assert_ne!(hash1, vec);
705 let reinit_cache = vm1.reinit_cache(cache1.clone());
706 assert!(reinit_cache.is_ok());
707 let hash2 = vm1.calculate_hash(input.as_bytes()).expect("no data");
708 assert_ne!(hash2, vec);
709 assert_eq!(hash1, hash2);
710
711 let cache2 = RandomXCache::new(flags, key.as_bytes()).unwrap();
712 let vm2 = RandomXVM::new(flags, Some(cache2.clone()), None).unwrap();
713 let hash3 = vm2.calculate_hash(input.as_bytes()).expect("no data");
714 assert_eq!(hash2, hash3);
715
716 let cache3 = RandomXCache::new(flags, key.as_bytes()).unwrap();
717 let dataset3 = RandomXDataset::new(flags, cache3.clone(), 0).unwrap();
718 let mut vm3 = RandomXVM::new(flags2, None, Some(dataset3.clone())).unwrap();
719 let hash4 = vm3.calculate_hash(input.as_bytes()).expect("no data");
720 assert_ne!(hash3, vec);
721 let reinit_dataset = vm3.reinit_dataset(dataset3.clone());
722 assert!(reinit_dataset.is_ok());
723 let hash5 = vm3.calculate_hash(input.as_bytes()).expect("no data");
724 assert_ne!(hash4, vec);
725 assert_eq!(hash4, hash5);
726
727 let cache4 = RandomXCache::new(flags, key.as_bytes()).unwrap();
728 let dataset4 = RandomXDataset::new(flags, cache4.clone(), 0).unwrap();
729 let vm4 = RandomXVM::new(flags2, Some(cache4), Some(dataset4.clone())).unwrap();
730 let hash6 = vm3.calculate_hash(input.as_bytes()).expect("no data");
731 assert_eq!(hash5, hash6);
732
733 drop(dataset3);
734 drop(dataset4);
735 drop(cache1);
736 drop(cache2);
737 drop(cache3);
738 drop(vm1);
739 drop(vm2);
740 drop(vm3);
741 drop(vm4);
742 }
743
744 #[test]
745 fn lib_calculate_hash_set() {
746 let flags = RandomXFlag::default();
747 let key = "Key";
748 let inputs = vec!["Input".as_bytes(), "Input 2".as_bytes(), "Inputs 3".as_bytes()];
749 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
750 let vm = RandomXVM::new(flags, Some(cache.clone()), None).unwrap();
751 let hashes = vm.calculate_hash_set(inputs.as_slice()).expect("no data");
752 assert_eq!(inputs.len(), hashes.len());
753 let mut prev_hash = Vec::new();
754 for (i, hash) in hashes.into_iter().enumerate() {
755 let vec = vec![0u8; hash.len()];
756 assert_ne!(hash, vec);
757 assert_ne!(hash, prev_hash);
758 let compare = vm.calculate_hash(inputs[i]).unwrap(); assert_eq!(hash, compare);
760 prev_hash = hash;
761 }
762 drop(cache);
763 drop(vm);
764 }
765
766 #[test]
767 fn lib_calculate_hash_is_consistent() {
768 let flags = RandomXFlag::get_recommended_flags();
769 let key = "Key";
770 let input = "Input";
771 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
772 let dataset = RandomXDataset::new(flags, cache.clone(), 0).unwrap();
773 let vm = RandomXVM::new(flags, Some(cache.clone()), Some(dataset.clone())).unwrap();
774 let hash = vm.calculate_hash(input.as_bytes()).expect("no data");
775 assert_eq!(hash, [
776 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, 215, 213, 59, 71, 32,
777 172, 253, 155, 204, 111, 183, 213, 157, 155
778 ]);
779 drop(vm);
780 drop(dataset);
781 drop(cache);
782
783 let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap();
784 let dataset1 = RandomXDataset::new(flags, cache1.clone(), 0).unwrap();
785 let vm1 = RandomXVM::new(flags, Some(cache1.clone()), Some(dataset1.clone())).unwrap();
786 let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data");
787 assert_eq!(hash1, [
788 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, 215, 213, 59, 71, 32,
789 172, 253, 155, 204, 111, 183, 213, 157, 155
790 ]);
791 drop(vm1);
792 drop(dataset1);
793 drop(cache1);
794 }
795
796 #[test]
797 fn lib_check_cache_and_dataset_lifetimes() {
798 let flags = RandomXFlag::get_recommended_flags();
799 let key = "Key";
800 let input = "Input";
801 let cache = RandomXCache::new(flags, key.as_bytes()).unwrap();
802 let dataset = RandomXDataset::new(flags, cache.clone(), 0).unwrap();
803 let vm = RandomXVM::new(flags, Some(cache.clone()), Some(dataset.clone())).unwrap();
804 drop(dataset);
805 drop(cache);
806 let hash = vm.calculate_hash(input.as_bytes()).expect("no data");
807 assert_eq!(hash, [
808 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, 215, 213, 59, 71, 32,
809 172, 253, 155, 204, 111, 183, 213, 157, 155
810 ]);
811 drop(vm);
812
813 let cache1 = RandomXCache::new(flags, key.as_bytes()).unwrap();
814 let dataset1 = RandomXDataset::new(flags, cache1.clone(), 0).unwrap();
815 let vm1 = RandomXVM::new(flags, Some(cache1.clone()), Some(dataset1.clone())).unwrap();
816 drop(dataset1);
817 drop(cache1);
818 let hash1 = vm1.calculate_hash(input.as_bytes()).expect("no data");
819 assert_eq!(hash1, [
820 114, 81, 192, 5, 165, 242, 107, 100, 184, 77, 37, 129, 52, 203, 217, 227, 65, 83, 215, 213, 59, 71, 32,
821 172, 253, 155, 204, 111, 183, 213, 157, 155
822 ]);
823 drop(vm1);
824 }
825
826 #[test]
827 fn randomx_hash_fast_vs_light() {
828 let input = b"input";
829 let key = b"key";
830
831 let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM;
832 let cache = RandomXCache::new(flags, key).unwrap();
833 let dataset = RandomXDataset::new(flags, cache, 0).unwrap();
834 let fast_vm = RandomXVM::new(flags, None, Some(dataset)).unwrap();
835
836 let flags = RandomXFlag::get_recommended_flags();
837 let cache = RandomXCache::new(flags, key).unwrap();
838 let light_vm = RandomXVM::new(flags, Some(cache), None).unwrap();
839
840 let fast = fast_vm.calculate_hash(input).unwrap();
841 let light = light_vm.calculate_hash(input).unwrap();
842 assert_eq!(fast, light);
843 }
844
845 #[test]
846 fn test_vectors_fast_mode() {
847 let key = b"test key 000";
849 let vectors = [
850 (
851 b"This is a test".as_slice(),
852 "639183aae1bf4c9a35884cb46b09cad9175f04efd7684e7262a0ac1c2f0b4e3f",
853 ),
854 (
855 b"Lorem ipsum dolor sit amet".as_slice(),
856 "300a0adb47603dedb42228ccb2b211104f4da45af709cd7547cd049e9489c969",
857 ),
858 (
859 b"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua".as_slice(),
860 "c36d4ed4191e617309867ed66a443be4075014e2b061bcdaf9ce7b721d2b77a8",
861 ),
862 ];
863
864 let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM;
865 let cache = RandomXCache::new(flags, key).unwrap();
866 let dataset = RandomXDataset::new(flags, cache, 0).unwrap();
867 let vm = RandomXVM::new(flags, None, Some(dataset)).unwrap();
868
869 for (input, expected) in vectors {
870 let hash = vm.calculate_hash(input).unwrap();
871 assert_eq!(hex::decode(expected).unwrap(), hash);
872 }
873 }
874
875 #[test]
876 fn test_vectors_light_mode() {
877 let vectors = [
879 (
880 b"test key 000",
881 b"This is a test".as_slice(),
882 "639183aae1bf4c9a35884cb46b09cad9175f04efd7684e7262a0ac1c2f0b4e3f",
883 ),
884 (
885 b"test key 000",
886 b"Lorem ipsum dolor sit amet".as_slice(),
887 "300a0adb47603dedb42228ccb2b211104f4da45af709cd7547cd049e9489c969",
888 ),
889 (
890 b"test key 000",
891 b"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua".as_slice(),
892 "c36d4ed4191e617309867ed66a443be4075014e2b061bcdaf9ce7b721d2b77a8",
893 ),
894 (
895 b"test key 001",
896 b"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua".as_slice(),
897 "e9ff4503201c0c2cca26d285c93ae883f9b1d30c9eb240b820756f2d5a7905fc",
898 ),
899 ];
900
901 let flags = RandomXFlag::get_recommended_flags();
902 for (key, input, expected) in vectors {
903 let cache = RandomXCache::new(flags, key).unwrap();
904 let vm = RandomXVM::new(flags, Some(cache), None).unwrap();
905 let hash = vm.calculate_hash(input).unwrap();
906 assert_eq!(hex::decode(expected).unwrap(), hash);
907 }
908 }
909}