1use libc::{c_uint, c_ulong, c_void};
24pub const RANDOMX_HASH_SIZE: u32 = 32;
25
26#[repr(C)]
27pub struct randomx_dataset {
28 _unused: [u8; 0],
29}
30
31#[repr(C)]
32pub struct randomx_cache {
33 _unused: [u8; 0],
34}
35
36#[repr(C)]
37pub struct randomx_vm {
38 _unused: [u8; 0],
39}
40
41extern "C" {
42 pub fn randomx_alloc_cache(flags: c_uint) -> *mut randomx_cache;
43 pub fn randomx_init_cache(cache: *mut randomx_cache, key: *const c_void, keySize: usize);
44 pub fn randomx_release_cache(cache: *mut randomx_cache);
45 pub fn randomx_alloc_dataset(flags: c_uint) -> *mut randomx_dataset;
46 pub fn randomx_dataset_item_count() -> c_ulong;
47 pub fn randomx_init_dataset(
48 dataset: *mut randomx_dataset,
49 cache: *mut randomx_cache,
50 start_item: c_ulong,
51 item_count: c_ulong,
52 );
53 pub fn randomx_get_dataset_memory(dataset: *mut randomx_dataset) -> *mut c_void;
54 pub fn randomx_release_dataset(dataset: *mut randomx_dataset);
55 pub fn randomx_create_vm(
56 flags: c_uint,
57 cache: *mut randomx_cache,
58 dataset: *mut randomx_dataset,
59 ) -> *mut randomx_vm;
60 pub fn randomx_vm_set_cache(machine: *mut randomx_vm, cache: *mut randomx_cache);
61 pub fn randomx_vm_set_dataset(machine: *mut randomx_vm, dataset: *mut randomx_dataset);
62 pub fn randomx_destroy_vm(machine: *mut randomx_vm);
63 pub fn randomx_calculate_hash(
64 machine: *mut randomx_vm,
65 input: *const c_void,
66 input_size: usize,
67 output: *mut c_void,
68 );
69 pub fn randomx_calculate_hash_first(machine: *mut randomx_vm, input: *const c_void, input_size: usize);
70 pub fn randomx_calculate_hash_next(
71 machine: *mut randomx_vm,
72 input_next: *const c_void,
73 input_size_next: usize,
74 output: *mut c_void,
75 );
76 pub fn randomx_calculate_hash_last(machine: *mut randomx_vm, output: *mut c_void);
77 pub fn randomx_get_flags() -> c_uint;
78}
79
80#[cfg(test)]
81mod tests {
82 use std::ptr;
83
84 use libc::{c_uint, c_void};
85
86 use super::*;
87
88 #[test]
89 fn alloc_cache() {
90 let key = b"Key";
91 let flag: c_uint = 0;
92 let cache = unsafe { randomx_alloc_cache(flag) };
93 assert!(!cache.is_null(), "Failed to init cache");
94
95 unsafe {
96 randomx_init_cache(cache, key.as_ptr() as _, key.len());
97 }
98 unsafe {
99 randomx_release_cache(cache);
100 }
101 }
102
103 #[test]
104 fn alloc_dataset() {
105 let key = b"Key";
106 let flag: c_uint = 0;
107 let cache = unsafe { randomx_alloc_cache(flag) };
108
109 unsafe {
110 randomx_init_cache(cache, key.as_ptr() as _, key.len());
111 }
112
113 let dataset = unsafe { randomx_alloc_dataset(flag) };
114
115 unsafe { randomx_init_dataset(dataset, cache, 0, 1) };
116
117 assert_ne!(unsafe { randomx_dataset_item_count() }, 0);
118
119 unsafe {
120 randomx_release_dataset(dataset);
121 randomx_release_cache(cache);
122 }
123 }
124
125 #[test]
126 fn alloc_vm() {
127 let key = b"Key";
128 let flag: c_uint = 0;
129
130 let cache = unsafe { randomx_alloc_cache(flag) };
131
132 unsafe {
133 randomx_init_cache(cache, key.as_ptr() as _, key.len());
134 }
135 let mut vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) };
136 if vm.is_null() {
137 panic!("Failed to init vm with cache");
138 }
139 unsafe {
140 randomx_vm_set_cache(vm, cache);
141 randomx_destroy_vm(vm);
142 }
143
144 let dataset = unsafe { randomx_alloc_dataset(flag) };
145 unsafe { randomx_init_dataset(dataset, cache, 0, 1) }
146
147 vm = unsafe { randomx_create_vm(flag, cache, dataset) };
148 if vm.is_null() {
149 panic!("Failed to init vm with dataset");
150 }
151 unsafe {
152 randomx_vm_set_dataset(vm, dataset);
153 }
154
155 unsafe {
156 randomx_release_dataset(dataset);
157 randomx_release_cache(cache);
158 randomx_destroy_vm(vm);
159 }
160 }
161
162 #[test]
163 fn calculate_hash() {
164 let key = b"test key 000";
165 let input = b"This is a test";
166 let expected = b"639183aae1bf4c9a35884cb46b09cad9175f04efd7684e7262a0ac1c2f0b4e3f";
167
168 let flag: c_uint = 0;
169
170 let arr = [0u8; RANDOMX_HASH_SIZE as usize];
171 let output_ptr = arr.as_ptr() as *mut c_void;
172
173 let cache = unsafe { randomx_alloc_cache(flag) };
174
175 unsafe {
176 randomx_init_cache(cache, key.as_ptr() as _, key.len());
177 }
178
179 let vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) };
180
181 unsafe {
182 randomx_calculate_hash(vm, input.as_ptr() as _, input.len(), output_ptr);
183 }
184 assert_eq!(hex::decode(expected).unwrap(), arr);
185
186 unsafe {
187 randomx_destroy_vm(vm);
188 randomx_release_cache(cache);
189 }
190 }
191
192 #[allow(clippy::cast_sign_loss)]
193 #[test]
194 fn calculate_hash_set() {
195 let key = b"test key 000";
196 let input = b"This is a test";
197 let expected = "639183aae1bf4c9a35884cb46b09cad9175f04efd7684e7262a0ac1c2f0b4e3f";
198
199 let input2 = b"Lorem ipsum dolor sit amet";
200 let expected2 = "300a0adb47603dedb42228ccb2b211104f4da45af709cd7547cd049e9489c969";
201
202 let input3 = b"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
203 let expected3 = "c36d4ed4191e617309867ed66a443be4075014e2b061bcdaf9ce7b721d2b77a8";
204
205 let flag: c_uint = 0;
206
207 let arr = [0u8; RANDOMX_HASH_SIZE as usize];
208 let output_ptr = arr.as_ptr() as *mut c_void;
209
210 let cache = unsafe { randomx_alloc_cache(flag) };
211
212 unsafe {
213 randomx_init_cache(cache, key.as_ptr() as _, key.len());
214 }
215
216 let vm = unsafe { randomx_create_vm(flag, cache, ptr::null_mut()) };
217
218 unsafe {
219 randomx_calculate_hash_first(vm, input.as_ptr() as _, input.len());
220 }
221
222 unsafe {
223 randomx_calculate_hash_next(vm, input2.as_ptr() as _, input2.len(), output_ptr);
224 }
225 assert_eq!(hex::decode(expected).unwrap(), arr);
226
227 unsafe {
228 randomx_calculate_hash_next(vm, input3.as_ptr() as _, input3.len(), output_ptr);
229 }
230 assert_eq!(hex::decode(expected2).unwrap(), arr);
231
232 unsafe {
233 randomx_calculate_hash_last(vm, output_ptr);
234 }
235 assert_eq!(hex::decode(expected3).unwrap(), arr);
236
237 unsafe {
238 randomx_destroy_vm(vm);
239 randomx_release_cache(cache);
240 }
241 }
242}