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/// Create an ed25519 keypair wrapper given a visibility and a struct name.
6///
7/// # Syntax:
8/// ```rust,ignore
9/// define_ed25519_keypair(<visibility> <prefix>)
10/// ```
11///
12/// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
13/// cryptographic keypair for an ed25519 keypair. It derives the deftly Ed25519Keypair template
14/// which in turn creates `<prefix>PublicKey` along a series of useful methods.
15///
16/// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
17///
18/// # Example:
19///
20/// ```rust
21/// use tor_key_forge::define_ed25519_keypair;
22///
23/// define_ed25519_keypair!(NonPublicSigning);
24/// define_ed25519_keypair!(pub PublicSigning);
25/// define_ed25519_keypair!(pub(crate) CratePublicSigning);
26/// ```
27///
28/// The above results in `NonPublicSigningKeypair` and `NonPublicSigningPublicKey` struct being
29/// created and usable with a series of useful methods. Same for the other defines.
30///
31/// You can then use these objects like so:
32///
33/// ```rust
34/// # use tor_llcrypto::rng::FakeEntropicRng;
35/// # let mut rng = FakeEntropicRng(rand::rng());
36/// use rand::Rng;
37/// use tor_key_forge::Keygen;
38/// use tor_key_forge::define_ed25519_keypair;
39/// use tor_llcrypto::pk::ValidatableSignature;
40/// use tor_llcrypto::pk::ed25519::Ed25519SigningKey;
41///
42/// define_ed25519_keypair!(
43/// /// Our signing key.
44/// MySigning
45/// );
46///
47/// let signing_kp = MySigningKeypair::generate(&mut rng).expect("Invalid keygen");
48/// let signing_pubkey = signing_kp.public();
49/// // Lets sign this wonderful message.
50/// let message = "Workers want rights, not your opinion".as_bytes();
51/// let sig = signing_kp.sign(&message);
52///
53/// // You can then verify either directly with the keypair or the public key.
54/// assert!(signing_kp.verify(sig, &message));
55/// assert!(signing_pubkey.verify(sig, &message));
56/// ```
57#[macro_export]
58macro_rules! define_ed25519_keypair {
59 ($(#[ $docs_and_attrs:meta ])*
60 $vis:vis $base_name:ident) => {
61 $crate::macro_deps::paste! {
62 #[derive($crate::derive_deftly::Deftly)]
63 #[derive_deftly($crate::macro_deps::Ed25519Keypair)]
64 #[deftly(kp(pubkey = $base_name "PublicKey"))]
65 #[non_exhaustive]
66 $(#[ $docs_and_attrs ])*
67 $vis struct [<$base_name "Keypair">]($crate::macro_deps::ed25519::Keypair);
68 }
69 };
70}
71
72define_derive_deftly! {
73 /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
74 export Ed25519Keypair for struct:
75
76 // Enforce that the object has a single field. We want to avoid the implementer to start
77 // storing metadata or other things in this object that is meant specifically to be
78 // a semantic wrapper around an Ed25519 keypair.
79 ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
80
81 ${define KP_NAME $( $fname )}
82 ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
83
84 /// Public key component of this keypair. Useful if we move the public key around,
85 /// it then keeps it semantic with the name and less prone to errors.
86 #[derive(Clone, Debug, PartialEq, Eq)]
87 #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
88 #[non_exhaustive]
89 $tvis struct $PK_NAME ($tvis $crate::macro_deps::ed25519::PublicKey);
90
91 impl $PK_NAME {
92 /// Verify the signature of a given message.
93 #[allow(unused)]
94 $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
95 use $crate::macro_deps::ValidatableSignature;
96 $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(self.0, sig, text).is_valid()
97 }
98 }
99
100 impl $crate::macro_deps::ed25519::Ed25519PublicKey for $PK_NAME {
101 fn public_key(&self) -> $crate::macro_deps::ed25519::PublicKey {
102 self.0
103 }
104 }
105
106 // We don't expect all implementations to use all code.
107 #[allow(unused)]
108 impl $ttype {
109 /// Build the raw inner public key into the wrapper public key object.
110 $tvis fn public(&self) -> $PK_NAME {
111 $PK_NAME((&self.$KP_NAME).into())
112 }
113 /// Verify the signature of a given message.
114 $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
115 use $crate::macro_deps::ValidatableSignature;
116 $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(
117 self.0.verifying_key(), sig, text
118 ).is_valid()
119 }
120 /// Return a Ed25519Identity built from this keypair.
121 $tvis fn to_ed25519_id(&self) -> $crate::macro_deps::ed25519::Ed25519Identity {
122 $crate::macro_deps::ed25519::Ed25519Identity::from(&self.public().0)
123 }
124 }
125
126 impl From<$crate::macro_deps::ed25519::Keypair> for $ttype {
127 fn from(kp: $crate::macro_deps::ed25519::Keypair) -> Self {
128 Self(kp)
129 }
130 }
131 impl $crate::macro_deps::ed25519::Ed25519PublicKey for $ttype {
132 fn public_key(&self) -> $crate::macro_deps::ed25519::PublicKey {
133 self.0.public_key()
134 }
135 }
136
137 impl $crate::macro_deps::ed25519::Ed25519SigningKey for $ttype {
138 fn sign(
139 &self,
140 msg: &[u8])
141 -> $crate::macro_deps::ed25519::Signature {
142 self.0.sign(msg)
143 }
144 }
145
146 /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
147 /// in a keystore.
148
149 impl $crate::ItemType for $ttype {
150 fn item_type() -> $crate::KeystoreItemType {
151 $crate::KeyType::Ed25519Keypair.into()
152 }
153 }
154
155 impl $crate::EncodableItem for $ttype {
156 fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
157 self.$KP_NAME.as_keystore_item()
158 }
159 }
160
161 impl $crate::ToEncodableKey for $ttype {
162 type Key = $crate::macro_deps::ed25519::Keypair;
163 type KeyPair = $ttype;
164
165 fn to_encodable_key(self) -> Self::Key {
166 self.$KP_NAME
167 }
168 fn from_encodable_key(key: Self::Key) -> Self {
169 Self(key)
170 }
171 }
172
173 impl $crate::Keygen for $ttype {
174 fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
175 where
176 Self: Sized
177 {
178 Ok(Self { $KP_NAME: $crate::macro_deps::ed25519::Keypair::generate(&mut rng) })
179 }
180 }
181}
182
183/// Create a curve25519 keypair wrapper given a visibility and a struct name.
184///
185/// # Syntax:
186/// ```rust,ignore
187/// define_curve25519_keypair(<visibility> <prefix>)
188/// ```
189///
190/// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
191/// cryptographic keypair for a curve25519 keypair. It derives the deftly Curve25519Keypair template
192/// which in turn creates `<prefix>PublicKey` along a series of useful methods.
193///
194/// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
195///
196/// # Example:
197///
198/// ```rust
199/// use tor_key_forge::define_curve25519_keypair;
200///
201/// define_curve25519_keypair!(NonPublicEnc);
202/// define_curve25519_keypair!(pub PublicEnc);
203/// define_curve25519_keypair!(pub(crate) CratePublicEnc);
204/// ```
205///
206/// The above results in `NonPublicEncKeypair` and `NonPublicEncPublicKey` struct being created and
207/// usable with a series of useful methods.
208///
209/// You can then use these objects like so:
210///
211/// ```rust
212/// # use tor_llcrypto::rng::FakeEntropicRng;
213/// # let mut rng = FakeEntropicRng(rand::rng());
214/// # use rand::Rng;
215/// use tor_key_forge::define_curve25519_keypair;
216/// use tor_key_forge::Keygen;
217///
218/// define_curve25519_keypair!(
219/// // This is Alice's keypair.
220/// AliceEnc
221/// );
222/// define_curve25519_keypair!(BobEnc);
223///
224/// let alice_kp = AliceEncKeypair::generate(&mut rng).expect("Failed alice keygen");
225/// let bob_kp = BobEncKeypair::generate(&mut rng).expect("Failed bob keygen");
226///
227/// // Using the public key wrapper
228/// let alice_shared_secret = alice_kp.diffie_hellman(bob_kp.public());
229/// // Using the direct curve25519::PublicKey.
230/// let bob_shared_secret = bob_kp.diffie_hellman(&alice_kp.public().0);
231///
232/// assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());
233/// ```
234#[macro_export]
235macro_rules! define_curve25519_keypair {
236 ($(#[ $docs_and_attrs:meta ])*
237 $vis:vis $base_name:ident) => {
238 $crate::macro_deps::paste! {
239 #[derive($crate::derive_deftly::Deftly)]
240 #[derive_deftly($crate::macro_deps::Curve25519Keypair)]
241 #[deftly(kp(pubkey = $base_name "PublicKey"))]
242 #[non_exhaustive]
243 $(#[ $docs_and_attrs ])*
244 $vis struct [<$base_name "Keypair">]($crate::macro_deps::curve25519::StaticKeypair);
245 }
246 };
247}
248
249define_derive_deftly! {
250 /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
251 export Curve25519Keypair for struct:
252
253 // Enforce that the object has a single field. We want to avoid the implementer to start
254 // storing metadata or other things in this object that is meant specifically to be
255 // a semantic wrapper around an Curve25519 keypair.
256 ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
257
258 ${define KP_NAME $( $fname )}
259 ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
260
261 /// Public key component of this keypair. Useful if we move the public key around,
262 /// it then keeps it semantic with the name and less prone to errors.
263 #[derive(Clone, Debug, PartialEq, Eq)]
264 #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
265 #[non_exhaustive]
266 $tvis struct $PK_NAME ($crate::macro_deps::curve25519::PublicKey);
267
268 impl std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey> for $PK_NAME {
269 #[inline]
270 fn borrow(&self) -> &$crate::macro_deps::curve25519::PublicKey {
271 &self.0
272 }
273 }
274
275 impl $PK_NAME {
276 /// Get the inner [`PublicKey`]($crate::macro_deps::curve25519::PublicKey).
277 // This can be nicer to use than
278 // `<FooPublicKey as Borrow<curve25519::PublicKey>>::borrow(&foo)`.
279 #[inline]
280 $tvis fn inner(&self) -> &$crate::macro_deps::curve25519::PublicKey {
281 &self.0
282 }
283 }
284
285 impl $ttype {
286 /// Build the raw inner public key into the wrapper public key object.
287 $tvis fn public(&self) -> $PK_NAME {
288 $PK_NAME(self.$KP_NAME.public.clone())
289 }
290
291 /// Wrapper around the diffie_hellman() function of the underlying type. This is pretty fun
292 /// because it accepts both the PK_NAME wrapper or the raw inner curve25519::PublicKey.
293 $tvis fn diffie_hellman<T>(&self, pk: T) -> $crate::macro_deps::curve25519::SharedSecret
294 where
295 T: std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey>
296 {
297 self.$KP_NAME.secret.diffie_hellman(pk.borrow())
298 }
299 }
300
301 impl From<$crate::macro_deps::curve25519::StaticKeypair> for $ttype {
302 fn from(kp: $crate::macro_deps::curve25519::StaticKeypair) -> Self {
303 Self(kp)
304 }
305 }
306
307 /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
308 /// in a keystore.
309
310 impl $crate::ItemType for $ttype {
311 fn item_type() -> $crate::KeystoreItemType {
312 $crate::KeyType::X25519StaticKeypair.into()
313 }
314 }
315
316 impl $crate::EncodableItem for $ttype {
317 fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
318 self.$KP_NAME.as_keystore_item()
319 }
320 }
321
322 impl $crate::ToEncodableKey for $ttype {
323 type Key = $crate::macro_deps::curve25519::StaticKeypair;
324 type KeyPair = $ttype;
325
326 fn to_encodable_key(self) -> Self::Key {
327 self.$KP_NAME
328 }
329 fn from_encodable_key(key: Self::Key) -> Self {
330 Self(key)
331 }
332 }
333
334 impl $crate::Keygen for $ttype {
335 fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
336 where
337 Self: Sized
338 {
339 let secret = $crate::macro_deps::curve25519::StaticSecret::random_from_rng(rng);
340 let public: $crate::macro_deps::curve25519::PublicKey = (&secret).into();
341 let kp = $crate::macro_deps::curve25519::StaticKeypair {
342 secret: secret.into(),
343 public: public.into(),
344 };
345 Ok(kp.into())
346 }
347 }
348}
349
350/// Create an RSA keypair wrapper given a visibility and a struct name.
351///
352/// # Syntax:
353/// ```rust,ignore
354/// define_rsa_keypair(<visibility> <prefix>)
355/// ```
356///
357/// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
358/// cryptographic keypair for an RSA keypair. It derives the deftly RsaKeypair template
359/// which in turn creates `<prefix>PublicKey` along a series of useful methods.
360///
361/// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
362///
363/// # Example:
364///
365/// ```rust
366/// use tor_key_forge::define_rsa_keypair;
367///
368/// define_rsa_keypair!(NonPublicSigning);
369/// define_rsa_keypair!(pub PublicSigning);
370/// define_rsa_keypair!(pub(crate) CratePublicSigning);
371/// ```
372///
373/// The above results in `NonPublicSigningKeypair` and `NonPublicSigningPublicKey` struct being
374/// created and usable with a series of useful methods. Same for the other defines.
375///
376/// You can then use these objects like so:
377///
378/// ```rust
379/// # use tor_llcrypto::rng::FakeEntropicRng;
380/// # let mut rng = FakeEntropicRng(rand::rng());
381/// use rand::Rng;
382/// use tor_key_forge::Keygen;
383/// use tor_key_forge::define_rsa_keypair;
384/// use tor_llcrypto::pk::ValidatableSignature;
385/// use tor_llcrypto::pk::rsa::KeyPair;
386///
387/// define_rsa_keypair!(
388/// /// Our signing key.
389/// MyRsa
390/// );
391///
392/// let signing_kp = MyRsaKeypair::generate(&mut rng).expect("Invalid keygen");
393/// let signing_pubkey = signing_kp.public();
394/// // Lets sign this wonderful message.
395/// let message = "Workers want rights, not your opinion".as_bytes();
396/// let sig = signing_kp.sign(&message).expect("Error signing message");
397///
398/// // You can then verify either directly with the keypair or the public key.
399/// assert!(signing_kp.verify(&sig, &message));
400/// assert!(signing_pubkey.verify(&sig, &message));
401/// ```
402#[macro_export]
403macro_rules! define_rsa_keypair {
404 ($(#[ $docs_and_attrs:meta ])*
405 $vis:vis $base_name:ident) => {
406 $crate::macro_deps::paste! {
407 #[derive($crate::derive_deftly::Deftly)]
408 #[derive_deftly($crate::macro_deps::RsaKeypair)]
409 #[deftly(kp(pubkey = $base_name "PublicKey"))]
410 #[non_exhaustive]
411 $(#[ $docs_and_attrs ])*
412 $vis struct [<$base_name "Keypair">]($crate::macro_deps::rsa::KeyPair);
413 }
414 };
415}
416
417define_derive_deftly! {
418 /// Implement set of helper functions around a type wrapping a rsa::KeyPair.
419 export RsaKeypair for struct:
420
421 // Enforce that the object has a single field. We want to avoid the implementer to start
422 // storing metadata or other things in this object that is meant specifically to be
423 // a semantic wrapper around an RSA keypair.
424 ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
425
426 ${define KP_NAME $( $fname )}
427 ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
428
429 /// Public key component of this keypair. Useful if we move the public key around,
430 /// it then keeps it semantic with the name and less prone to errors.
431 #[derive(Clone, Debug, PartialEq, Eq)]
432 #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
433 #[non_exhaustive]
434 $tvis struct $PK_NAME ($tvis $crate::macro_deps::rsa::PublicKey);
435
436 impl $PK_NAME {
437 /// Verify the signature of a given message.
438 #[allow(unused)]
439 $tvis fn verify(&self, sig: &[u8], text: &[u8]) -> bool {
440 use $crate::macro_deps::ValidatableSignature;
441 $crate::macro_deps::rsa::ValidatableRsaSignature::new(&self.0, sig, text).is_valid()
442 }
443 }
444
445 // We don't expect all implementations to use all code.
446 #[allow(unused)]
447 impl $ttype {
448 /// Build the raw inner public key into the wrapper public key object.
449 $tvis fn public(&self) -> $PK_NAME {
450 $PK_NAME((&self.$KP_NAME).into())
451 }
452
453 /// Reference to the internal keypair.
454 $tvis fn keypair(&self) -> &$crate::macro_deps::rsa::KeyPair {
455 &self.0
456 }
457
458 /// Sign the given message.
459 $tvis fn sign(&self, message: &[u8]) -> Result<Vec<u8>, $crate::macro_deps::rsa::Error> {
460 self.0.sign(message)
461 }
462
463 /// Verify the signature of a given message.
464 $tvis fn verify(&self, sig: &[u8], text: &[u8]) -> bool {
465 use $crate::macro_deps::ValidatableSignature;
466 $crate::macro_deps::rsa::ValidatableRsaSignature::new(
467 &self.0.to_public_key(), sig, text
468 ).is_valid()
469 }
470
471 /// Return a RsaIdentity built from this keypair.
472 $tvis fn to_rsa_identity(&self) -> $crate::macro_deps::rsa::RsaIdentity {
473 self.public().0.to_rsa_identity()
474 }
475 }
476
477 impl From<$crate::macro_deps::rsa::KeyPair> for $ttype {
478 fn from(kp: $crate::macro_deps::rsa::KeyPair) -> Self {
479 Self(kp)
480 }
481 }
482
483 /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
484 /// in a keystore.
485
486 impl $crate::ItemType for $ttype {
487 fn item_type() -> $crate::KeystoreItemType {
488 $crate::KeyType::RsaKeypair.into()
489 }
490 }
491
492 impl $crate::EncodableItem for $ttype {
493 fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
494 self.$KP_NAME.as_keystore_item()
495 }
496 }
497
498 impl $crate::ToEncodableKey for $ttype {
499 type Key = $crate::macro_deps::rsa::KeyPair;
500 type KeyPair = $ttype;
501
502 fn to_encodable_key(self) -> Self::Key {
503 self.$KP_NAME
504 }
505 fn from_encodable_key(key: Self::Key) -> Self {
506 Self(key)
507 }
508 }
509
510 impl $crate::Keygen for $ttype {
511 fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
512 where
513 Self: Sized
514 {
515 Ok(Self { $KP_NAME: $crate::macro_deps::rsa::KeyPair::generate(&mut rng)? })
516 }
517 }
518}
519
520// Re-export dependencies as `tor_key_forge::macro_deps` that we use to make this macro work.
521#[doc(hidden)]
522pub mod deps {
523 pub use derive_deftly_template_Curve25519Keypair;
524 pub use derive_deftly_template_Ed25519Keypair;
525 pub use derive_deftly_template_RsaKeypair;
526 pub use derive_more;
527 pub use paste::paste;
528 pub use signature;
529 pub use tor_llcrypto::pk::{ValidatableSignature, curve25519, ed25519, rsa};
530}
531
532#[cfg(test)]
533mod test {
534 use crate::Keygen;
535 use tor_basic_utils::test_rng::testing_rng;
536 use tor_llcrypto::{pk::ed25519::Ed25519SigningKey, rng::FakeEntropicRng};
537
538 #[test]
539 fn deftly_ed25519_keypair() {
540 define_ed25519_keypair!(SomeEd25519);
541
542 let mut rng = FakeEntropicRng(testing_rng());
543 let kp = SomeEd25519Keypair::generate(&mut rng).expect("Failed to gen key");
544
545 // Make sure the generated public key from our wrapper is the same as the
546 // underlying keypair.
547 let pubkey = kp.public();
548 assert_eq!(pubkey.0, kp.0.verifying_key());
549
550 // Message to sign and verify.
551 let msg: [u8; 4] = [2, 3, 4, 5];
552 let msg_bad: [u8; 4] = [2, 3, 4, 6];
553
554 let sig = kp.sign(msg.as_slice());
555 assert!(kp.verify(sig, msg.as_slice()));
556 // Lets make sure we don't validate another message.
557 assert!(!kp.verify(sig, msg_bad.as_slice()));
558 }
559
560 #[test]
561 fn deftly_rsa_keypair() {
562 define_rsa_keypair!(SomeRsa);
563
564 let mut rng = FakeEntropicRng(testing_rng());
565 let kp = SomeRsaKeypair::generate(&mut rng).expect("Failed to gen key");
566
567 // Make sure the generated public key from our wrapper is the same as the
568 // underlying keypair.
569 let pubkey = kp.public();
570 assert_eq!(pubkey.0, kp.0.to_public_key());
571
572 // Message to sign and verify.
573 let msg: [u8; 4] = [2, 3, 4, 5];
574 let msg_bad: [u8; 4] = [2, 3, 4, 6];
575
576 let sig = kp.sign(msg.as_slice()).expect("Failed to sign message.");
577 assert!(kp.verify(&sig, msg.as_slice()));
578 // Lets make sure we don't validate another message.
579 assert!(!kp.verify(&sig, msg_bad.as_slice()));
580 }
581}