junobuild_shared/
random.rs

1use ic_cdk::management_canister;
2use rand::{rngs::StdRng, SeedableRng};
3
4/// Initializes a [`StdRng`] using 32 bytes of randomness retrieved from the IC management canister.
5///
6/// # Behavior
7///
8/// This function internally calls [`raw_rand()`] to obtain 32 bytes of randomness
9/// from the management canister and uses them as a seed to create a deterministic
10/// random number generator (`StdRng`).
11///
12/// If randomness cannot be retrieved (e.g., due to a call failure), the function
13/// returns `None` instead of blocking initialization. This allows the caller to
14/// proceed with limited functionality.
15///
16/// # Returns
17///
18/// - `Some(StdRng)` if randomness was successfully fetched.
19/// - `None` if the management canister call failed.
20///
21/// # Example
22///
23/// ```ignore
24/// if let Some(mut rng) = get_random_seed().await {
25///     let value: u64 = rng.gen();
26///     println!("Random value: {}", value);
27/// }
28/// ```
29pub async fn get_random_seed() -> Option<StdRng> {
30    let result = raw_rand().await;
31
32    match result {
33        // We do nothing in case of error to not block initialization but, getrandom will throw errors
34        Err(_) => None,
35        Ok(seed) => Some(StdRng::from_seed(seed)),
36    }
37}
38
39/// Retrieves 32 bytes of randomness from the Internet Computer management canister.
40///
41/// # Behavior
42///
43/// Calls the management canister's [`raw_rand`](https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-management-canister)
44/// method, which returns 32 random bytes (256 bits) of cryptographically secure randomness.
45/// These bytes can be used as a seed for random number generators or as a unique salt.
46///
47/// The function performs length validation to ensure the result is exactly 32 bytes.
48///
49/// # Returns
50///
51/// - `Ok([u8; 32])` containing the random seed bytes on success.
52/// - `Err(String)` with an error message if the call failed or returned an unexpected length.
53///
54/// # Example
55///
56/// ```ignore
57/// let seed = raw_rand().await?;
58/// println!("Received 32 bytes of randomness: {:?}", seed);
59/// ```
60pub async fn raw_rand() -> Result<[u8; 32], String> {
61    let bytes = management_canister::raw_rand()
62        .await
63        .map_err(|e| format!("raw_rand failed: {:?}", e))?;
64
65    let seed: [u8; 32] = bytes
66        .as_slice()
67        .try_into()
68        .map_err(|_| format!("raw_rand expected 32 bytes, got {}", bytes.len()))?;
69
70    Ok(seed)
71}