randomx_rs/
bindings.rs

1// Copyright 2019. The Tari Project
2//
3// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4// following conditions are met:
5//
6// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7// disclaimer.
8//
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10// following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13// products derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23use 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}