Skip to main content

vodozemac/types/
ed25519.rs

1// Copyright 2021 Denis Kasak, Damir Jelić
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16
17use base64::decoded_len_estimate;
18use base64ct::Encoding;
19use curve25519_dalek::EdwardsPoint;
20use ed25519_dalek::{
21    PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH, Signature, Signer, SigningKey, VerifyingKey,
22};
23use rand::rng;
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
26use sha2::Sha512;
27use thiserror::Error;
28use zeroize::Zeroize;
29
30use crate::utilities::{base64_decode, base64_encode};
31
32/// Error type describing signature verification failures.
33#[derive(Debug, Error)]
34pub enum SignatureError {
35    /// The signature wasn't valid base64.
36    #[error("The signature couldn't be decoded: {0}")]
37    Base64(#[from] base64::DecodeError),
38    /// The signature failed to be verified.
39    #[error("The signature was invalid: {0}")]
40    Signature(#[from] ed25519_dalek::SignatureError),
41}
42
43/// A struct collecting both a public, and a secret, Ed25519 key.
44#[derive(Deserialize, Serialize)]
45#[serde(try_from = "Ed25519KeypairPickle")]
46#[serde(into = "Ed25519KeypairPickle")]
47pub struct Ed25519Keypair {
48    secret_key: SecretKeys,
49    public_key: Ed25519PublicKey,
50}
51
52struct ExpandedSecretKey {
53    source: Box<[u8; 64]>,
54    inner: Box<ed25519_dalek::hazmat::ExpandedSecretKey>,
55}
56
57impl ExpandedSecretKey {
58    fn from_bytes(bytes: &[u8; 64]) -> Self {
59        let mut source = Box::new([0u8; 64]);
60        source.copy_from_slice(bytes);
61
62        Self { source, inner: ed25519_dalek::hazmat::ExpandedSecretKey::from_bytes(bytes).into() }
63    }
64
65    const fn as_bytes(&self) -> &[u8; 64] {
66        &self.source
67    }
68
69    fn sign(&self, message: &[u8]) -> Signature {
70        ed25519_dalek::hazmat::raw_sign::<Sha512>(&self.inner, message, &self.public_key().0)
71    }
72
73    fn public_key(&self) -> Ed25519PublicKey {
74        let point = EdwardsPoint::mul_base(&self.inner.scalar);
75        Ed25519PublicKey(VerifyingKey::from(point))
76    }
77}
78
79impl Clone for ExpandedSecretKey {
80    fn clone(&self) -> Self {
81        let source = self.source.clone();
82        Self {
83            source,
84            inner: ed25519_dalek::hazmat::ExpandedSecretKey::from_bytes(&self.source).into(),
85        }
86    }
87}
88
89impl Serialize for ExpandedSecretKey {
90    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91    where
92        S: Serializer,
93    {
94        let bytes = self.as_bytes();
95        SerdeBytes::new(bytes).serialize(serializer)
96    }
97}
98
99impl<'d> Deserialize<'d> for ExpandedSecretKey {
100    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101    where
102        D: Deserializer<'d>,
103    {
104        let mut bytes = <SerdeByteBuf>::deserialize(deserializer)?;
105        let length = bytes.len();
106
107        if bytes.len() != 64 {
108            bytes.zeroize();
109
110            Err(serde::de::Error::custom(format!(
111                "Invalid secret key length: expected 64 bytes, got {length}"
112            )))
113        } else {
114            let mut slice = [0u8; 64];
115            slice.copy_from_slice(&bytes);
116
117            let ret = ExpandedSecretKey::from_bytes(&slice);
118
119            slice.zeroize();
120            bytes.zeroize();
121
122            Ok(ret)
123        }
124    }
125}
126
127impl Ed25519Keypair {
128    /// Create a new, random, `Ed25519Keypair`.
129    pub fn new() -> Self {
130        let mut rng = rng();
131        let signing_key = SigningKey::generate(&mut rng);
132
133        Self {
134            public_key: Ed25519PublicKey(signing_key.verifying_key()),
135            secret_key: signing_key.into(),
136        }
137    }
138
139    pub(crate) fn from_unexpanded_key(secret_key: &[u8; 32]) -> Result<Self, crate::KeyError> {
140        let secret_key = SigningKey::from_bytes(secret_key);
141        let public_key = secret_key.verifying_key();
142        Ok(Self { secret_key: secret_key.into(), public_key: Ed25519PublicKey(public_key) })
143    }
144
145    pub(crate) fn unexpanded_secret_key(&self) -> Option<Box<[u8; 32]>> {
146        match &self.secret_key {
147            SecretKeys::Normal(k) => Some(Box::new(k.to_bytes())),
148            SecretKeys::Expanded(_) => None,
149        }
150    }
151
152    #[cfg(feature = "libolm-compat")]
153    pub(crate) fn from_expanded_key(secret_key: &[u8; 64]) -> Result<Self, crate::KeyError> {
154        let secret_key = ExpandedSecretKey::from_bytes(secret_key);
155        let public_key = secret_key.public_key();
156
157        Ok(Self { secret_key: secret_key.into(), public_key })
158    }
159
160    #[cfg(feature = "libolm-compat")]
161    pub(crate) fn expanded_secret_key(&self) -> Box<[u8; 64]> {
162        use std::ops::DerefMut;
163
164        use sha2::Digest;
165
166        let mut expanded = Box::new([0u8; 64]);
167
168        match &self.secret_key {
169            SecretKeys::Normal(k) => {
170                let mut k = k.to_bytes();
171                Sha512::new().chain_update(k).finalize_into(expanded.deref_mut().into());
172
173                k.zeroize();
174            }
175            SecretKeys::Expanded(k) => expanded.copy_from_slice(k.as_bytes()),
176        }
177
178        expanded
179    }
180
181    /// Get the public Ed25519 key of this keypair.
182    pub const fn public_key(&self) -> Ed25519PublicKey {
183        self.public_key
184    }
185
186    /// Sign the given message with our secret key.
187    pub fn sign(&self, message: &[u8]) -> Ed25519Signature {
188        self.secret_key.sign(message)
189    }
190}
191
192impl Default for Ed25519Keypair {
193    fn default() -> Self {
194        Self::new()
195    }
196}
197
198/// An Ed25519 secret key, used to create digital signatures.
199#[derive(Deserialize, Serialize)]
200#[serde(transparent)]
201pub struct Ed25519SecretKey(Box<SigningKey>);
202
203impl Ed25519SecretKey {
204    /// The number of bytes a Ed25519 secret key has.
205    pub const LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
206
207    const BASE64_LENGTH: usize = 43;
208    const PADDED_BASE64_LENGTH: usize = 44;
209
210    /// Create a new random `Ed25519SecretKey`.
211    pub fn new() -> Self {
212        let mut rng = rng();
213        let signing_key = SigningKey::generate(&mut rng);
214        let key = Box::new(signing_key);
215
216        Self(key)
217    }
218
219    /// Get the byte representation of the secret key.
220    ///
221    /// **Warning**: This creates a copy of the key which won't be zeroized, the
222    /// caller of the method needs to make sure to zeroize the returned array.
223    pub fn to_bytes(&self) -> Box<[u8; 32]> {
224        Box::new(self.0.to_bytes())
225    }
226
227    /// Try to create a `Ed25519SecretKey` from a slice of bytes.
228    pub fn from_slice(bytes: &[u8; 32]) -> Self {
229        Self(Box::new(SigningKey::from_bytes(bytes)))
230    }
231
232    /// Convert the secret key to a base64 encoded string.
233    ///
234    /// This can be useful if the secret key needs to be sent over the network
235    /// or persisted.
236    ///
237    /// **Warning**: The string should be zeroized after it has been used,
238    /// otherwise an unintentional copy of the key might exist in memory.
239    pub fn to_base64(&self) -> String {
240        let mut bytes = self.to_bytes();
241        let ret = base64ct::Base64Unpadded::encode_string(bytes.as_ref());
242
243        bytes.zeroize();
244
245        ret
246    }
247
248    /// Try to create a `Ed25519SecretKey` from a base64 encoded string.
249    pub fn from_base64(input: &str) -> Result<Self, crate::KeyError> {
250        if input.len() != Self::BASE64_LENGTH && input.len() != Self::PADDED_BASE64_LENGTH {
251            Err(crate::KeyError::InvalidKeyLength {
252                key_type: "Ed25519",
253                expected_length: ed25519_dalek::SECRET_KEY_LENGTH,
254                length: decoded_len_estimate(input.len()),
255            })
256        } else {
257            // Ed25519 secret keys can sometimes be encoded with padding, don't
258            // ask me why. This means that if the unpadded decoding
259            // fails, we have to attempt the padded one.
260            let mut bytes = if let Ok(bytes) = base64ct::Base64Unpadded::decode_vec(input) {
261                bytes
262            } else {
263                base64ct::Base64::decode_vec(input)?
264            };
265
266            let result = if bytes.len() == ed25519_dalek::SECRET_KEY_LENGTH {
267                let mut key_bytes = [0u8; ed25519_dalek::SECRET_KEY_LENGTH];
268                key_bytes.copy_from_slice(&bytes);
269                let key = Self::from_slice(&key_bytes);
270                key_bytes.zeroize();
271
272                Ok(key)
273            } else {
274                Err(crate::KeyError::InvalidKeyLength {
275                    key_type: "Ed25519",
276                    expected_length: ed25519_dalek::SECRET_KEY_LENGTH,
277                    length: bytes.len(),
278                })
279            };
280
281            bytes.zeroize();
282            result
283        }
284    }
285
286    /// Get the public key that matches this `Ed25519SecretKey`.
287    pub fn public_key(&self) -> Ed25519PublicKey {
288        Ed25519PublicKey(self.0.verifying_key())
289    }
290
291    /// Sign the given slice of bytes with this `Ed25519SecretKey`.
292    ///
293    /// The signature can be verified using the public key.
294    ///
295    /// # Examples
296    ///
297    /// ```
298    /// use vodozemac::{Ed25519SecretKey, Ed25519PublicKey};
299    ///
300    /// let secret = Ed25519SecretKey::new();
301    /// let message = "It's dangerous to go alone";
302    ///
303    /// let signature = secret.sign(message.as_bytes());
304    ///
305    /// let public_key = secret.public_key();
306    ///
307    /// public_key.verify(message.as_bytes(), &signature).expect("The signature has to be valid");
308    /// ```
309    pub fn sign(&self, message: &[u8]) -> Ed25519Signature {
310        Ed25519Signature(self.0.sign(message))
311    }
312}
313
314impl Default for Ed25519SecretKey {
315    fn default() -> Self {
316        Self::new()
317    }
318}
319
320#[derive(Serialize, Deserialize)]
321enum SecretKeys {
322    Normal(Box<SigningKey>),
323    Expanded(Box<ExpandedSecretKey>),
324}
325
326impl SecretKeys {
327    fn public_key(&self) -> Ed25519PublicKey {
328        match &self {
329            SecretKeys::Normal(k) => Ed25519PublicKey(k.verifying_key()),
330            SecretKeys::Expanded(k) => k.public_key(),
331        }
332    }
333
334    fn sign(&self, message: &[u8]) -> Ed25519Signature {
335        let signature = match &self {
336            SecretKeys::Normal(k) => k.sign(message),
337            SecretKeys::Expanded(k) => k.sign(message),
338        };
339
340        Ed25519Signature(signature)
341    }
342}
343
344/// An Ed25519 public key, used to verify digital signatures.
345#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
346#[serde(transparent)]
347pub struct Ed25519PublicKey(VerifyingKey);
348
349impl Ed25519PublicKey {
350    /// The number of bytes a Ed25519 public key has.
351    pub const LENGTH: usize = PUBLIC_KEY_LENGTH;
352
353    const BASE64_LENGTH: usize = 43;
354    const PADDED_BASE64_LENGTH: usize = 44;
355
356    /// Try to create a `Ed25519PublicKey` from a slice of bytes.
357    pub fn from_slice(bytes: &[u8; 32]) -> Result<Self, crate::KeyError> {
358        Ok(Self(VerifyingKey::from_bytes(bytes).map_err(SignatureError::from)?))
359    }
360
361    /// View this public key as a byte array.
362    pub fn as_bytes(&self) -> &[u8; Self::LENGTH] {
363        self.0.as_bytes()
364    }
365
366    /// Instantiate a Ed25519PublicKey public key from an unpadded base64
367    /// representation.
368    pub fn from_base64(input: &str) -> Result<Self, crate::KeyError> {
369        if input.len() != Self::BASE64_LENGTH && input.len() != Self::PADDED_BASE64_LENGTH {
370            Err(crate::KeyError::InvalidKeyLength {
371                key_type: "Ed25519",
372                expected_length: Self::LENGTH,
373                length: decoded_len_estimate(input.len()),
374            })
375        } else {
376            let mut bytes = base64_decode(input)?;
377            let mut key_bytes = [0u8; Self::LENGTH];
378
379            if bytes.len() == Self::LENGTH {
380                key_bytes.copy_from_slice(&bytes);
381                let key = Self::from_slice(&key_bytes);
382
383                bytes.zeroize();
384                key_bytes.zeroize();
385
386                key
387            } else {
388                Err(crate::KeyError::InvalidKeyLength {
389                    key_type: "Ed25519",
390                    expected_length: Self::LENGTH,
391                    length: bytes.len(),
392                })
393            }
394        }
395    }
396
397    /// Serialize a Ed25519PublicKey public key to an unpadded base64
398    /// representation.
399    pub fn to_base64(&self) -> String {
400        base64_encode(self.as_bytes())
401    }
402
403    /// Verify that the provided signature for a given message has been signed
404    /// by the private key matching this public one.
405    #[cfg(not(fuzzing))]
406    pub fn verify(
407        &self,
408        message: &[u8],
409        signature: &Ed25519Signature,
410    ) -> Result<(), SignatureError> {
411        Ok(self.0.verify_strict(message, &signature.0)?)
412    }
413
414    /// Fuzzing-only stub of verify().
415    #[cfg(fuzzing)]
416    pub fn verify(
417        &self,
418        _message: &[u8],
419        _signature: &Ed25519Signature,
420    ) -> Result<(), SignatureError> {
421        Ok(())
422    }
423}
424
425impl Display for Ed25519PublicKey {
426    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427        write!(f, "{}", self.to_base64())
428    }
429}
430
431impl std::fmt::Debug for Ed25519PublicKey {
432    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433        let s = format!("ed25519:{self}");
434        <str as std::fmt::Debug>::fmt(&s, f)
435    }
436}
437
438/// An Ed25519 digital signature, can be used to verify the authenticity of a
439/// message.
440#[derive(Clone, Copy, PartialEq, Eq)]
441pub struct Ed25519Signature(pub(crate) Signature);
442
443impl Ed25519Signature {
444    /// The number of bytes a Ed25519 signature has.
445    pub const LENGTH: usize = SIGNATURE_LENGTH;
446
447    /// Try to create a `Ed25519Signature` from a slice of bytes.
448    pub fn from_slice(bytes: &[u8]) -> Result<Self, SignatureError> {
449        Ok(Self(Signature::try_from(bytes)?))
450    }
451
452    /// Try to create a `Ed25519Signature` from an unpadded base64
453    /// representation.
454    pub fn from_base64(signature: &str) -> Result<Self, SignatureError> {
455        Ok(Self(Signature::try_from(base64_decode(signature)?.as_slice())?))
456    }
457
458    /// Serialize an `Ed25519Signature` to an unpadded base64 representation.
459    pub fn to_base64(&self) -> String {
460        base64_encode(self.0.to_bytes())
461    }
462
463    /// Convert the `Ed25519Signature` to a byte array.
464    pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
465        self.0.to_bytes()
466    }
467}
468
469impl Display for Ed25519Signature {
470    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
471        write!(f, "{}", self.to_base64())
472    }
473}
474
475impl std::fmt::Debug for Ed25519Signature {
476    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
477        let s = format!("ed25519:{self}");
478        <str as std::fmt::Debug>::fmt(&s, f)
479    }
480}
481
482impl Clone for Ed25519Keypair {
483    fn clone(&self) -> Self {
484        let secret_key: SecretKeys = match &self.secret_key {
485            SecretKeys::Normal(k) => SecretKeys::Normal(k.clone()),
486            SecretKeys::Expanded(k) => SecretKeys::Expanded(k.clone()),
487        };
488
489        Self { secret_key, public_key: self.public_key }
490    }
491}
492
493impl From<Ed25519Keypair> for Ed25519KeypairPickle {
494    fn from(key: Ed25519Keypair) -> Self {
495        Self(key.secret_key)
496    }
497}
498
499impl From<SigningKey> for SecretKeys {
500    fn from(key: SigningKey) -> Self {
501        Self::Normal(Box::new(key))
502    }
503}
504
505impl From<ExpandedSecretKey> for SecretKeys {
506    fn from(key: ExpandedSecretKey) -> Self {
507        Self::Expanded(Box::new(key))
508    }
509}
510
511#[derive(Serialize, Deserialize)]
512#[serde(transparent)]
513pub struct Ed25519KeypairPickle(SecretKeys);
514
515impl From<Ed25519KeypairPickle> for Ed25519Keypair {
516    fn from(pickle: Ed25519KeypairPickle) -> Self {
517        let secret_key = pickle.0;
518        let public_key = secret_key.public_key();
519
520        Self { secret_key, public_key }
521    }
522}
523
524#[cfg(test)]
525mod tests {
526    use std::assert_matches;
527
528    use super::ExpandedSecretKey;
529    use crate::{Ed25519Keypair, Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature, KeyError};
530
531    #[test]
532    fn byte_decoding_roundtrip_succeeds_for_secret_key() {
533        let bytes = *b"oooooooooooooooooooooooooooooooo";
534        let key = Ed25519SecretKey::from_slice(&bytes);
535        assert_eq!(*(key.to_bytes()), bytes);
536    }
537
538    #[test]
539    fn base_64_decoding_too_long_unpadded_secret_key_fails() {
540        let base64 = "MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEE";
541        assert!(matches!(
542            Ed25519SecretKey::from_base64(base64),
543            Err(KeyError::InvalidKeyLength { expected_length: 32, length: 33, .. })
544        ));
545    }
546
547    #[test]
548    fn base_64_decoding_too_short_unpadded_secret_key_fails() {
549        let base64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
550        assert!(matches!(
551            Ed25519SecretKey::from_base64(base64),
552            Err(KeyError::InvalidKeyLength { expected_length: 32, length: 31, .. })
553        ));
554    }
555
556    #[test]
557    fn base64_decoding_incorrect_num_of_bytes_fails_for_secret_key() {
558        assert!(matches!(
559            Ed25519SecretKey::from_base64("foo"),
560            Err(KeyError::InvalidKeyLength { .. })
561        ));
562    }
563
564    #[test]
565    fn unpadded_base64_decoding_roundtrip_succeeds_for_secret_key() {
566        let base64 = "MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE";
567        let key = Ed25519SecretKey::from_base64(base64).expect("Should decode key from base64");
568        assert_eq!(key.to_base64(), base64);
569    }
570
571    #[test]
572    fn padded_base64_decoding_roundtrip_succeeds_for_secret_key() {
573        let base64 = "MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE=";
574        let key = Ed25519SecretKey::from_base64(base64).expect("Should decode key from base64");
575        assert_eq!(key.to_base64(), base64.trim_end_matches('='));
576    }
577
578    #[test]
579    fn byte_decoding_roundtrip_succeeds_for_public_key() {
580        let bytes = *b"oooooooooooooooooooooooooooooooo";
581        let key = Ed25519PublicKey::from_slice(&bytes).expect("Should decode key from bytes");
582        assert_eq!(key.as_bytes(), &bytes);
583    }
584
585    #[test]
586    fn base64_decoding_incorrect_num_of_bytes_fails_for_public_key() {
587        assert_matches!(
588            Ed25519PublicKey::from_base64("foo"),
589            Err(KeyError::InvalidKeyLength { .. })
590        );
591    }
592
593    #[test]
594    fn base_64_decoding_too_long_unpadded_public_key_fails() {
595        let base64 = "b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb288";
596        assert_matches!(
597            Ed25519PublicKey::from_base64(base64),
598            Err(KeyError::InvalidKeyLength { expected_length: 32, length: 33, .. })
599        )
600    }
601
602    #[test]
603    fn base_64_decoding_too_short_unpadded_public_key_fails() {
604        let base64 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
605        assert_matches!(
606            Ed25519PublicKey::from_base64(base64),
607            Err(KeyError::InvalidKeyLength { expected_length: 32, length: 31, .. })
608        )
609    }
610
611    #[test]
612    fn unpadded_base64_decoding_roundtrip_succeeds_for_public_key() {
613        let base64 = "b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28";
614        let key = Ed25519PublicKey::from_base64(base64).expect("Should decode key from base64");
615        assert_eq!(key.to_base64(), base64);
616    }
617
618    #[test]
619    fn padded_base64_decoding_roundtrip_succeeds_for_public_key() {
620        let base64 = "b29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28=";
621        let key = Ed25519PublicKey::from_base64(base64).expect("Should decode key from base64");
622        assert_eq!(key.to_base64(), base64.trim_end_matches('='));
623    }
624
625    #[test]
626    fn verifying_valid_signature_succeeds() {
627        let key_pair = Ed25519Keypair::new();
628        let signature = key_pair.secret_key.sign(b"foo");
629        key_pair.public_key().verify(b"foo", &signature).expect("Should verify valid signature");
630    }
631
632    #[test]
633    fn verifying_invalid_signature_fails() {
634        let key_pair = Ed25519Keypair::new();
635        let signature = key_pair.secret_key.sign(b"foo");
636        key_pair
637            .public_key()
638            .verify(b"bar", &signature)
639            .expect_err("Should reject invalid signature");
640    }
641
642    #[test]
643    #[cfg(feature = "libolm-compat")]
644    fn can_only_expand_secret_key_once() {
645        let key_pair = Ed25519Keypair::new();
646        assert!(matches!(key_pair.secret_key, crate::types::ed25519::SecretKeys::Normal(_)));
647
648        let expanded_key = key_pair.expanded_secret_key();
649        let expanded_key_pair = Ed25519Keypair::from_expanded_key(&expanded_key).unwrap();
650        assert!(matches!(
651            expanded_key_pair.secret_key,
652            crate::types::ed25519::SecretKeys::Expanded(_)
653        ));
654        assert_eq!(expanded_key_pair.public_key(), key_pair.public_key());
655
656        let reexpanded_key = expanded_key_pair.expanded_secret_key();
657        assert_eq!(reexpanded_key, expanded_key);
658    }
659
660    #[test]
661    fn serialization_roundtrip_succeeds() {
662        let bytes = b"9999999999999999999999999999999999999999999999999999999999999999";
663        let key = ExpandedSecretKey::from_bytes(bytes);
664        let serialized = serde_json::to_value(key).expect("Should serialize key");
665        let deserialized = serde_json::from_value::<ExpandedSecretKey>(serialized)
666            .expect("Should deserialize key");
667        assert_eq!(deserialized.as_bytes(), bytes);
668    }
669
670    #[test]
671    fn deserializing_from_invalid_length_fails() {
672        let serialized = serde_json::to_value(b"foo").expect("Should serialize key");
673        let deserialized = serde_json::from_value::<ExpandedSecretKey>(serialized);
674        assert!(deserialized.is_err());
675    }
676
677    #[test]
678    fn unexpanded_key_roundtrip_succeeds() {
679        let key_pair = Ed25519Keypair::new();
680
681        let unexpanded_key = key_pair.unexpanded_secret_key().expect("Should have unexpanded key");
682        let recovered_key_pair = Ed25519Keypair::from_unexpanded_key(unexpanded_key.as_ref())
683            .expect("Should create new keypair");
684
685        assert_eq!(key_pair.public_key().to_base64(), recovered_key_pair.public_key().to_base64());
686    }
687
688    #[test]
689    fn snapshot_public_key_debug() {
690        let public_key = Ed25519PublicKey::from_slice(&[0; 32])
691            .expect("We should be able to create a public key from zero bytes");
692
693        insta::assert_debug_snapshot!(public_key)
694    }
695
696    #[test]
697    fn snapshot_signature_debug() {
698        let signature = Ed25519Signature::from_slice(&[0; 64])
699            .expect("We should be able to create a public key from zero bytes");
700
701        insta::assert_debug_snapshot!(signature)
702    }
703}