tor_hscrypto/macros.rs
1//! Macros that we use to define other types in this crate.
2//!
3//! (These macros are not likely to work outside of the context used in this
4//! crate without additional help.)
5
6/// Define a public key type and a private key type to wrap a given inner key.
7//
8// TODO This macro needs proper formal documentation of its its input syntax and semantics.
9// (Possibly the input syntax ought to be revisited.)
10macro_rules! define_pk_keypair {
11 {
12 $(#[$meta:meta])* pub struct $pk:ident($pkt:ty) / $(#[$sk_meta:meta])* $sk:ident($skt:ty);
13 $($(#[$p_meta:meta])* curve25519_pair as $pair:ident;)?
14 } => {
15 paste::paste!{
16 $(#[$meta])*
17 #[derive(Clone,Debug,derive_more::From,derive_more::Deref,derive_more::Into,derive_more::AsRef)]
18 pub struct $pk ($pkt);
19
20 #[doc = concat!("The private counterpart of a [`", stringify!($pk), "Key'].")]
21 $(#[$sk_meta])*
22 #[derive(derive_more::From, derive_more::Into, derive_more::AsRef)]
23 pub struct $sk ($skt);
24
25 impl std::fmt::Debug for $sk
26 {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.write_str(concat!(stringify!($pk), "SecretKey(...)"))
29 }
30 }
31
32 // For curve25519 keys, we are willing to handle secret keys without
33 // a corresponding public key, since there is not a cryptographic
34 // risk inherent in our protocols to getting them mixed up.
35 //
36 // But that means that it sometimes _is_ worthwhile defining a
37 // keypair type.
38 $(
39 #[doc = concat!("A pair of a public and private components for a [`", stringify!($pk), "`].")]
40 $(#[$p_meta])*
41 #[derive(Debug)]
42 pub struct $pair {
43 public: $pk,
44 secret: $sk,
45 }
46 impl $pair {
47 /// Construct this keypair from a public key and a secret key.
48 pub fn new(public: $pk, secret: $sk) -> Self {
49 Self { public, secret }
50 }
51 /// Construct this keypair from a secret key.
52 pub fn from_secret_key(secret: $sk) -> Self {
53 let public:$pk = $pkt::from(&secret.0).into();
54 Self { public, secret }
55 }
56 /// Return the public part of this keypair.
57 pub fn public(&self) -> &$pk { &self.public }
58 /// Return the secret part of this keypair.
59 pub fn secret(&self) -> &$sk { &self.secret }
60 /// Generate a new keypair from a secure random number generator.
61 //
62 // TODO: this should be implemented in terms of
63 // `<curve25519::StaticSecret as tor_keymgr::Keygen>` and
64 // `<$pair as From<curve25519::StaticKeypair>>`
65 // See https://gitlab.torproject.org/tpo/core/arti/-/issues/1137#note_2969181
66 pub fn generate<R>(rng: &mut R) -> Self
67 where
68 R: rand::Rng + rand::CryptoRng,
69 {
70 let secret = curve25519::StaticSecret::random_from_rng(rng);
71 let public: curve25519::PublicKey = (&secret).into();
72 Self {
73 secret: secret.into(),
74 public: public.into(),
75 }
76 }
77 }
78 impl From<curve25519::StaticKeypair> for $pair {
79 fn from(input: curve25519::StaticKeypair) -> $pair {
80 $pair {
81 secret: input.secret.into(),
82 public: input.public.into(),
83 }
84 }
85 }
86 impl From<$pair> for curve25519::StaticKeypair {
87 fn from(input: $pair) -> curve25519::StaticKeypair {
88 curve25519::StaticKeypair {
89 secret: input.secret.into(),
90 public: input.public.into(),
91 }
92 }
93 }
94 )?
95 }
96 };
97}
98
99/// Define a wrapper type around a byte array of fixed length.
100///
101/// (Internally, it uses a [`CtByteArray`](tor_llcrypto::util::ct::CtByteArray),
102/// so it's safe to derive Ord, Eq, etc.)
103macro_rules! define_bytes {
104{ $(#[$meta:meta])* pub struct $name:ident([u8 ; $n:expr]); } =>
105{
106 $(#[$meta])*
107 pub struct $name(tor_llcrypto::util::ct::CtByteArray<$n>);
108
109 impl $name {
110 fn new(inp: [u8;$n]) -> Self {
111 Self(inp.into())
112 }
113 }
114 impl AsRef<[u8;$n]> for $name {
115 fn as_ref(&self) -> &[u8;$n] {
116 self.0.as_ref()
117 }
118 }
119 impl From<[u8;$n]> for $name {
120 fn from(inp: [u8;$n]) -> Self {
121 Self::new(inp)
122 }
123 }
124 impl From<$name> for [u8;$n] {
125 fn from(inp: $name) -> [u8;$n] {
126 inp.0.into()
127 }
128 }
129 impl tor_bytes::Readable for $name {
130 fn take_from(r: &mut tor_bytes::Reader<'_>) -> tor_bytes::Result<Self> {
131 Ok(Self::new(r.extract()?))
132 }
133 }
134 impl tor_bytes::Writeable for $name {
135 fn write_onto<B:tor_bytes::Writer+?Sized>(&self, w: &mut B) -> tor_bytes::EncodeResult<()> {
136 w.write_all(&self.0.as_ref()[..]);
137 Ok(())
138 }
139 }
140}
141}
142
143pub(crate) use {define_bytes, define_pk_keypair};