oasis_runtime_sdk/crypto/
random.rs1use std::{cell::RefCell, convert::Infallible};
3
4use anyhow::anyhow;
5use merlin::{Transcript, TranscriptRng};
6use rand::{rngs::SysRng, TryCryptoRng, TryRng};
7use rand_core::RngCore;
8use schnorrkel::keys::{ExpansionMode, Keypair, MiniSecretKey};
9
10use oasis_core_runtime::common::crypto::hash::Hash;
11
12use crate::{
13 context::Context, dispatcher, keymanager::KeyManagerError, modules::core::Error, state::Mode,
14};
15
16const RNG_CONTEXT: &[u8] = b"oasis-runtime-sdk/crypto: rng v1";
18const VRF_KEY_CONTEXT: &[u8] = b"oasis-runtime-sdk/crypto: root vrf key v1";
20
21pub struct RootRng {
23 inner: RefCell<Inner>,
24 mode: Mode,
25 valid: bool,
26}
27
28struct Inner {
29 transcript: Transcript,
31 rng: Option<TranscriptRng>,
33}
34
35impl RootRng {
36 pub fn new(mode: Mode) -> Self {
38 Self {
39 inner: RefCell::new(Inner {
40 transcript: Transcript::new(RNG_CONTEXT),
41 rng: None,
42 }),
43 mode,
44 valid: true,
45 }
46 }
47
48 pub fn invalid() -> Self {
50 Self {
51 inner: RefCell::new(Inner {
52 transcript: Transcript::new(&[]),
53 rng: None,
54 }),
55 mode: Mode::Simulate, valid: false,
57 }
58 }
59
60 fn derive_root_vrf_key<C: Context + ?Sized>(ctx: &C, mode: Mode) -> Result<Keypair, Error> {
61 let km = ctx
62 .key_manager()
63 .ok_or(Error::Abort(dispatcher::Error::KeyManagerFailure(
64 KeyManagerError::NotInitialized,
65 )))?;
66 let round_header_hash = ctx.runtime_header().encoded_hash();
67 let key_id = crate::keymanager::get_key_pair_id([
68 VRF_KEY_CONTEXT,
69 &[mode as u8],
70 round_header_hash.as_ref(),
71 ]);
72 let km_kp = km
73 .get_or_create_ephemeral_keys(key_id, ctx.epoch())
74 .map_err(|err| Error::Abort(dispatcher::Error::KeyManagerFailure(err)))?
75 .input_keypair;
76 let kp = MiniSecretKey::from_bytes(km_kp.sk.0.as_ref())
79 .map_err(|err| {
80 Error::Abort(dispatcher::Error::KeyManagerFailure(
81 KeyManagerError::Other(anyhow::anyhow!("{err}")),
82 ))
83 })?
84 .expand_to_keypair(ExpansionMode::Uniform);
85
86 Ok(kp)
87 }
88
89 pub fn append_local_entropy(&self) {
95 if !self.valid {
96 return;
97 }
98
99 let mut bytes = [0u8; 32];
100 SysRng.try_fill_bytes(&mut bytes).unwrap();
101
102 let mut inner = self.inner.borrow_mut();
103 inner.transcript.append_message(b"local-rng", &bytes);
104 }
105
106 pub fn append_tx(&self, tx_hash: Hash) {
108 if !self.valid {
109 return;
110 }
111
112 let mut inner = self.inner.borrow_mut();
113 inner.transcript.append_message(b"tx", tx_hash.as_ref());
114 }
115
116 pub fn append_subcontext(&self) {
118 if !self.valid {
119 return;
120 }
121
122 let mut inner = self.inner.borrow_mut();
123 inner.transcript.append_message(b"subctx", &[]);
124 }
125
126 pub fn fork<C: Context + ?Sized>(&self, ctx: &C, pers: &[u8]) -> Result<LeafRng, Error> {
128 if !self.valid {
129 return Err(Error::InvalidArgument(anyhow!("rng is not available")));
130 }
131
132 let mut inner = self.inner.borrow_mut();
133
134 if inner.rng.is_none() {
136 let root_vrf_key = Self::derive_root_vrf_key(ctx, self.mode)?;
138
139 let rng = root_vrf_key
141 .vrf_create_hash(&mut inner.transcript)
142 .make_merlin_rng(&[]);
143 inner.rng = Some(rng);
144 }
145
146 inner.transcript.append_message(b"fork", pers);
148
149 let rng_builder = inner.transcript.build_rng();
150 let parent_rng = inner.rng.as_mut().expect("rng must be initialized");
151 let rng = rng_builder.finalize(parent_rng);
152
153 Ok(LeafRng(rng))
154 }
155}
156
157pub struct LeafRng(TranscriptRng);
159
160impl TryRng for LeafRng {
161 type Error = Infallible;
162
163 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
164 Ok(self.0.next_u32())
165 }
166
167 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
168 Ok(self.0.next_u64())
169 }
170
171 fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
172 self.0.fill_bytes(dst);
173 Ok(())
174 }
175}
176
177impl TryCryptoRng for LeafRng {}
178
179#[cfg(test)]
180mod test {
181 use super::*;
182
183 use crate::{state::Mode, testing::mock};
184
185 #[test]
186 fn test_rng_basic() {
187 let mut mock = mock::Mock::default();
188 let ctx = mock.create_ctx_for_runtime::<mock::EmptyRuntime>(true);
189
190 let root_rng = RootRng::new(Mode::Execute);
192
193 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
194 let mut bytes1 = [0u8; 32];
195 leaf_rng.try_fill_bytes(&mut bytes1).unwrap();
196
197 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
198 let mut bytes1_1 = [0u8; 32];
199 leaf_rng.try_fill_bytes(&mut bytes1_1).unwrap();
200
201 assert_ne!(bytes1, bytes1_1, "rng should apply domain separation");
202
203 let root_rng = RootRng::new(Mode::Execute);
205
206 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
207 let mut bytes2 = [0u8; 32];
208 leaf_rng.try_fill_bytes(&mut bytes2).unwrap();
209
210 assert_eq!(bytes1, bytes2, "rng should be deterministic");
211
212 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
213 let mut bytes2_1 = [0u8; 32];
214 leaf_rng.try_fill_bytes(&mut bytes2_1).unwrap();
215
216 assert_ne!(bytes2, bytes2_1, "rng should apply domain separation");
217 assert_eq!(bytes1_1, bytes2_1, "rng should be deterministic");
218
219 let root_rng = RootRng::new(Mode::Execute);
221
222 let mut leaf_rng = root_rng
223 .fork(&ctx, b"domsep")
224 .expect("rng fork should work");
225 let mut bytes3 = [0u8; 32];
226 leaf_rng.try_fill_bytes(&mut bytes3).unwrap();
227
228 assert_ne!(bytes2, bytes3, "rng should apply domain separation");
229
230 let root_rng = RootRng::new(Mode::Execute);
232 root_rng
233 .append_tx("0000000000000000000000000000000000000000000000000000000000000001".into());
234
235 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
236 let mut bytes4 = [0u8; 32];
237 leaf_rng.try_fill_bytes(&mut bytes4).unwrap();
238
239 assert_ne!(bytes2, bytes4, "rng should apply domain separation");
240
241 let root_rng = RootRng::new(Mode::Execute);
243 root_rng
244 .append_tx("0000000000000000000000000000000000000000000000000000000000000002".into());
245
246 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
247 let mut bytes5 = [0u8; 32];
248 leaf_rng.try_fill_bytes(&mut bytes5).unwrap();
249
250 assert_ne!(bytes4, bytes5, "rng should apply domain separation");
251
252 let root_rng = RootRng::new(Mode::Execute);
254 root_rng
255 .append_tx("0000000000000000000000000000000000000000000000000000000000000001".into());
256
257 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
258 let mut bytes6 = [0u8; 32];
259 leaf_rng.try_fill_bytes(&mut bytes6).unwrap();
260
261 assert_eq!(bytes4, bytes6, "rng should be deterministic");
262
263 let root_rng = RootRng::new(Mode::Execute);
265 root_rng
266 .append_tx("0000000000000000000000000000000000000000000000000000000000000001".into());
267 root_rng
268 .append_tx("0000000000000000000000000000000000000000000000000000000000000002".into());
269
270 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
271 let mut bytes7 = [0u8; 32];
272 leaf_rng.try_fill_bytes(&mut bytes7).unwrap();
273
274 assert_ne!(bytes4, bytes7, "rng should apply domain separation");
275
276 let root_rng = RootRng::new(Mode::Execute);
278 root_rng
279 .append_tx("0000000000000000000000000000000000000000000000000000000000000001".into());
280 let _ = root_rng.fork(&ctx, &[]).expect("rng fork should work"); root_rng
282 .append_tx("0000000000000000000000000000000000000000000000000000000000000002".into());
283
284 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
285 let mut bytes8 = [0u8; 32];
286 leaf_rng.try_fill_bytes(&mut bytes8).unwrap();
287
288 assert_ne!(bytes7, bytes8, "rng should apply domain separation");
289 assert_ne!(bytes6, bytes8, "rng should apply domain separation");
290 }
291
292 #[test]
293 fn test_rng_fail_nonconfidential() {
294 let mut mock = mock::Mock::default();
295 let ctx = mock.create_ctx_for_runtime::<mock::EmptyRuntime>(false);
296
297 let root_rng = RootRng::new(Mode::Execute);
298 assert!(
299 root_rng.fork(&ctx, &[]).is_err(),
300 "rng fork should fail on non-confidential runtimes"
301 );
302 }
303
304 #[test]
305 fn test_rng_local_entropy() {
306 let mut mock = mock::Mock::default();
307 let ctx = mock.create_ctx_for_runtime::<mock::EmptyRuntime>(true);
308
309 let root_rng = RootRng::new(Mode::Execute);
311
312 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
313 let mut bytes1 = [0u8; 32];
314 leaf_rng.try_fill_bytes(&mut bytes1).unwrap();
315
316 let root_rng = RootRng::new(Mode::Execute);
318 root_rng.append_local_entropy();
319
320 let mut leaf_rng = root_rng.fork(&ctx, &[]).expect("rng fork should work");
321 let mut bytes2 = [0u8; 32];
322 leaf_rng.try_fill_bytes(&mut bytes2).unwrap();
323
324 assert_ne!(bytes1, bytes2, "rng should apply domain separation");
325 }
326
327 #[test]
328 fn test_rng_parent_fork_propagation() {
329 let mut mock = mock::Mock::default();
330 let ctx = mock.create_ctx_for_runtime::<mock::EmptyRuntime>(true);
331
332 let root_rng = RootRng::new(Mode::Execute);
334
335 let mut leaf_rng = root_rng.fork(&ctx, b"a").expect("rng fork should work");
336 let mut bytes1 = [0u8; 32];
337 leaf_rng.try_fill_bytes(&mut bytes1).unwrap();
338
339 let mut leaf_rng = root_rng.fork(&ctx, b"a").expect("rng fork should work");
340 let mut bytes1_1 = [0u8; 32];
341 leaf_rng.try_fill_bytes(&mut bytes1_1).unwrap();
342
343 let root_rng = RootRng::new(Mode::Execute);
345
346 let mut leaf_rng = root_rng.fork(&ctx, b"b").expect("rng fork should work");
347 let mut bytes2 = [0u8; 32];
348 leaf_rng.try_fill_bytes(&mut bytes2).unwrap();
349
350 let mut leaf_rng = root_rng.fork(&ctx, b"a").expect("rng fork should work");
351 let mut bytes2_1 = [0u8; 32];
352 leaf_rng.try_fill_bytes(&mut bytes2_1).unwrap();
353
354 assert_ne!(
355 bytes1_1, bytes2_1,
356 "forks should propagate domain separator to parent"
357 );
358 }
359
360 #[test]
361 fn test_rng_invalid() {
362 let mut mock = mock::Mock::default();
363 let ctx = mock.create_ctx_for_runtime::<mock::EmptyRuntime>(true);
364
365 let root_rng = RootRng::invalid();
366 assert!(
367 root_rng.fork(&ctx, b"a").is_err(),
368 "rng fork should fail for invalid rng"
369 );
370 }
371}