oasis_runtime_sdk/crypto/signature/
context.rs1use std::sync::Mutex;
3
4use once_cell::sync::Lazy;
5
6use oasis_core_runtime::common::{crypto::hash::Hash, namespace::Namespace};
7
8const CHAIN_CONTEXT_SEPARATOR: &[u8] = b" for chain ";
9
10static CHAIN_CONTEXT: Lazy<Mutex<Option<Vec<u8>>>> = Lazy::new(Default::default);
11
12pub fn get_chain_context_for(base: &[u8]) -> Vec<u8> {
26 let guard = CHAIN_CONTEXT.lock().unwrap();
27 let chain_context = match guard.as_ref() {
28 Some(cc) => cc,
29 None => {
30 drop(guard); panic!("chain domain separation context must be configured");
32 }
33 };
34
35 let mut ctx = vec![0; base.len() + CHAIN_CONTEXT_SEPARATOR.len() + chain_context.len()];
36 ctx[..base.len()].copy_from_slice(base);
37 ctx[base.len()..base.len() + CHAIN_CONTEXT_SEPARATOR.len()]
38 .copy_from_slice(CHAIN_CONTEXT_SEPARATOR);
39 ctx[base.len() + CHAIN_CONTEXT_SEPARATOR.len()..].copy_from_slice(chain_context);
40 ctx
41}
42
43pub fn set_chain_context(runtime_id: Namespace, consensus_chain_context: &str) {
56 let ctx = hex::encode(Hash::digest_bytes_list(&[
57 runtime_id.as_ref(),
58 consensus_chain_context.as_bytes(),
59 ]));
60 let mut guard = CHAIN_CONTEXT.lock().unwrap();
61 if let Some(ref existing) = *guard {
62 if cfg!(any(test, feature = "test")) && existing == ctx.as_bytes() {
63 return;
64 }
65 let ex = String::from_utf8(existing.clone()).unwrap();
66 drop(guard); panic!("chain domain separation context already set: {ex}");
68 }
69 *guard = Some(ctx.into_bytes());
70}
71
72#[cfg(any(test, feature = "test"))]
83pub fn test_using_chain_context() -> std::sync::MutexGuard<'static, ()> {
84 static TEST_USING_CHAIN_CONTEXT: Lazy<Mutex<()>> = Lazy::new(Default::default);
85 let guard = TEST_USING_CHAIN_CONTEXT.lock().unwrap();
86 *CHAIN_CONTEXT.lock().unwrap() = None;
87
88 guard
89}
90
91#[cfg(test)]
92mod test {
93 use super::*;
94
95 #[test]
96 fn test_chain_context() {
97 let _guard = test_using_chain_context();
98 set_chain_context(
99 "8000000000000000000000000000000000000000000000000000000000000000".into(),
100 "643fb06848be7e970af3b5b2d772eb8cfb30499c8162bc18ac03df2f5e22520e",
101 );
102
103 let ctx = get_chain_context_for(b"oasis-runtime-sdk/tx: v0");
104 assert_eq!(&String::from_utf8(ctx).unwrap(), "oasis-runtime-sdk/tx: v0 for chain ca4842870b97a6d5c0d025adce0b6a0dec94d2ba192ede70f96349cfbe3628b9");
105 }
106
107 #[test]
108 fn test_chain_context_not_configured() {
109 let _guard = test_using_chain_context();
110
111 let result = std::panic::catch_unwind(|| get_chain_context_for(b"test"));
112 assert!(result.is_err());
113 }
114
115 #[test]
116 fn test_chain_context_already_configured() {
117 let _guard = test_using_chain_context();
118 set_chain_context(
119 "8000000000000000000000000000000000000000000000000000000000000000".into(),
120 "643fb06848be7e970af3b5b2d772eb8cfb30499c8162bc18ac03df2f5e22520e",
121 );
122
123 let result = std::panic::catch_unwind(|| {
124 set_chain_context(
125 "8000000000000000000000000000000000000000000000000000000000000001".into(),
126 "643fb06848be7e970af3b5b2d772eb8cfb30499c8162bc18ac03df2f5e22520e",
127 )
128 });
129 assert!(result.is_err());
130 }
131}