oasis_core_runtime/common/crypto/
x25519.rs1use anyhow::Result;
3use rand::{rand_core::UnwrapErr, rngs::SysRng};
4use zeroize::{Zeroize, ZeroizeOnDrop};
5
6use super::hash::Hash;
7
8pub const PRIVATE_KEY_LENGTH: usize = 32;
10
11pub const PUBLIC_KEY_LENGTH: usize = 32;
13
14#[derive(Clone, ZeroizeOnDrop)]
16pub struct PrivateKey(pub x25519_dalek::StaticSecret);
17
18impl PrivateKey {
19 pub fn generate() -> Self {
21 let mut rng = UnwrapErr(SysRng);
22 PrivateKey(x25519_dalek::StaticSecret::random_from_rng(&mut rng))
23 }
24
25 pub fn public_key(&self) -> PublicKey {
27 PublicKey(x25519_dalek::PublicKey::from(&self.0))
28 }
29
30 pub fn from_test_seed(seed: String) -> Self {
32 let seed = Hash::digest_bytes(seed.as_bytes());
33 Self::from(seed.0)
34 }
35}
36
37impl From<[u8; PRIVATE_KEY_LENGTH]> for PrivateKey {
38 fn from(bytes: [u8; PRIVATE_KEY_LENGTH]) -> PrivateKey {
40 PrivateKey(x25519_dalek::StaticSecret::from(bytes))
41 }
42}
43
44impl Default for PrivateKey {
45 fn default() -> Self {
46 Self::from([0; PRIVATE_KEY_LENGTH])
47 }
48}
49
50impl AsRef<[u8]> for PrivateKey {
51 fn as_ref(&self) -> &[u8] {
52 self.0.as_ref()
53 }
54}
55
56impl From<PrivateKey> for x25519_dalek::StaticSecret {
57 fn from(sk: PrivateKey) -> Self {
58 sk.0.clone() }
60}
61
62impl From<x25519_dalek::StaticSecret> for PrivateKey {
63 fn from(sk: x25519_dalek::StaticSecret) -> Self {
64 Self(sk)
65 }
66}
67
68impl cbor::Encode for PrivateKey {
69 fn into_cbor_value(self) -> cbor::Value {
70 cbor::to_value(self.0.to_bytes())
71 }
72}
73
74impl cbor::Decode for PrivateKey {
75 fn try_default() -> Result<Self, cbor::DecodeError> {
76 Ok(Default::default())
77 }
78
79 fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
80 let mut bytes: [u8; PRIVATE_KEY_LENGTH] = cbor::Decode::try_from_cbor_value(value)?;
81 let sk = PrivateKey(x25519_dalek::StaticSecret::from(bytes));
82 bytes.zeroize();
83 Ok(sk)
84 }
85}
86
87#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
89pub struct PublicKey(pub x25519_dalek::PublicKey);
90
91impl From<[u8; PUBLIC_KEY_LENGTH]> for PublicKey {
92 fn from(bytes: [u8; PUBLIC_KEY_LENGTH]) -> PublicKey {
94 PublicKey(x25519_dalek::PublicKey::from(bytes))
95 }
96}
97
98impl From<&PrivateKey> for PublicKey {
99 fn from(sk: &PrivateKey) -> PublicKey {
101 PublicKey(x25519_dalek::PublicKey::from(&sk.0))
102 }
103}
104
105impl Default for PublicKey {
106 fn default() -> Self {
107 Self::from([0; PUBLIC_KEY_LENGTH])
108 }
109}
110
111impl AsRef<[u8]> for PublicKey {
112 fn as_ref(&self) -> &[u8] {
113 self.0.as_ref()
114 }
115}
116
117impl From<PublicKey> for x25519_dalek::PublicKey {
118 fn from(pk: PublicKey) -> Self {
119 pk.0
120 }
121}
122
123impl From<x25519_dalek::PublicKey> for PublicKey {
124 fn from(pk: x25519_dalek::PublicKey) -> Self {
125 Self(pk)
126 }
127}
128
129impl cbor::Encode for PublicKey {
130 fn into_cbor_value(self) -> cbor::Value {
131 cbor::to_value(*self.0.as_bytes())
132 }
133}
134
135impl cbor::Decode for PublicKey {
136 fn try_default() -> Result<Self, cbor::DecodeError> {
137 Ok(Default::default())
138 }
139
140 fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
141 let bytes: [u8; PUBLIC_KEY_LENGTH] = cbor::Decode::try_from_cbor_value(value)?;
142 let pk = PublicKey(x25519_dalek::PublicKey::from(bytes));
143 Ok(pk)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use crate::common::crypto::x25519::{PrivateKey, PublicKey, PRIVATE_KEY_LENGTH};
150
151 #[test]
152 fn test_cbor_serialization() {
153 let sk = PrivateKey::from([1; PRIVATE_KEY_LENGTH]);
154 let pk = PublicKey::from(&sk);
155
156 let enc = cbor::to_vec(sk.clone());
158 let dec: PrivateKey = cbor::from_slice(&enc).expect("deserialization should succeed");
159 assert_eq!(
160 sk.0.to_bytes(),
161 dec.0.to_bytes(),
162 "serialization should round-trip"
163 );
164
165 let enc = cbor::to_vec(pk.clone());
167 let dec: PublicKey = cbor::from_slice(&enc).expect("deserialization should succeed");
168 assert_eq!(
169 pk.0.to_bytes(),
170 dec.0.to_bytes(),
171 "serialization should round-trip"
172 );
173 }
174
175 #[test]
176 fn test_zeroize_on_drop() {
177 let private_key_ptr;
179 {
180 let private_key = PrivateKey([10; 32].into());
181 private_key_ptr = private_key.0.as_bytes().as_ptr();
182 }
183
184 unsafe {
187 for i in 0..32 {
188 assert_eq!(*private_key_ptr.add(i), 0);
189 }
190 }
191 }
192}