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}