tor_llcrypto/pk/
ed25519.rs

1//! Re-exporting Ed25519 implementations, and related utilities.
2//!
3//! Here we re-export types from [`ed25519_dalek`] that implement the
4//! Ed25519 signature algorithm.  (TODO: Eventually, this module
5//! should probably be replaced with a wrapper that uses the ed25519
6//! trait and the Signature trait.)
7//!
8//! We additionally provide an `Ed25519Identity` type to represent the
9//! unvalidated Ed25519 "identity keys" that we use throughout the Tor
10//! protocol to uniquely identify a relay.
11
12use base64ct::{Base64Unpadded, Encoding as _};
13use curve25519_dalek::Scalar;
14use std::fmt::{self, Debug, Display, Formatter};
15use subtle::{Choice, ConstantTimeEq};
16
17#[cfg(feature = "memquota-memcost")]
18use {derive_deftly::Deftly, tor_memquota::derive_deftly_template_HasMemoryCost};
19
20use ed25519_dalek::hazmat::ExpandedSecretKey;
21use ed25519_dalek::{Signer as _, Verifier as _};
22
23use crate::util::{ct::CtByteArray, rng::RngCompat};
24
25/// An Ed25519 signature.
26///
27/// See [`ed25519_dalek::Signature`] for more information.
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub struct Signature(pub(crate) ed25519_dalek::Signature);
30
31/// An Ed25519 keypair.
32///
33/// (We do not provide a separate "private key only" type.)
34///
35/// See [`ed25519_dalek::SigningKey`] for more information.
36#[derive(Debug)]
37pub struct Keypair(pub(crate) ed25519_dalek::SigningKey);
38
39/// An Ed25519 public key.
40///
41/// See [`ed25519_dalek::SigningKey`] for more information.
42#[derive(Clone, Copy, Debug, Eq, PartialEq)]
43pub struct PublicKey(pub(crate) ed25519_dalek::VerifyingKey);
44
45impl<'a> From<&'a Keypair> for PublicKey {
46    fn from(value: &'a Keypair) -> Self {
47        PublicKey((&value.0).into())
48    }
49}
50
51impl PublicKey {
52    /// Construct a public key from its byte representation.
53    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, signature::Error> {
54        Ok(PublicKey(ed25519_dalek::VerifyingKey::from_bytes(bytes)?))
55    }
56
57    /// Return a reference to the byte representation of this public key.
58    pub fn as_bytes(&self) -> &[u8; 32] {
59        self.0.as_bytes()
60    }
61    /// Return the byte representation of this public key.
62    pub fn to_bytes(&self) -> [u8; 32] {
63        self.0.to_bytes()
64    }
65    /// Verify a signature using this public key.
66    ///
67    /// See [`ed25519_dalek::VerifyingKey::verify`] for more information.
68    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), signature::Error> {
69        self.0.verify(message, &signature.0)
70    }
71}
72impl Keypair {
73    /// Generate a new random ed25519 keypair.
74    pub fn generate<R: rand_core::RngCore + rand_core::CryptoRng>(csprng: &mut R) -> Self {
75        Self(ed25519_dalek::SigningKey::generate(&mut RngCompat::new(
76            csprng,
77        )))
78    }
79    /// Construct an ed25519 keypair from the byte representation of its secret key.
80    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
81        Self(ed25519_dalek::SigningKey::from_bytes(bytes))
82    }
83    /// Return a reference to the byte representation of the secret key in this keypair.
84    pub fn as_bytes(&self) -> &[u8; 32] {
85        self.0.as_bytes()
86    }
87    /// Return to the byte representation of the secret key in this keypair.
88    pub fn to_bytes(&self) -> [u8; 32] {
89        self.0.to_bytes()
90    }
91    /// Return the public key in this keypair.
92    pub fn verifying_key(&self) -> PublicKey {
93        PublicKey(*self.0.as_ref())
94    }
95    /// Verify a signature generated with this keypair.
96    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), signature::Error> {
97        self.0.verify(message, &signature.0)
98    }
99    /// Sign a message using this keypair.
100    pub fn sign(&self, message: &[u8]) -> Signature {
101        Signature(self.0.sign(message))
102    }
103}
104impl Signature {
105    /// Construct this signature from its byte representation.
106    pub fn from_bytes(bytes: &[u8; 64]) -> Self {
107        Self(ed25519_dalek::Signature::from_bytes(bytes))
108    }
109    /// Return the byte representation of this signature.
110    pub fn to_bytes(&self) -> [u8; 64] {
111        self.0.to_bytes()
112    }
113}
114impl<'a> TryFrom<&'a [u8]> for PublicKey {
115    type Error = signature::Error;
116
117    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
118        Ok(Self(ed25519_dalek::VerifyingKey::try_from(value)?))
119    }
120}
121impl<'a> From<&'a [u8; 32]> for Keypair {
122    fn from(value: &'a [u8; 32]) -> Self {
123        Self(ed25519_dalek::SigningKey::from(value))
124    }
125}
126impl From<[u8; 64]> for Signature {
127    fn from(value: [u8; 64]) -> Self {
128        Signature(value.into())
129    }
130}
131impl<'a> From<&'a [u8; 64]> for Signature {
132    fn from(value: &'a [u8; 64]) -> Self {
133        Signature(value.into())
134    }
135}
136
137/// The length of an ED25519 identity, in bytes.
138pub const ED25519_ID_LEN: usize = 32;
139
140/// The length of an ED25519 signature, in bytes.
141pub const ED25519_SIGNATURE_LEN: usize = 64;
142
143/// A variant of [`Keypair`] containing an [`ExpandedSecretKey`].
144///
145/// In the Tor protocol, we use this type for blinded onion service identity keys
146/// (KS_hs_blind_id).  Since their scalar values are computed, rather than taken
147/// directly from a
148/// SHA-512 transformation of a SecretKey, we cannot use the regular `Keypair`
149/// type.
150#[allow(clippy::exhaustive_structs)]
151pub struct ExpandedKeypair {
152    /// The secret part of the key.
153    pub(crate) secret: ExpandedSecretKey,
154    /// The public part of this key.
155    ///
156    /// NOTE: As with [`ed25519_dalek::SigningKey`], this public key _must_ be
157    /// the public key matching `secret`.  Putting a different public key in
158    /// here would enable a class of attacks against ed25519 and enable secret
159    /// key recovery.
160    pub(crate) public: PublicKey,
161}
162
163impl ExpandedKeypair {
164    /// Return the public part of this expanded keypair.
165    pub fn public(&self) -> &PublicKey {
166        &self.public
167    }
168
169    // NOTE: There is deliberately no secret() function.  If we had one, we
170    // would be exposing an unescorted secret key, which is part of
171    // ed25519::hazmat.
172
173    /// Compute a signature over a message using this keypair.
174    pub fn sign(&self, message: &[u8]) -> Signature {
175        use sha2::Sha512;
176        // See notes on ExpandedKeypair about why this hazmat is okay to use.
177        Signature(ed25519_dalek::hazmat::raw_sign::<Sha512>(
178            &self.secret,
179            message,
180            &self.public.0,
181        ))
182    }
183
184    /// Return a representation of the secret key in this keypair.
185    ///
186    /// (Since it is an expanded secret key, we represent it as its scalar part
187    /// followed by its hash_prefix.)
188    pub fn to_secret_key_bytes(&self) -> [u8; 64] {
189        let mut output = [0_u8; 64];
190        output[0..32].copy_from_slice(&self.secret.scalar.to_bytes());
191        output[32..64].copy_from_slice(&self.secret.hash_prefix);
192        output
193    }
194
195    /// Reconstruct a key from its byte representation as returned by
196    /// `to_secret_key_bytes()`.
197    ///
198    /// Return None if the input cannot be the output of `to_secret_key_bytes()`.
199    //
200    // NOTE: Returning None is a bit silly, but that's what Dalek does.
201    pub fn from_secret_key_bytes(bytes: [u8; 64]) -> Option<Self> {
202        let scalar = Option::from(Scalar::from_bytes_mod_order(
203            bytes[0..32].try_into().expect("wrong length on slice"),
204        ))?;
205        let hash_prefix = bytes[32..64].try_into().expect("wrong length on slice");
206        let secret = ExpandedSecretKey {
207            scalar,
208            hash_prefix,
209        };
210        let public = PublicKey((&secret).into());
211        Some(Self { secret, public })
212    }
213
214    // NOTE: There is deliberately no constructor here that takes a (secret,
215    // public) pair.  If there were, you could construct a pair with a
216    // mismatched public key.
217}
218
219impl<'a> From<&'a Keypair> for ExpandedKeypair {
220    fn from(kp: &'a Keypair) -> ExpandedKeypair {
221        ExpandedKeypair {
222            secret: kp.as_bytes().into(),
223            public: kp.into(),
224        }
225    }
226}
227
228impl From<ExpandedKeypair> for PublicKey {
229    fn from(ekp: ExpandedKeypair) -> PublicKey {
230        ekp.public
231    }
232}
233
234/// An unchecked, unvalidated Ed25519 key.
235///
236/// This key is an "identity" in the sense that it identifies (up to) one
237/// Ed25519 key.  It may also represent the identity for a particular entity,
238/// such as a relay or an onion service.
239///
240/// This type is distinct from an Ed25519 [`PublicKey`] for several reasons:
241///  * We're storing it in a compact format, whereas the public key
242///    implementation might want an expanded form for more efficient key
243///    validation.
244///  * This type hasn't checked whether the bytes here actually _are_ a valid
245///    Ed25519 public key.
246#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
247#[cfg_attr(
248    feature = "memquota-memcost",
249    derive(Deftly),
250    derive_deftly(HasMemoryCost)
251)]
252pub struct Ed25519Identity {
253    /// A raw unchecked Ed25519 public key.
254    id: CtByteArray<ED25519_ID_LEN>,
255}
256
257impl Ed25519Identity {
258    /// Construct a new Ed25519 identity from a 32-byte sequence.
259    ///
260    /// This might or might not actually be a valid Ed25519 public key.
261    ///
262    /// ```
263    /// use tor_llcrypto::pk::ed25519::{Ed25519Identity, PublicKey};
264    ///
265    /// let bytes = b"klsadjfkladsfjklsdafkljasdfsdsd!";
266    /// let id = Ed25519Identity::new(*bytes);
267    /// let pk: Result<PublicKey,_> = (&id).try_into();
268    /// assert!(pk.is_ok());
269    ///
270    /// let bytes = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
271    /// let id = Ed25519Identity::new(*bytes);
272    /// let pk: Result<PublicKey,_> = (&id).try_into();
273    /// assert!(pk.is_err());
274    /// ```
275    pub fn new(id: [u8; 32]) -> Self {
276        Ed25519Identity { id: id.into() }
277    }
278    /// If `id` is of the correct length, wrap it in an Ed25519Identity.
279    pub fn from_bytes(id: &[u8]) -> Option<Self> {
280        Some(Ed25519Identity::new(id.try_into().ok()?))
281    }
282    /// Return a reference to the bytes in this key.
283    pub fn as_bytes(&self) -> &[u8] {
284        &self.id.as_ref()[..]
285    }
286}
287
288impl From<[u8; ED25519_ID_LEN]> for Ed25519Identity {
289    fn from(id: [u8; ED25519_ID_LEN]) -> Self {
290        Ed25519Identity::new(id)
291    }
292}
293
294impl From<Ed25519Identity> for [u8; ED25519_ID_LEN] {
295    fn from(value: Ed25519Identity) -> Self {
296        value.id.into()
297    }
298}
299
300impl From<PublicKey> for Ed25519Identity {
301    fn from(pk: PublicKey) -> Self {
302        (&pk).into()
303    }
304}
305
306impl From<&PublicKey> for Ed25519Identity {
307    fn from(pk: &PublicKey) -> Self {
308        // This unwrap is safe because the public key is always 32 bytes
309        // long.
310        Ed25519Identity::from_bytes(pk.as_bytes()).expect("Ed25519 public key had wrong length?")
311    }
312}
313
314impl TryFrom<&Ed25519Identity> for PublicKey {
315    type Error = ed25519_dalek::SignatureError;
316    fn try_from(id: &Ed25519Identity) -> Result<PublicKey, Self::Error> {
317        PublicKey::from_bytes(id.id.as_ref())
318    }
319}
320
321impl TryFrom<Ed25519Identity> for PublicKey {
322    type Error = ed25519_dalek::SignatureError;
323    fn try_from(id: Ed25519Identity) -> Result<PublicKey, Self::Error> {
324        (&id).try_into()
325    }
326}
327
328impl ConstantTimeEq for Ed25519Identity {
329    fn ct_eq(&self, other: &Self) -> Choice {
330        self.id.ct_eq(&other.id)
331    }
332}
333
334impl Display for Ed25519Identity {
335    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
336        write!(f, "{}", Base64Unpadded::encode_string(self.id.as_ref()))
337    }
338}
339
340impl Debug for Ed25519Identity {
341    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
342        write!(f, "Ed25519Identity {{ {} }}", self)
343    }
344}
345
346impl safelog::Redactable for Ed25519Identity {
347    /// Warning: This displays 12 bits of the ed25519 identity, which is
348    /// enough to narrow down a public relay by a great deal.
349    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350        write!(
351            f,
352            "{}…",
353            &Base64Unpadded::encode_string(self.id.as_ref())[..2]
354        )
355    }
356
357    fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358        write!(f, "Ed25519Identity {{ {} }}", self.redacted())
359    }
360}
361
362impl serde::Serialize for Ed25519Identity {
363    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
364    where
365        S: serde::Serializer,
366    {
367        if serializer.is_human_readable() {
368            serializer.serialize_str(&Base64Unpadded::encode_string(self.id.as_ref()))
369        } else {
370            serializer.serialize_bytes(&self.id.as_ref()[..])
371        }
372    }
373}
374
375impl<'de> serde::Deserialize<'de> for Ed25519Identity {
376    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
377    where
378        D: serde::Deserializer<'de>,
379    {
380        if deserializer.is_human_readable() {
381            /// Helper for deserialization
382            struct EdIdentityVisitor;
383            impl<'de> serde::de::Visitor<'de> for EdIdentityVisitor {
384                type Value = Ed25519Identity;
385                fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> fmt::Result {
386                    fmt.write_str("base64-encoded Ed25519 public key")
387                }
388                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
389                where
390                    E: serde::de::Error,
391                {
392                    let bytes = Base64Unpadded::decode_vec(s).map_err(E::custom)?;
393                    Ed25519Identity::from_bytes(&bytes)
394                        .ok_or_else(|| E::custom("wrong length for Ed25519 public key"))
395                }
396            }
397
398            deserializer.deserialize_str(EdIdentityVisitor)
399        } else {
400            /// Helper for deserialization
401            struct EdIdentityVisitor;
402            impl<'de> serde::de::Visitor<'de> for EdIdentityVisitor {
403                type Value = Ed25519Identity;
404                fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> fmt::Result {
405                    fmt.write_str("ed25519 public key")
406                }
407                fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
408                where
409                    E: serde::de::Error,
410                {
411                    Ed25519Identity::from_bytes(bytes)
412                        .ok_or_else(|| E::custom("wrong length for ed25519 public key"))
413                }
414            }
415            deserializer.deserialize_bytes(EdIdentityVisitor)
416        }
417    }
418}
419
420/// An ed25519 signature, plus the document that it signs and its
421/// public key.
422#[derive(Clone, Debug)]
423#[cfg_attr(
424    feature = "memquota-memcost",
425    derive(Deftly),
426    derive_deftly(HasMemoryCost)
427)]
428pub struct ValidatableEd25519Signature {
429    /// The key that allegedly produced the signature
430    #[cfg_attr(feature = "memquota-memcost", deftly(has_memory_cost(copy)))]
431    key: PublicKey,
432    /// The alleged signature
433    #[cfg_attr(feature = "memquota-memcost", deftly(has_memory_cost(copy)))]
434    sig: Signature,
435    /// The entire body of text that is allegedly signed here.
436    ///
437    /// TODO: It's not so good to have this included here; it
438    /// would be better to have a patch to ed25519_dalek to allow
439    /// us to pre-hash the signed thing, and just store a digest.
440    /// We can't use that with the 'prehash' variant of ed25519,
441    /// since that has different constants.
442    entire_text_of_signed_thing: Vec<u8>,
443}
444
445impl ValidatableEd25519Signature {
446    /// Create a new ValidatableEd25519Signature
447    pub fn new(key: PublicKey, sig: Signature, text: &[u8]) -> Self {
448        ValidatableEd25519Signature {
449            key,
450            sig,
451            entire_text_of_signed_thing: text.into(),
452        }
453    }
454
455    /// View the interior of this signature object.
456    pub(crate) fn as_parts(&self) -> (&PublicKey, &Signature, &[u8]) {
457        (&self.key, &self.sig, &self.entire_text_of_signed_thing[..])
458    }
459
460    /// Return a reference to the underlying Signature.
461    pub fn signature(&self) -> &Signature {
462        &self.sig
463    }
464}
465
466impl super::ValidatableSignature for ValidatableEd25519Signature {
467    fn is_valid(&self) -> bool {
468        self.key
469            .verify(&self.entire_text_of_signed_thing[..], &self.sig)
470            .is_ok()
471    }
472
473    fn as_ed25519(&self) -> Option<&ValidatableEd25519Signature> {
474        Some(self)
475    }
476}
477
478/// Perform a batch verification operation on the provided signatures
479///
480/// Return `true` if _every_ signature is valid; otherwise return `false`.
481///
482/// Note that the mathematics for batch validation are slightly
483/// different than those for normal one-signature validation.  Because
484/// of this, it is possible for an ostensible signature that passes
485/// one validation algorithm might fail the other.  (Well-formed
486/// signatures generated by a correct Ed25519 implementation will
487/// always pass both kinds of validation, and an attacker should not
488/// be able to forge a signature that passes either kind.)
489pub fn validate_batch(sigs: &[&ValidatableEd25519Signature]) -> bool {
490    use crate::pk::ValidatableSignature;
491    if sigs.is_empty() {
492        // ed25519_dalek has nonzero cost for a batch-verification of
493        // zero sigs.
494        true
495    } else if sigs.len() == 1 {
496        // Validating one signature in the traditional way is faster.
497        sigs[0].is_valid()
498    } else {
499        let mut ed_msgs = Vec::new();
500        let mut ed_sigs = Vec::new();
501        let mut ed_pks = Vec::new();
502        for ed_sig in sigs {
503            let (pk, sig, msg) = ed_sig.as_parts();
504            ed_sigs.push(sig.0);
505            ed_pks.push(pk.0);
506            ed_msgs.push(msg);
507        }
508        ed25519_dalek::verify_batch(&ed_msgs[..], &ed_sigs[..], &ed_pks[..]).is_ok()
509    }
510}
511
512/// An object that has an Ed25519 [`PublicKey`].
513pub trait Ed25519PublicKey {
514    /// Get the Ed25519 [`PublicKey`].
515    fn public_key(&self) -> PublicKey;
516}
517
518impl Ed25519PublicKey for Keypair {
519    fn public_key(&self) -> PublicKey {
520        Keypair::verifying_key(self)
521    }
522}
523
524/// An object that can generate Ed25519 signatures.
525pub trait Ed25519SigningKey {
526    /// Sign a message with this key.
527    fn sign(&self, message: &[u8]) -> Signature;
528}
529
530impl Ed25519SigningKey for Keypair {
531    fn sign(&self, message: &[u8]) -> Signature {
532        Keypair::sign(self, message)
533    }
534}
535impl Ed25519SigningKey for ExpandedKeypair {
536    fn sign(&self, message: &[u8]) -> Signature {
537        ExpandedKeypair::sign(self, message)
538    }
539}