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);