/ crates / tor-key-forge / src / macros.rs
macros.rs
  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 rand::Rng;
 38  /// use tor_key_forge::Keygen;
 39  /// use tor_key_forge::define_ed25519_keypair;
 40  /// use tor_llcrypto::pk::ValidatableSignature;
 41  /// use tor_llcrypto::pk::ed25519::Signer;
 42  ///
 43  /// define_ed25519_keypair!(
 44  ///     /// Our signing key.
 45  ///     MySigning
 46  /// );
 47  ///
 48  /// let mut rng = rand::thread_rng();
 49  /// let signing_kp = MySigningKeypair::generate(&mut rng).expect("Invalid keygen");
 50  /// let signing_pubkey = signing_kp.public();
 51  /// // Lets sign this wonderful message.
 52  /// let message = "Workers want rights, not your opinion".as_bytes();
 53  /// let sig = signing_kp.sign(&message);
 54  ///
 55  /// // You can then verify either directly with the keypair or the public key.
 56  /// assert!(signing_kp.verify(sig, &message));
 57  /// assert!(signing_pubkey.verify(sig, &message));
 58  /// ```
 59  #[macro_export]
 60  macro_rules! define_ed25519_keypair {
 61      ($(#[ $docs_and_attrs:meta ])*
 62       $vis:vis $base_name:ident) => {
 63          $crate::macro_deps::paste! {
 64              #[derive($crate::derive_deftly::Deftly)]
 65              #[derive_deftly($crate::macro_deps::Ed25519Keypair)]
 66              #[deftly(kp(pubkey = $base_name "PublicKey"))]
 67              #[non_exhaustive]
 68              $(#[ $docs_and_attrs ])*
 69              $vis struct [<$base_name "Keypair">]($crate::macro_deps::ed25519::Keypair);
 70          }
 71      };
 72  }
 73  
 74  define_derive_deftly! {
 75      /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
 76      export Ed25519Keypair for struct:
 77  
 78      // Enforce that the object has a single field. We want to avoid the implementer to start
 79      // storing metadata or other things in this object that is meant specifically to be
 80      // a semantic wrapper around an Ed25519 keypair.
 81      ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
 82  
 83      ${define KP_NAME $( $fname )}
 84      ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
 85  
 86      /// Public key component of this keypair. Useful if we move the public key around,
 87      /// it then keeps it semantic with the name and less prone to errors.
 88      #[derive(Clone, Debug, PartialEq, Eq)]
 89      #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
 90      #[non_exhaustive]
 91      $tvis struct $PK_NAME ($tvis $crate::macro_deps::ed25519::PublicKey);
 92  
 93      impl $PK_NAME {
 94          /// Verify the signature of a given message.
 95          #[allow(unused)]
 96          $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
 97              use $crate::macro_deps::ValidatableSignature;
 98              $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(self.0, sig, text).is_valid()
 99          }
100      }
101  
102      impl $crate::macro_deps::ed25519::Ed25519PublicKey for $PK_NAME {
103          fn public_key(&self) -> &$crate::macro_deps::ed25519::PublicKey {
104              &self.0
105          }
106      }
107  
108      // We don't expect all implementations to use all code.
109      #[allow(unused)]
110      impl $ttype {
111          /// Build the raw inner public key into the wrapper public key object.
112          $tvis fn public(&self) -> $PK_NAME {
113              $PK_NAME((&self.$KP_NAME).into())
114          }
115          /// Verify the signature of a given message.
116          $tvis fn verify(&self, sig: $crate::macro_deps::ed25519::Signature, text: &[u8]) -> bool {
117              use $crate::macro_deps::ValidatableSignature;
118              $crate::macro_deps::ed25519::ValidatableEd25519Signature::new(
119                  self.0.verifying_key(), sig, text
120              ).is_valid()
121          }
122          /// Return a Ed25519Identity built from this keypair.
123          $tvis fn to_ed25519_id(&self) -> $crate::macro_deps::ed25519::Ed25519Identity {
124              $crate::macro_deps::ed25519::Ed25519Identity::from(&self.public().0)
125          }
126      }
127  
128      impl From<$crate::macro_deps::ed25519::Keypair> for $ttype {
129          fn from(kp: $crate::macro_deps::ed25519::Keypair) -> Self {
130              Self(kp)
131          }
132      }
133      impl $crate::macro_deps::ed25519::Ed25519PublicKey for $ttype {
134          fn public_key(&self) -> &$crate::macro_deps::ed25519::PublicKey {
135              self.0.as_ref()
136          }
137      }
138  
139      impl $crate::macro_deps::ed25519::Signer<$crate::macro_deps::ed25519::Signature> for $ttype {
140          fn try_sign(
141              &self,
142              msg: &[u8])
143          -> Result<$crate::macro_deps::ed25519::Signature, $crate::macro_deps::signature::Error> {
144              self.0.try_sign(msg)
145          }
146      }
147  
148      /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
149      /// in a keystore.
150  
151      impl $crate::ItemType for $ttype {
152          fn item_type() -> $crate::KeystoreItemType {
153              $crate::KeyType::Ed25519Keypair.into()
154          }
155      }
156  
157      impl $crate::EncodableItem for $ttype {
158          fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
159              self.$KP_NAME.as_keystore_item()
160          }
161      }
162  
163      impl $crate::ToEncodableKey for $ttype {
164          type Key = $crate::macro_deps::ed25519::Keypair;
165          type KeyPair = $ttype;
166  
167          fn to_encodable_key(self) -> Self::Key {
168              self.$KP_NAME
169          }
170          fn from_encodable_key(key: Self::Key) -> Self {
171              Self(key)
172          }
173      }
174  
175      impl $crate::Keygen for $ttype {
176          fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
177          where
178              Self: Sized
179          {
180              Ok(Self { $KP_NAME: $crate::macro_deps::ed25519::Keypair::generate(&mut rng) })
181          }
182      }
183  }
184  
185  /// Create a curve25519 keypair wrapper given a visibility and a struct name.
186  ///
187  /// # Syntax:
188  /// ```rust,ignore
189  /// define_curve25519_keypair(<visibility> <prefix>)
190  /// ```
191  ///
192  /// This macro creates a struct tuple named `<prefix>Keypair` which contains the lower-level
193  /// cryptographic keypair for a curve25519 keypair. It derives the deftly Curve25519Keypair template
194  /// which in turn creates `<prefix>PublicKey` along a series of useful methods.
195  ///
196  /// The keypair is NOT clonable by design in order to avoid duplicating secret key material.
197  ///
198  /// # Example:
199  ///
200  /// ```rust
201  /// use tor_key_forge::define_curve25519_keypair;
202  ///
203  /// define_curve25519_keypair!(NonPublicEnc);
204  /// define_curve25519_keypair!(pub PublicEnc);
205  /// define_curve25519_keypair!(pub(crate) CratePublicEnc);
206  /// ```
207  ///
208  /// The above results in `NonPublicEncKeypair` and `NonPublicEncPublicKey` struct being created and
209  /// usable with a series of useful methods.
210  ///
211  /// You can then use these objects like so:
212  ///
213  /// ```rust
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 mut rng = rand::thread_rng();
225  /// let alice_kp = AliceEncKeypair::generate(&mut rng).expect("Failed alice keygen");
226  /// let bob_kp = BobEncKeypair::generate(&mut rng).expect("Failed bob keygen");
227  ///
228  /// // Using the public key wrapper
229  /// let alice_shared_secret = alice_kp.diffie_hellman(bob_kp.public());
230  /// // Using the direct curve25519::PublicKey.
231  /// let bob_shared_secret = bob_kp.diffie_hellman(&alice_kp.public().0);
232  ///
233  /// assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());
234  /// ```
235  #[macro_export]
236  macro_rules! define_curve25519_keypair {
237      ($(#[ $docs_and_attrs:meta ])*
238      $vis:vis $base_name:ident) => {
239          $crate::macro_deps::paste! {
240              #[derive($crate::derive_deftly::Deftly)]
241              #[derive_deftly($crate::macro_deps::Curve25519Keypair)]
242              #[deftly(kp(pubkey = $base_name "PublicKey"))]
243              #[non_exhaustive]
244              $(#[ $docs_and_attrs ])*
245              $vis struct [<$base_name "Keypair">]($crate::macro_deps::curve25519::StaticKeypair);
246          }
247      };
248  }
249  
250  define_derive_deftly! {
251      /// Implement set of helper functions around a type wrapping an ed25519::Keypair.
252      export Curve25519Keypair for struct:
253  
254      // Enforce that the object has a single field. We want to avoid the implementer to start
255      // storing metadata or other things in this object that is meant specifically to be
256      // a semantic wrapper around an Curve25519 keypair.
257      ${if not(approx_equal(${for fields { 1 }}, 1)) { ${error "Single field only"}}}
258  
259      ${define KP_NAME $( $fname )}
260      ${define PK_NAME ${tmeta(kp(pubkey)) as ident}}
261  
262      /// Public key component of this keypair. Useful if we move the public key around,
263      /// it then keeps it semantic with the name and less prone to errors.
264      #[derive(Clone, Debug, PartialEq, Eq)]
265      #[derive($crate::macro_deps::derive_more::From, $crate::macro_deps::derive_more::Into)]
266      #[non_exhaustive]
267      $tvis struct $PK_NAME ($crate::macro_deps::curve25519::PublicKey);
268  
269      impl std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey> for $PK_NAME {
270          #[inline]
271          fn borrow(&self) -> &$crate::macro_deps::curve25519::PublicKey {
272              &self.0
273          }
274      }
275  
276      impl $ttype {
277          /// Build the raw inner public key into the wrapper public key object.
278          $tvis fn public(&self) -> $PK_NAME {
279              $PK_NAME(self.$KP_NAME.public.clone())
280          }
281  
282          /// Wrapper around the diffie_hellman() function of the underlying type. This is pretty fun
283          /// because it accepts both the PK_NAME wrapper or the raw inner curve25519::PublicKey.
284          $tvis fn diffie_hellman<T>(&self, pk: T) -> $crate::macro_deps::curve25519::SharedSecret
285          where
286              T: std::borrow::Borrow<$crate::macro_deps::curve25519::PublicKey>
287          {
288              self.$KP_NAME.secret.diffie_hellman(pk.borrow())
289          }
290      }
291  
292      impl From<$crate::macro_deps::curve25519::StaticKeypair> for $ttype {
293          fn from(kp: $crate::macro_deps::curve25519::StaticKeypair) -> Self {
294              Self(kp)
295          }
296      }
297  
298      /// Implementing EncodableItem, ToEncodableKey and Keygen allows this wrapper key to be stored
299      /// in a keystore.
300  
301      impl $crate::ItemType for $ttype {
302          fn item_type() -> $crate::KeystoreItemType {
303              $crate::KeyType::X25519StaticKeypair.into()
304          }
305      }
306  
307      impl $crate::EncodableItem for $ttype {
308          fn as_keystore_item(&self) -> $crate::Result<$crate::KeystoreItem> {
309              self.$KP_NAME.as_keystore_item()
310          }
311      }
312  
313      impl $crate::ToEncodableKey for $ttype {
314          type Key = $crate::macro_deps::curve25519::StaticKeypair;
315          type KeyPair = $ttype;
316  
317          fn to_encodable_key(self) -> Self::Key {
318              self.$KP_NAME
319          }
320          fn from_encodable_key(key: Self::Key) -> Self {
321              Self(key)
322          }
323      }
324  
325      impl $crate::Keygen for $ttype {
326          fn generate(mut rng: &mut dyn $crate::KeygenRng) -> $crate::Result<Self>
327          where
328              Self: Sized
329          {
330              let secret = $crate::macro_deps::curve25519::StaticSecret::random_from_rng(rng);
331              let public: $crate::macro_deps::curve25519::PublicKey = (&secret).into();
332              let kp = $crate::macro_deps::curve25519::StaticKeypair {
333                  secret: secret.into(),
334                  public: public.into(),
335              };
336              Ok(kp.into())
337          }
338      }
339  }
340  
341  // Re-export dependencies as `tor_key_forge::macro_deps` that we use to make this macro work.
342  #[doc(hidden)]
343  pub mod deps {
344      pub use derive_deftly_template_Curve25519Keypair;
345      pub use derive_deftly_template_Ed25519Keypair;
346      pub use derive_more;
347      pub use paste::paste;
348      pub use signature;
349      pub use tor_llcrypto::pk::{curve25519, ed25519, ValidatableSignature};
350  }
351  
352  #[cfg(test)]
353  mod test {
354      use crate::Keygen;
355      use tor_basic_utils::test_rng::testing_rng;
356      use tor_llcrypto::pk::ed25519::Signer;
357  
358      #[test]
359      fn deftly_ed25519_keypair() {
360          define_ed25519_keypair!(SomeEd25519);
361  
362          let mut rng = testing_rng();
363          let kp = SomeEd25519Keypair::generate(&mut rng).expect("Failed to gen key");
364  
365          // Make sure the generated public key from our wrapper is the same as the
366          // underlying keypair.
367          let pubkey = kp.public();
368          assert_eq!(pubkey.0, kp.0.verifying_key());
369  
370          // Message to sign and verify.
371          let msg: [u8; 4] = [2, 3, 4, 5];
372          let msg_bad: [u8; 4] = [2, 3, 4, 6];
373  
374          let sig = kp.sign(msg.as_slice());
375          assert!(kp.verify(sig, msg.as_slice()));
376          // Lets make sure we don't validate another message.
377          assert!(!kp.verify(sig, msg_bad.as_slice()));
378      }
379  }