1#![cfg_attr(not(feature = "std"), no_std)]
2extern crate alloc;
3
4pub mod aes128;
5pub mod aes256;
6#[cfg(target_arch = "x86_64")]
7mod aes256_ni;
8pub mod ed25519;
9pub mod hkdf;
10pub mod hmac;
11pub mod identity;
12pub mod pkcs7;
13pub mod ratchet;
14pub mod sha256;
15#[cfg(target_arch = "x86_64")]
16mod sha256_x2;
17pub mod sha512;
18pub mod stamp_value;
19pub mod token;
20pub mod x25519;
21
22pub trait Rng {
25 fn fill_bytes(&mut self, dest: &mut [u8]);
26}
27
28pub struct FixedRng {
30 bytes: alloc::vec::Vec<u8>,
31 pos: usize,
32}
33
34impl FixedRng {
35 pub fn new(bytes: &[u8]) -> Self {
36 Self {
37 bytes: bytes.to_vec(),
38 pos: 0,
39 }
40 }
41}
42
43impl Rng for FixedRng {
44 fn fill_bytes(&mut self, dest: &mut [u8]) {
45 for b in dest.iter_mut() {
46 *b = self.bytes[self.pos % self.bytes.len()];
47 self.pos += 1;
48 }
49 }
50}
51
52#[cfg(feature = "std")]
56pub struct OsRng;
57
58#[cfg(feature = "std")]
59impl Rng for OsRng {
60 fn fill_bytes(&mut self, dest: &mut [u8]) {
61 #[cfg(target_os = "espidf")]
63 {
64 unsafe {
65 esp_idf_sys::esp_fill_random(
66 dest.as_mut_ptr() as *mut core::ffi::c_void,
67 dest.len(),
68 );
69 }
70 }
71 #[cfg(target_os = "linux")]
72 {
73 let mut rest = dest;
74 while !rest.is_empty() {
75 let n = unsafe { libc::getrandom(rest.as_mut_ptr().cast(), rest.len(), 0) };
77 if n < 0 {
78 let error = std::io::Error::last_os_error();
79 if error.kind() == std::io::ErrorKind::Interrupted {
80 continue;
81 }
82 panic!("getrandom failed: {error}");
83 }
84 rest = &mut rest[n as usize..];
85 }
86 }
87 #[cfg(not(any(target_os = "espidf", target_os = "linux")))]
88 {
89 use std::io::Read;
90 static URANDOM: std::sync::OnceLock<std::fs::File> = std::sync::OnceLock::new();
93 let mut f = URANDOM.get_or_init(|| {
94 std::fs::File::open("/dev/urandom").expect("Failed to open /dev/urandom")
95 });
96 f.read_exact(dest)
97 .expect("Failed to read from /dev/urandom");
98 }
99 }
100}
101
102#[cfg(all(test, feature = "std", not(target_os = "espidf")))]
103mod tests {
104 use super::{OsRng, Rng};
105
106 #[test]
107 fn os_rng_fills_large_and_empty_buffers() {
108 let mut empty = [0u8; 0];
109 OsRng.fill_bytes(&mut empty);
110 let mut large = std::vec![0u8; 1 << 20];
111 OsRng.fill_bytes(&mut large);
112 assert!(large
114 .chunks(1 << 16)
115 .all(|chunk| chunk.iter().any(|&b| b != 0)));
116 }
117
118 #[test]
119 fn os_rng_fills_buffers_from_concurrent_threads() {
120 let draws: std::vec::Vec<[u8; 32]> = (0..8)
121 .map(|_| {
122 std::thread::spawn(|| {
123 let mut out = [0u8; 32];
124 OsRng.fill_bytes(&mut out);
125 out
126 })
127 })
128 .collect::<std::vec::Vec<_>>()
129 .into_iter()
130 .map(|thread| thread.join().unwrap())
131 .collect();
132 for (i, a) in draws.iter().enumerate() {
133 assert_ne!(a, &[0u8; 32]);
134 for b in &draws[i + 1..] {
135 assert_ne!(a, b);
136 }
137 }
138 }
139}
140
141#[cfg(all(
143 any(feature = "x25519-aws-lc", feature = "ed25519-aws-lc"),
144 any(target_arch = "x86_64", target_arch = "aarch64")
145))]
146pub(crate) fn aws_lc_init() {
147 static INIT: std::sync::Once = std::sync::Once::new();
148 INIT.call_once(|| unsafe { aws_lc_sys::CRYPTO_library_init() });
150}