tor_key_forge/
macros.rs

1//! Macros that can be used to improve your life with regards to crypto.
2
3use 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]
61macro_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
75define_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        $tvis fn public(&self) -> $PK_NAME {
114            $PK_NAME((&self.$KP_NAME).into())
115        }
116        /// Verify the signature of a given message.
117        $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        fn sign(
142            &self,
143            msg: &[u8])
144        -> $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        fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
178        where
179            Self: Sized
180        {
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]
238macro_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
252define_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)]
345pub 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)]
355mod 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}