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