Skip to main content

spideroak_crypto/
ed25519.rs

1//! Ed25519 key generation, signatures, and verification using
2//! [ed25519-dalek].
3//!
4//! This module performs *strict* signature verification to
5//! protect against [weak key forgeries][weak-key]. This means
6//! that it might not be interoperable with all Ed25519
7//! implementations.
8//!
9//! [ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek
10//! [weak-key]: https://github.com/dalek-cryptography/ed25519-dalek/tree/58a967f6fb28806a21180c880bbec4fdeb907aef#weak-key-forgery-and-verify_strict
11
12use core::fmt;
13
14use ed25519_dalek as dalek;
15use subtle::{Choice, ConstantTimeEq};
16use typenum::U32;
17
18use crate::{
19    csprng::{Csprng, Random},
20    hex::ToHex,
21    import::{try_import, ExportError, Import, ImportError},
22    keys::{PublicKey, SecretKey, SecretKeyBytes},
23    oid::{consts::ED25519, Identified, Oid},
24    signer::{self, PkError, Signer, SignerError},
25    zeroize::{is_zeroize_on_drop, ZeroizeOnDrop},
26};
27
28/// EdDSA using Ed25519.
29#[derive(Copy, Clone, Debug)]
30pub struct Ed25519;
31
32impl Signer for Ed25519 {
33    type SigningKey = SigningKey;
34    type VerifyingKey = VerifyingKey;
35    type Signature = Signature;
36
37    #[cfg_attr(docsrs, doc(cfg(feature = "ed25519_batch")))]
38    #[cfg(feature = "ed25519_batch")]
39    fn verify_batch(
40        msgs: &[&[u8]],
41        sigs: &[Self::Signature],
42        pks: &[Self::VerifyingKey],
43    ) -> Result<(), SignerError> {
44        dalek::verify_batch(
45            msgs,
46            // SAFETY: [`Signature`] has the same layout as [`dalek::Signature`].
47            unsafe { core::mem::transmute::<&[Signature], &[ed25519_dalek::Signature]>(sigs) },
48            // SAFETY: [`VerifyingKey`] has the same layout as [`dalek::VerifyingKey`].
49            unsafe { core::mem::transmute::<&[VerifyingKey], &[ed25519_dalek::VerifyingKey]>(pks) },
50        )
51        .map_err(|_| SignerError::Verification)
52    }
53}
54
55impl Identified for Ed25519 {
56    const OID: &Oid = ED25519;
57}
58
59/// An Ed25519 signing key.
60#[derive(Clone)]
61pub struct SigningKey(dalek::SigningKey);
62
63impl signer::SigningKey<Ed25519> for SigningKey {
64    fn sign(&self, msg: &[u8]) -> Result<Signature, SignerError> {
65        let sig = dalek::Signer::sign(&self.0, msg);
66        Ok(Signature(sig))
67    }
68
69    fn public(&self) -> Result<VerifyingKey, PkError> {
70        Ok(VerifyingKey(self.0.verifying_key()))
71    }
72}
73
74impl SecretKey for SigningKey {
75    type Size = U32;
76
77    #[inline]
78    fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError> {
79        Ok(SecretKeyBytes::new(self.0.to_bytes().into()))
80    }
81}
82
83impl Random for SigningKey {
84    fn random<R: Csprng>(rng: R) -> Self {
85        let mut sk = dalek::SecretKey::default();
86        rng.fill_bytes(&mut sk);
87        Self(dalek::SigningKey::from_bytes(&sk))
88    }
89}
90
91impl ConstantTimeEq for SigningKey {
92    fn ct_eq(&self, other: &Self) -> Choice {
93        self.0.ct_eq(&other.0)
94    }
95}
96
97impl Import<&[u8; 32]> for SigningKey {
98    fn import(data: &[u8; 32]) -> Result<Self, ImportError> {
99        Ok(Self(dalek::SigningKey::from_bytes(data)))
100    }
101}
102
103impl Import<[u8; 32]> for SigningKey {
104    fn import(data: [u8; 32]) -> Result<Self, ImportError> {
105        Self::import(&data)
106    }
107}
108
109impl Import<&[u8]> for SigningKey {
110    fn import(data: &[u8]) -> Result<Self, ImportError> {
111        try_import(data)
112    }
113}
114
115impl fmt::Debug for SigningKey {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        f.debug_struct("SigningKey").finish_non_exhaustive()
118    }
119}
120
121impl ZeroizeOnDrop for SigningKey {}
122impl Drop for SigningKey {
123    fn drop(&mut self) {
124        is_zeroize_on_drop(&self.0);
125    }
126}
127
128/// An Ed25519 signature verifying key.
129#[derive(Clone, Eq, PartialEq)]
130#[repr(transparent)]
131pub struct VerifyingKey(dalek::VerifyingKey);
132
133impl signer::VerifyingKey<Ed25519> for VerifyingKey {
134    fn verify(&self, msg: &[u8], sig: &Signature) -> Result<(), SignerError> {
135        self.0
136            .verify_strict(msg, &sig.0)
137            .map_err(|_| SignerError::Verification)
138    }
139}
140
141impl PublicKey for VerifyingKey {
142    type Data = [u8; 32];
143
144    fn export(&self) -> Self::Data {
145        self.0.to_bytes()
146    }
147}
148
149impl Import<&[u8; 32]> for VerifyingKey {
150    fn import(data: &[u8; 32]) -> Result<Self, ImportError> {
151        let pk = dalek::VerifyingKey::from_bytes(data).map_err(|_| ImportError::InvalidSyntax)?;
152        Ok(Self(pk))
153    }
154}
155
156impl Import<[u8; 32]> for VerifyingKey {
157    fn import(data: [u8; 32]) -> Result<Self, ImportError> {
158        Self::import(&data)
159    }
160}
161
162impl<'a> Import<&'a [u8]> for VerifyingKey {
163    fn import(data: &'a [u8]) -> Result<Self, ImportError> {
164        try_import(data)
165    }
166}
167
168impl fmt::Debug for VerifyingKey {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        write!(f, "{}", self.export().to_hex())
171    }
172}
173
174/// An Ed25519 signature.
175#[derive(Copy, Clone, Debug, Eq, PartialEq)]
176#[repr(transparent)]
177pub struct Signature(dalek::Signature);
178
179impl signer::Signature<Ed25519> for Signature {
180    type Data = [u8; 64];
181
182    fn export(&self) -> Self::Data {
183        self.0.to_bytes()
184    }
185}
186
187impl Import<&[u8; 64]> for Signature {
188    fn import(data: &[u8; 64]) -> Result<Self, ImportError> {
189        Ok(Signature(dalek::Signature::from_bytes(data)))
190    }
191}
192
193impl Import<[u8; 64]> for Signature {
194    fn import(data: [u8; 64]) -> Result<Self, ImportError> {
195        Self::import(&data)
196    }
197}
198
199impl Import<&[u8]> for Signature {
200    fn import(data: &[u8]) -> Result<Self, ImportError> {
201        try_import(data)
202    }
203}
204
205impl Identified for Signature {
206    const OID: &Oid = ED25519;
207}
208
209impl SigningKey {
210    /// infallible public method
211    pub fn public(&self) -> VerifyingKey {
212        VerifyingKey(self.0.verifying_key())
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219    use crate::test_util::test_signer;
220
221    test_signer!(ed25519, Ed25519, EddsaTest::Ed25519);
222}