spideroak_crypto/
ed25519.rs1use 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#[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 unsafe { core::mem::transmute::<&[Signature], &[ed25519_dalek::Signature]>(sigs) },
48 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#[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#[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#[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 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}