oasis_runtime_sdk/crypto/signature/
ed25519.rs1use std::convert::TryInto;
3
4use base64::prelude::*;
5use curve25519_dalek::{digest::consts::U64, edwards::CompressedEdwardsY};
6use ed25519_dalek::Signer as _;
7use rand_core::{CryptoRng, RngCore};
8use sha2::{Digest as _, Sha512, Sha512_256};
9
10use oasis_core_runtime::common::crypto::signature::{
11 PublicKey as CorePublicKey, Signature as CoreSignature,
12};
13
14use crate::crypto::signature::{Error, Signature, Signer};
15
16#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, cbor::Encode, cbor::Decode)]
18#[cbor(transparent, no_default)]
19pub struct PublicKey(CorePublicKey);
20
21impl PublicKey {
22 pub fn as_bytes(&self) -> &[u8] {
24 self.0.as_ref()
25 }
26
27 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
29 if bytes.len() != CorePublicKey::len() {
31 return Err(Error::MalformedPublicKey);
32 }
33
34 let a = CompressedEdwardsY::from_slice(bytes).unwrap(); let _a = match a.decompress() {
41 Some(point) => point,
42 None => return Err(Error::MalformedPublicKey),
43 };
44
45 Ok(PublicKey(CorePublicKey::from(bytes)))
46 }
47
48 pub fn verify(
50 &self,
51 context: &[u8],
52 message: &[u8],
53 signature: &Signature,
54 ) -> Result<(), Error> {
55 if signature.0.len() != CoreSignature::len() {
57 return Err(Error::MalformedSignature);
58 }
59 let sig: &[u8] = signature.0.as_ref();
60 let sig = CoreSignature::from(sig);
61
62 sig.verify(&self.0, context, message)
63 .map_err(|_| Error::VerificationFailed)
64 }
65
66 pub fn verify_raw(&self, message: &[u8], signature: &Signature) -> Result<(), Error> {
68 if signature.0.len() != CoreSignature::len() {
70 return Err(Error::MalformedSignature);
71 }
72 let sig: &[u8] = signature.0.as_ref();
73 let sig = CoreSignature::from(sig);
74
75 sig.verify_raw(&self.0, message)
76 .map_err(|_| Error::VerificationFailed)
77 }
78
79 pub fn verify_digest<D>(&self, digest: D, signature: &Signature) -> Result<(), Error>
81 where
82 D: ed25519_dalek::Digest<OutputSize = U64>,
83 {
84 let sig: ed25519_dalek::Signature = signature
85 .as_ref()
86 .try_into()
87 .map_err(|_| Error::MalformedSignature)?;
88 let pk: ed25519_dalek::VerifyingKey = self
89 .as_bytes()
90 .try_into()
91 .map_err(|_| Error::MalformedPublicKey)?;
92 pk.verify_prehashed(digest, None, &sig)
93 .map_err(|_| Error::VerificationFailed)
94 }
95}
96
97impl From<&'static str> for PublicKey {
98 fn from(s: &'static str) -> PublicKey {
99 PublicKey::from_bytes(&BASE64_STANDARD.decode(s).unwrap()).unwrap()
100 }
101}
102
103impl From<CorePublicKey> for PublicKey {
104 fn from(pk: CorePublicKey) -> PublicKey {
105 PublicKey(pk)
106 }
107}
108
109impl From<&CorePublicKey> for PublicKey {
110 fn from(pk: &CorePublicKey) -> PublicKey {
111 PublicKey(*pk)
112 }
113}
114
115impl From<PublicKey> for CorePublicKey {
116 fn from(pk: PublicKey) -> CorePublicKey {
117 pk.0
118 }
119}
120
121pub struct MemorySigner {
123 key: Key,
124}
125
126enum Key {
131 Expanded {
132 esk: ed25519_dalek::hazmat::ExpandedSecretKey,
133 hash: zeroize::Zeroizing<[u8; 64]>,
136 },
137 Regular(ed25519_dalek::SigningKey),
138}
139
140impl Key {
141 fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
142 match bytes.len() {
143 32 => bytes
145 .try_into()
146 .map(ed25519_dalek::SigningKey::from_bytes)
147 .map(Self::Regular)
148 .map_err(|_| Error::MalformedPrivateKey),
149 64 => bytes
151 .try_into()
152 .map(|hash| Self::Expanded {
153 esk: ed25519_dalek::hazmat::ExpandedSecretKey::from_bytes(&hash),
154 hash: hash.into(),
155 })
156 .map_err(|_| Error::MalformedPrivateKey),
157 _ => Err(Error::MalformedPrivateKey),
158 }
159 }
160
161 fn to_bytes(&self) -> Vec<u8> {
162 match self {
163 Self::Expanded { hash, .. } => hash.to_vec(),
164 Self::Regular(sk) => sk.to_bytes().to_vec(),
165 }
166 }
167
168 fn sign(&self, message: &[u8]) -> Signature {
169 match self {
170 Self::Expanded { esk, .. } => {
171 let verifying_key = ed25519_dalek::VerifyingKey::from(esk);
172 ed25519_dalek::hazmat::raw_sign::<Sha512>(esk, message, &verifying_key)
173 }
174 Self::Regular(sk) => sk.sign(message),
175 }
176 .to_bytes()
177 .to_vec()
178 .into()
179 }
180
181 fn sign_digest<D>(&self, digest: D) -> Result<Signature, Error>
182 where
183 D: ed25519_dalek::Digest<OutputSize = U64>,
184 {
185 match self {
186 Key::Expanded { esk, .. } => {
187 let verifying_key = ed25519_dalek::VerifyingKey::from(esk);
188 ed25519_dalek::hazmat::raw_sign_prehashed::<Sha512, _>(
189 esk,
190 digest,
191 &verifying_key,
192 None,
193 )
194 }
195 Key::Regular(sk) => sk.sign_prehashed(digest, None),
196 }
197 .map_err(|_| Error::SigningError)
198 .map(|sig| sig.to_bytes().to_vec().into())
199 }
200
201 fn public_key(&self) -> super::PublicKey {
202 let pk = match self {
203 Self::Expanded { esk, .. } => ed25519_dalek::VerifyingKey::from(esk),
204 Self::Regular(sk) => sk.verifying_key(),
205 };
206 super::PublicKey::Ed25519(PublicKey::from_bytes(pk.as_bytes()).unwrap())
207 }
208}
209
210impl MemorySigner {
211 pub fn sign_digest<D>(&self, digest: D) -> Result<Signature, Error>
212 where
213 D: ed25519_dalek::Digest<OutputSize = U64>,
214 {
215 self.key.sign_digest(digest)
216 }
217}
218
219impl Signer for MemorySigner {
220 fn random(rng: &mut (impl RngCore + CryptoRng)) -> Result<Self, Error> {
221 let mut seed = [0u8; 32];
222 rng.fill_bytes(&mut seed);
223 Self::new_from_seed(&seed)
224 }
225
226 fn new_from_seed(seed: &[u8]) -> Result<Self, Error> {
227 if seed.len() != 32 {
228 return Err(Error::MalformedPublicKey);
229 }
230 Self::from_bytes(seed)
231 }
232
233 fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
234 Ok(Self {
235 key: Key::from_bytes(bytes)?,
236 })
237 }
238
239 fn to_bytes(&self) -> Vec<u8> {
240 self.key.to_bytes()
241 }
242
243 fn public_key(&self) -> super::PublicKey {
244 self.key.public_key()
245 }
246
247 fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
248 let mut digest = Sha512_256::new();
249 digest.update(context);
250 digest.update(message);
251 Ok(self.key.sign(&digest.finalize()))
252 }
253
254 fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error> {
255 Ok(self.key.sign(message))
256 }
257}
258
259#[cfg(test)]
260mod test {
261 use super::*;
262
263 #[test]
264 fn legacy_esk_equivalence() {
265 let seed = [42u8; 32];
266 let signer = MemorySigner::new_from_seed(&seed).unwrap();
267
268 let esk = ed25519_dalek::hazmat::ExpandedSecretKey::from(&seed);
269 let esk_hash = Sha512::digest(seed);
270 let esk_signer = MemorySigner::from_bytes(&esk_hash).unwrap();
271
272 let esk_public_key = super::super::PublicKey::Ed25519(
273 PublicKey::from_bytes(&ed25519_dalek::VerifyingKey::from(&esk).to_bytes()).unwrap(),
274 );
275
276 assert_eq!(
277 esk_signer.to_bytes().as_slice(),
278 esk_hash.as_slice(),
279 "esk roundtrip"
280 );
281 assert_eq!(signer.to_bytes(), seed, "sk roundtrip");
282
283 let context = b"tests";
284 let message = b"hello, world!";
285 let digest = Sha512::new().chain_update(context).chain_update(message);
286
287 let sig = signer.sign(context, message).unwrap();
288 let esk_sig = esk_signer.sign(context, message).unwrap();
289 assert_eq!(sig, esk_sig, "sig != esk_sig");
290
291 let raw_sig = signer.sign_raw(message).unwrap();
292 let esk_raw_sig = esk_signer.sign_raw(message).unwrap();
293 assert_eq!(raw_sig, esk_raw_sig, "raw_sig != esk_raw_sig");
294
295 let digest_sig = signer.sign_digest(digest.clone()).unwrap();
296 let esk_digest_sig = esk_signer.sign_digest(digest).unwrap();
297 assert_eq!(digest_sig, esk_digest_sig, "digest_sig != esk_digest_sig");
298
299 assert_eq!(
300 signer.public_key(),
301 esk_public_key,
302 "signer pk != esk_public_key"
303 );
304 assert_eq!(
305 esk_signer.public_key(),
306 esk_public_key,
307 "esk_signer pk != esk_pubic_key"
308 );
309 }
310}