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