1
//! Macros that can be used to improve your life with regards to crypto.
2

            
3
use derive_deftly::define_derive_deftly;
4

            
5
// NOTE: We will require a define_rsa_keypair for the future so the relay legacy RSA keys can be
6
// declared.
7

            
8
/// Create an ed25519 keypair wrapper given a visibility and a struct name.
9
///
10
/// # Syntax:
11
/// ```rust,ignore
12
/// define_ed25519_keypair(<visibility> <prefix>)
13
/// ```
14
///
15
/// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
16
/// cryptographic keypair for an ed25519 keypair. It derives the deftly Ed25519Keypair template
17
/// which in turn creates `<prefix>PublicKey` along a series of useful methods.
18
///
19
/// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
20
///
21
/// # Example:
22
///
23
/// ```rust
24
/// use tor_key_forge::define_ed25519_keypair;
25
///
26
/// define_ed25519_keypair!(NonPublicSigning);
27
/// define_ed25519_keypair!(pub PublicSigning);
28
/// define_ed25519_keypair!(pub(crate) CratePublicSigning);
29
/// ```
30
///
31
/// The above results in `NonPublicSigningKeypair` and `NonPublicSigningPublicKey` struct being
32
/// created and usable with a series of useful methods. Same for the other defines.
33
///
34
/// You can then use these objects like so:
35
///
36
/// ```rust
37
/// # use tor_llcrypto::rng::FakeEntropicRng;
38
/// # let mut rng = FakeEntropicRng(rand::rng());
39
/// use rand::Rng;
40
/// use tor_key_forge::Keygen;
41
/// use tor_key_forge::define_ed25519_keypair;
42
/// use tor_llcrypto::pk::ValidatableSignature;
43
/// use tor_llcrypto::pk::ed25519::Ed25519SigningKey;
44
///
45
/// define_ed25519_keypair!(
46
///     /// Our signing key.
47
///     MySigning
48
/// );
49
///
50
/// let signing_kp = MySigningKeypair::generate(&mut rng).expect("Invalid keygen");
51
/// let signing_pubkey = signing_kp.public();
52
/// // Lets sign this wonderful message.
53
/// let message = "Workers want rights, not your opinion".as_bytes();
54
/// let sig = signing_kp.sign(&message);
55
///
56
/// // You can then verify either directly with the keypair or the public key.
57
/// assert!(signing_kp.verify(sig, &message));
58
/// assert!(signing_pubkey.verify(sig, &message));
59
/// ```
60
#[macro_export]
61
macro_rules! define_ed25519_keypair {
62
    ($(#[ $docs_and_attrs:meta ])*
63
     $vis:vis $base_name:ident) => {
64
        $crate::macro_deps::paste! {
65
            #[derive($crate::derive_deftly::Deftly)]
66
            #[derive_deftly($crate::macro_deps::Ed25519Keypair)]
67
            #[deftly(kp(pubkey = $base_name "PublicKey"))]
68
            #[non_exhaustive]
69
            $(#[ $docs_and_attrs ])*
70
            $vis struct [<$base_name "Keypair">]($crate::macro_deps::ed25519::Keypair);
71
        }
72
    };
73
}
74

            
75
define_derive_deftly! {
76
    /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
77
    export Ed25519Keypair for struct:
78

            
79
    // Enforce that the object has a single field. We want to avoid the implementer to start
80
    // storing metadata or other things in this object that is meant specifically to be
81
    // a semantic wrapper around an Ed25519 keypair.
82
    ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
83

            
84
    ${define KP_NAME $( $fname )}
85
    ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
86

            
87
    /// Public key component of this keypair. Useful if we move the public key around,
88
    /// it then keeps it semantic with the name and less prone to errors.
89
    #[derive(Clone, Debug, PartialEq, Eq)]
90
    #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
91
    #[non_exhaustive]
92
    $tvis struct $PK_NAME ($tvis $crate::macro_deps::ed25519::PublicKey);
93

            
94
    impl $PK_NAME {
95
        /// Verify the signature of a given message.
96
        #[allow(unused)]
97
        $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
98
            use $crate::macro_deps::ValidatableSignature;
99
            $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(self.0, sig, text).is_valid()
100
        }
101
    }
102

            
103
    impl $crate::macro_deps::ed25519::Ed25519PublicKey for $PK_NAME {
104
        fn public_key(&self) -> $crate::macro_deps::ed25519::PublicKey {
105
            self.0
106
        }
107
    }
108

            
109
    // We don't expect all implementations to use all code.
110
    #[allow(unused)]
111
    impl $ttype {
112
        /// Build the raw inner public key into the wrapper public key object.
113
2
        $tvis fn public(&self) -> $PK_NAME {
114
            $PK_NAME((&self.$KP_NAME).into())
115
        }
116
        /// Verify the signature of a given message.
117
4
        $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
118
            use $crate::macro_deps::ValidatableSignature;
119
            $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(
120
                self.0.verifying_key(), sig, text
121
            ).is_valid()
122
        }
123
        /// Return a Ed25519Identity built from this keypair.
124
        $tvis fn to_ed25519_id(&self) -> $crate::macro_deps::ed25519::Ed25519Identity {
125
            $crate::macro_deps::ed25519::Ed25519Identity::from(&self.public().0)
126
        }
127
    }
128

            
129
    impl From<$crate::macro_deps::ed25519::Keypair> for $ttype {
130
        fn from(kp: $crate::macro_deps::ed25519::Keypair) -> Self {
131
            Self(kp)
132
        }
133
    }
134
    impl $crate::macro_deps::ed25519::Ed25519PublicKey for $ttype {
135
        fn public_key(&self) -> $crate::macro_deps::ed25519::PublicKey {
136
            self.0.public_key()
137
        }
138
    }
139

            
140
    impl $crate::macro_deps::ed25519::Ed25519SigningKey for $ttype {
141
2
        fn sign(
142
2
            &self,
143
2
            msg: &[u8])
144
2
        -> $crate::macro_deps::ed25519::Signature {
145
            self.0.sign(msg)
146
        }
147
    }
148

            
149
    /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
150
    /// in a keystore.
151

            
152
    impl $crate::ItemType for $ttype {
153
        fn item_type() -> $crate::KeystoreItemType {
154
            $crate::KeyType::Ed25519Keypair.into()
155
        }
156
    }
157

            
158
    impl $crate::EncodableItem for $ttype {
159
        fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
160
            self.$KP_NAME.as_keystore_item()
161
        }
162
    }
163

            
164
    impl $crate::ToEncodableKey for $ttype {
165
        type Key = $crate::macro_deps::ed25519::Keypair;
166
        type KeyPair = $ttype;
167

            
168
        fn to_encodable_key(self) -> Self::Key {
169
            self.$KP_NAME
170
        }
171
        fn from_encodable_key(key: Self::Key) -> Self {
172
            Self(key)
173
        }
174
    }
175

            
176
    impl $crate::Keygen for $ttype {
177
2
        fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
178
2
        where
179
2
            Self: Sized
180
2
        {
181
            Ok(Self { $KP_NAME: $crate::macro_deps::ed25519::Keypair::generate(&mut rng) })
182
        }
183
    }
184
}
185

            
186
/// Create a curve25519 keypair wrapper given a visibility and a struct name.
187
///
188
/// # Syntax:
189
/// ```rust,ignore
190
/// define_curve25519_keypair(<visibility> <prefix>)
191
/// ```
192
///
193
/// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
194
/// cryptographic keypair for a curve25519 keypair. It derives the deftly Curve25519Keypair template
195
/// which in turn creates `<prefix>PublicKey` along a series of useful methods.
196
///
197
/// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
198
///
199
/// # Example:
200
///
201
/// ```rust
202
/// use tor_key_forge::define_curve25519_keypair;
203
///
204
/// define_curve25519_keypair!(NonPublicEnc);
205
/// define_curve25519_keypair!(pub PublicEnc);
206
/// define_curve25519_keypair!(pub(crate) CratePublicEnc);
207
/// ```
208
///
209
/// The above results in `NonPublicEncKeypair` and `NonPublicEncPublicKey` struct being created and
210
/// usable with a series of useful methods.
211
///
212
/// You can then use these objects like so:
213
///
214
/// ```rust
215
/// # use tor_llcrypto::rng::FakeEntropicRng;
216
/// # let mut rng = FakeEntropicRng(rand::rng());
217
/// # use rand::Rng;
218
/// use tor_key_forge::define_curve25519_keypair;
219
/// use tor_key_forge::Keygen;
220
///
221
/// define_curve25519_keypair!(
222
///     // This is Alice's keypair.
223
///     AliceEnc
224
/// );
225
/// define_curve25519_keypair!(BobEnc);
226
///
227
/// let alice_kp = AliceEncKeypair::generate(&mut rng).expect("Failed alice keygen");
228
/// let bob_kp = BobEncKeypair::generate(&mut rng).expect("Failed bob keygen");
229
///
230
/// // Using the public key wrapper
231
/// let alice_shared_secret = alice_kp.diffie_hellman(bob_kp.public());
232
/// // Using the direct curve25519::PublicKey.
233
/// let bob_shared_secret = bob_kp.diffie_hellman(&alice_kp.public().0);
234
///
235
/// assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());
236
/// ```
237
#[macro_export]
238
macro_rules! define_curve25519_keypair {
239
    ($(#[ $docs_and_attrs:meta ])*
240
    $vis:vis $base_name:ident) => {
241
        $crate::macro_deps::paste! {
242
            #[derive($crate::derive_deftly::Deftly)]
243
            #[derive_deftly($crate::macro_deps::Curve25519Keypair)]
244
            #[deftly(kp(pubkey = $base_name "PublicKey"))]
245
            #[non_exhaustive]
246
            $(#[ $docs_and_attrs ])*
247
            $vis struct [<$base_name "Keypair">]($crate::macro_deps::curve25519::StaticKeypair);
248
        }
249
    };
250
}
251

            
252
define_derive_deftly! {
253
    /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
254
    export Curve25519Keypair for struct:
255

            
256
    // Enforce that the object has a single field. We want to avoid the implementer to start
257
    // storing metadata or other things in this object that is meant specifically to be
258
    // a semantic wrapper around an Curve25519 keypair.
259
    ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
260

            
261
    ${define KP_NAME $( $fname )}
262
    ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
263

            
264
    /// Public key component of this keypair. Useful if we move the public key around,
265
    /// it then keeps it semantic with the name and less prone to errors.
266
    #[derive(Clone, Debug, PartialEq, Eq)]
267
    #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
268
    #[non_exhaustive]
269
    $tvis struct $PK_NAME ($crate::macro_deps::curve25519::PublicKey);
270

            
271
    impl std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey> for $PK_NAME {
272
        #[inline]
273
        fn borrow(&self) -> &$crate::macro_deps::curve25519::PublicKey {
274
            &self.0
275
        }
276
    }
277

            
278
    impl $ttype {
279
        /// Build the raw inner public key into the wrapper public key object.
280
        $tvis fn public(&self) -> $PK_NAME {
281
            $PK_NAME(self.$KP_NAME.public.clone())
282
        }
283

            
284
        /// Wrapper around the diffie_hellman() function of the underlying type. This is pretty fun
285
        /// because it accepts both the PK_NAME wrapper or the raw inner curve25519::PublicKey.
286
        $tvis fn diffie_hellman<T>(&self, pk: T) -> $crate::macro_deps::curve25519::SharedSecret
287
        where
288
            T: std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey>
289
        {
290
            self.$KP_NAME.secret.diffie_hellman(pk.borrow())
291
        }
292
    }
293

            
294
    impl From<$crate::macro_deps::curve25519::StaticKeypair> for $ttype {
295
        fn from(kp: $crate::macro_deps::curve25519::StaticKeypair) -> Self {
296
            Self(kp)
297
        }
298
    }
299

            
300
    /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
301
    /// in a keystore.
302

            
303
    impl $crate::ItemType for $ttype {
304
        fn item_type() -> $crate::KeystoreItemType {
305
            $crate::KeyType::X25519StaticKeypair.into()
306
        }
307
    }
308

            
309
    impl $crate::EncodableItem for $ttype {
310
        fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
311
            self.$KP_NAME.as_keystore_item()
312
        }
313
    }
314

            
315
    impl $crate::ToEncodableKey for $ttype {
316
        type Key = $crate::macro_deps::curve25519::StaticKeypair;
317
        type KeyPair = $ttype;
318

            
319
        fn to_encodable_key(self) -> Self::Key {
320
            self.$KP_NAME
321
        }
322
        fn from_encodable_key(key: Self::Key) -> Self {
323
            Self(key)
324
        }
325
    }
326

            
327
    impl $crate::Keygen for $ttype {
328
        fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
329
        where
330
            Self: Sized
331
        {
332
            let secret = $crate::macro_deps::curve25519::StaticSecret::random_from_rng(rng);
333
            let public: $crate::macro_deps::curve25519::PublicKey = (&secret).into();
334
            let kp = $crate::macro_deps::curve25519::StaticKeypair {
335
                secret: secret.into(),
336
                public: public.into(),
337
            };
338
            Ok(kp.into())
339
        }
340
    }
341
}
342

            
343
// Re-export dependencies as `tor_key_forge::macro_deps` that we use to make this macro work.
344
#[doc(hidden)]
345
pub mod deps {
346
    pub use derive_deftly_template_Curve25519Keypair;
347
    pub use derive_deftly_template_Ed25519Keypair;
348
    pub use derive_more;
349
    pub use paste::paste;
350
    pub use signature;
351
    pub use tor_llcrypto::pk::{curve25519, ed25519, ValidatableSignature};
352
}
353

            
354
#[cfg(test)]
355
mod test {
356
    use crate::Keygen;
357
    use tor_basic_utils::test_rng::testing_rng;
358
    use tor_llcrypto::{pk::ed25519::Ed25519SigningKey, rng::FakeEntropicRng};
359

            
360
    #[test]
361
    fn deftly_ed25519_keypair() {
362
        define_ed25519_keypair!(SomeEd25519);
363

            
364
        let mut rng = FakeEntropicRng(testing_rng());
365
        let kp = SomeEd25519Keypair::generate(&mut rng).expect("Failed to gen key");
366

            
367
        // Make sure the generated public key from our wrapper is the same as the
368
        // underlying keypair.
369
        let pubkey = kp.public();
370
        assert_eq!(pubkey.0, kp.0.verifying_key());
371

            
372
        // Message to sign and verify.
373
        let msg: [u8; 4] = [2, 3, 4, 5];
374
        let msg_bad: [u8; 4] = [2, 3, 4, 6];
375

            
376
        let sig = kp.sign(msg.as_slice());
377
        assert!(kp.verify(sig, msg.as_slice()));
378
        // Lets make sure we don't validate another message.
379
        assert!(!kp.verify(sig, msg_bad.as_slice()));
380
    }
381
}