hdk/
random.rs

1use crate::prelude::*;
2
3/// Get N cryptographically strong random bytes.
4///
5/// ```ignore
6/// let five_bytes = random_bytes(5)?;
7/// ```
8///
9/// It's not possible to generate random bytes from inside the wasm guest so the data is provided
10/// by the wasm host which implies operating system specific details re: randomness.
11///
12/// The bytes are cryptographically random in that they are unpredictable, to the quality of what
13/// host environment offers and the crypto implementation within holochain.
14///
15/// The bytes are not "secure" though:
16///
17/// - there's no way to prove that a specific value was the result of random generation or not
18/// - the bytes are open in memory and even (de)serialized several times between the host and guest
19///
20/// The bytes are not a performant or testable way to do statistical analysis (e.g. monte carlo).
21/// Rust provides several seedable PRNG implementations that are fast, repeatable and statistically
22/// high quality even if not suitable for crypto applications. If you need to do anything with
23/// statistics it is usually recommended to generate or provide a seed and then use an appropriate
24/// PRNG from there.
25///
26/// See the rand rust crate
27pub fn random_bytes(number_of_bytes: u32) -> ExternResult<Bytes> {
28    HDK.with(|h| h.borrow().random_bytes(number_of_bytes))
29}
30
31pub trait TryFromRandom {
32    fn try_from_random() -> ExternResult<Self>
33    where
34        Self: Sized;
35}
36
37/// Ideally we wouldn't need to do this with a macro.
38/// All we want is to implement this trait with whatever length our random-bytes-new-types need to
39/// be, but if we use a const on the trait directly we get 'constant expression depends on a
40/// generic parameter'
41macro_rules! impl_try_from_random {
42    ( $t:ty, $bytes:expr ) => {
43        impl TryFromRandom for $t {
44            fn try_from_random() -> $crate::prelude::ExternResult<Self> {
45                $crate::prelude::random_bytes($bytes as u32).map(|bytes| {
46                    // Always a fatal error if our own bytes generation has the wrong length.
47                    assert_eq!($bytes, bytes.len());
48                    let mut inner = [0; $bytes];
49                    inner.copy_from_slice(bytes.as_ref());
50                    Self::from(inner)
51                })
52            }
53        }
54    };
55}
56
57impl_try_from_random!(
58    CapSecret,
59    holochain_zome_types::capability::CAP_SECRET_BYTES
60);