verity_ic/random/
mod.rs

1//! The 'random' submodule provides functionality for initializing and retrieving random numbers for use on the Internet Computer (IC).
2
3// Import necessary modules and traits
4use rand::Rng;
5use std::{cell::RefCell, time::Duration};
6
7use candid::Principal;
8use getrandom::register_custom_getrandom;
9use rand::{rngs::StdRng, RngCore, SeedableRng};
10
11// Thread-local storage for the random number generator
12thread_local! {
13    pub static RNG: RefCell<Option<StdRng>> = RefCell::new(None);
14}
15
16/// Initializes the random number generator for the canister.
17/// This function should be called in the canister's init hook and post-update hook.
18pub fn init_ic_rand() {
19    ic_cdk_timers::set_timer(Duration::from_secs(0), || ic_cdk::spawn(set_rand()));
20    register_custom_getrandom!(custom_getrandom);
21}
22
23/// Retrieves a random number for use in the canister.
24/// Assumes `init_ic_rand` has been called previously.
25pub fn get_random_number() -> u64 {
26    RNG.with(|rng| rng.borrow_mut().as_mut().unwrap().gen())
27}
28
29// Asynchronously sets the random number generator with a seed obtained from the management canister.
30async fn set_rand() {
31    let (seed,) = ic_cdk::call(Principal::management_canister(), "raw_rand", ())
32        .await
33        .unwrap();
34    RNG.with(|rng| {
35        *rng.borrow_mut() = Some(StdRng::from_seed(seed));
36        ic_cdk::println!("rng: {:?}", *rng.borrow());
37    });
38}
39
40// Custom implementation of the getrandom function to fill a buffer with random bytes.
41fn custom_getrandom(buf: &mut [u8]) -> Result<(), getrandom::Error> {
42    RNG.with(|rng| rng.borrow_mut().as_mut().unwrap().fill_bytes(buf));
43    Ok(())
44}