1
//! Public-key cryptography for Tor.
2
//!
3
//! In old places, Tor uses RSA; newer Tor public-key cryptography is
4
//! based on curve25519 and ed25519.
5

            
6
pub mod ed25519;
7
pub mod keymanip;
8
pub mod rsa;
9

            
10
/// Re-exporting Curve25519 implementations.
11
///
12
/// *TODO*: Eventually we should probably recommend using is code via some
13
/// key-agreement trait, but for now we are just re-using the APIs from
14
/// [`x25519_dalek`].
15
pub mod curve25519 {
16
    pub use x25519_dalek::{EphemeralSecret, PublicKey, SharedSecret, StaticSecret};
17
}
18

            
19
/// A type for a validatable signature.
20
///
21
/// It necessarily includes the signature, the public key, and (a hash
22
/// of?) the document being checked.
23
///
24
/// Having this trait enables us to write code for checking a large number
25
/// of validatable signatures in a way that permits batch signatures for
26
/// Ed25519.
27
///
28
/// To be used with [`validate_all_sigs`].
29
pub trait ValidatableSignature {
30
    /// Check whether this signature is a correct signature for the document.
31
    fn is_valid(&self) -> bool;
32

            
33
    /// Return this value as a validatable Ed25519 signature, if it is one.
34
126
    fn as_ed25519(&self) -> Option<&ed25519::ValidatableEd25519Signature> {
35
126
        None
36
126
    }
37
}
38

            
39
/// Check whether all of the signatures in this Vec are valid.
40
///
41
/// Return `true` if every signature is valid; return `false` if even
42
/// one is invalid.
43
///
44
/// This function should typically give the same result as just
45
/// calling `v.iter().all(ValidatableSignature::is_valid))`, while taking
46
/// advantage of batch verification to whatever extent possible.
47
///
48
/// (See [`ed25519::validate_batch`] for caveats.)
49
304
pub fn validate_all_sigs(v: &[Box<dyn ValidatableSignature>]) -> bool {
50
304
    // First we break out the ed25519 signatures (if any) so we can do
51
304
    // a batch-verification on them.
52
304
    let mut ed_sigs = Vec::new();
53
304
    let mut non_ed_sigs = Vec::new();
54
627
    for sig in v.iter() {
55
627
        match sig.as_ed25519() {
56
57
            Some(ed_sig) => ed_sigs.push(ed_sig),
57
570
            None => non_ed_sigs.push(sig),
58
        }
59
    }
60

            
61
    // Find out if the ed25519 batch is valid.
62
304
    let ed_batch_is_valid = crate::pk::ed25519::validate_batch(&ed_sigs[..]);
63
304

            
64
304
    // if so, verify the rest.
65
957
    ed_batch_is_valid && non_ed_sigs.iter().all(|b| b.is_valid())
66
304
}
67

            
68
#[cfg(test)]
69
mod test {
70
    #![allow(clippy::unwrap_used)]
71
    #[test]
72
    fn validatable_ed_sig() {
73
        use super::ed25519::{PublicKey, Signature, ValidatableEd25519Signature};
74
        use super::ValidatableSignature;
75
        use hex_literal::hex;
76
        let pk = PublicKey::from_bytes(&hex!(
77
            "fc51cd8e6218a1a38da47ed00230f058
78
             0816ed13ba3303ac5deb911548908025"
79
        ))
80
        .unwrap();
81
        let sig: Signature = hex!(
82
            "6291d657deec24024827e69c3abe01a3
83
             0ce548a284743a445e3680d7db5ac3ac
84
             18ff9b538d16f290ae67f760984dc659
85
             4a7c15e9716ed28dc027beceea1ec40a"
86
        )
87
        .into();
88

            
89
        let valid = ValidatableEd25519Signature::new(pk, sig, &hex!("af82"));
90
        let invalid = ValidatableEd25519Signature::new(pk, sig, &hex!("af83"));
91

            
92
        assert!(valid.is_valid());
93
        assert!(!invalid.is_valid());
94
    }
95
}