1use crate::Error;
24use libp2p_identity as identity;
25use once_cell::sync::Lazy;
26use rand::{Rng as _, SeedableRng};
27use snow::params::NoiseParams;
28use x25519_dalek::{x25519, X25519_BASEPOINT_BYTES};
29use zeroize::Zeroize;
30
31pub(crate) const STATIC_KEY_DOMAIN: &str = "noise-libp2p-static-key:";
33
34pub(crate) static PARAMS_XX: Lazy<NoiseParams> = Lazy::new(|| {
35 "Noise_XX_25519_ChaChaPoly_SHA256"
36 .parse()
37 .expect("Invalid protocol name")
38});
39
40pub(crate) fn noise_params_into_builder<'b>(
41 params: NoiseParams,
42 prologue: &'b [u8],
43 private_key: &'b SecretKey,
44 remote_public_key: Option<&'b PublicKey>,
45) -> snow::Builder<'b> {
46 let mut builder = snow::Builder::with_resolver(params, Box::new(Resolver))
47 .prologue(prologue.as_ref())
48 .local_private_key(private_key.as_ref());
49
50 if let Some(remote_public_key) = remote_public_key {
51 builder = builder.remote_public_key(remote_public_key.as_ref());
52 }
53
54 builder
55}
56
57#[derive(Clone)]
59pub(crate) struct Keypair {
60 secret: SecretKey,
61 public: PublicKey,
62}
63
64#[derive(Clone)]
66pub(crate) struct AuthenticKeypair {
67 pub(crate) keypair: Keypair,
68 pub(crate) identity: KeypairIdentity,
69}
70
71#[derive(Clone)]
73pub(crate) struct KeypairIdentity {
74 pub(crate) public: identity::PublicKey,
76 pub(crate) signature: Vec<u8>,
78}
79
80impl Keypair {
81 pub(crate) fn secret(&self) -> &SecretKey {
83 &self.secret
84 }
85
86 pub(crate) fn into_authentic(
89 self,
90 id_keys: &identity::Keypair,
91 ) -> Result<AuthenticKeypair, Error> {
92 let sig = id_keys.sign(&[STATIC_KEY_DOMAIN.as_bytes(), self.public.as_ref()].concat())?;
93
94 let identity = KeypairIdentity {
95 public: id_keys.public(),
96 signature: sig,
97 };
98
99 Ok(AuthenticKeypair {
100 keypair: self,
101 identity,
102 })
103 }
104
105 pub(crate) fn empty() -> Self {
108 Keypair {
109 secret: SecretKey([0u8; 32]),
110 public: PublicKey([0u8; 32]),
111 }
112 }
113
114 pub(crate) fn new() -> Keypair {
116 let mut sk_bytes = [0u8; 32];
117 rand::thread_rng().fill(&mut sk_bytes);
118 let sk = SecretKey(sk_bytes); sk_bytes.zeroize();
120 Self::from(sk)
121 }
122}
123
124#[derive(Clone, Default)]
126pub(crate) struct SecretKey([u8; 32]);
127
128impl Drop for SecretKey {
129 fn drop(&mut self) {
130 self.0.zeroize()
131 }
132}
133
134impl AsRef<[u8]> for SecretKey {
135 fn as_ref(&self) -> &[u8] {
136 self.0.as_ref()
137 }
138}
139
140#[derive(Clone, PartialEq, Default)]
142pub(crate) struct PublicKey([u8; 32]);
143
144impl PublicKey {
145 pub(crate) fn from_slice(slice: &[u8]) -> Result<Self, Error> {
146 if slice.len() != 32 {
147 return Err(Error::InvalidLength);
148 }
149
150 let mut key = [0u8; 32];
151 key.copy_from_slice(slice);
152 Ok(PublicKey(key))
153 }
154}
155
156impl AsRef<[u8]> for PublicKey {
157 fn as_ref(&self) -> &[u8] {
158 self.0.as_ref()
159 }
160}
161
162struct Resolver;
167
168impl snow::resolvers::CryptoResolver for Resolver {
169 fn resolve_rng(&self) -> Option<Box<dyn snow::types::Random>> {
170 Some(Box::new(Rng(rand::rngs::StdRng::from_entropy())))
171 }
172
173 fn resolve_dh(&self, choice: &snow::params::DHChoice) -> Option<Box<dyn snow::types::Dh>> {
174 if let snow::params::DHChoice::Curve25519 = choice {
175 Some(Box::new(Keypair::empty()))
176 } else {
177 None
178 }
179 }
180
181 fn resolve_hash(
182 &self,
183 choice: &snow::params::HashChoice,
184 ) -> Option<Box<dyn snow::types::Hash>> {
185 #[cfg(target_arch = "wasm32")]
186 {
187 snow::resolvers::DefaultResolver.resolve_hash(choice)
188 }
189 #[cfg(not(target_arch = "wasm32"))]
190 {
191 snow::resolvers::RingResolver.resolve_hash(choice)
192 }
193 }
194
195 fn resolve_cipher(
196 &self,
197 choice: &snow::params::CipherChoice,
198 ) -> Option<Box<dyn snow::types::Cipher>> {
199 #[cfg(target_arch = "wasm32")]
200 {
201 snow::resolvers::DefaultResolver.resolve_cipher(choice)
202 }
203 #[cfg(not(target_arch = "wasm32"))]
204 {
205 snow::resolvers::RingResolver.resolve_cipher(choice)
206 }
207 }
208}
209
210struct Rng(rand::rngs::StdRng);
212
213impl rand::RngCore for Rng {
214 fn next_u32(&mut self) -> u32 {
215 self.0.next_u32()
216 }
217
218 fn next_u64(&mut self) -> u64 {
219 self.0.next_u64()
220 }
221
222 fn fill_bytes(&mut self, dest: &mut [u8]) {
223 self.0.fill_bytes(dest)
224 }
225
226 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
227 self.0.try_fill_bytes(dest)
228 }
229}
230
231impl rand::CryptoRng for Rng {}
232
233impl snow::types::Random for Rng {}
234
235impl Default for Keypair {
236 fn default() -> Self {
237 Self::new()
238 }
239}
240
241impl From<SecretKey> for Keypair {
243 fn from(secret: SecretKey) -> Keypair {
244 let public = PublicKey(x25519(secret.0, X25519_BASEPOINT_BYTES));
245 Keypair { secret, public }
246 }
247}
248
249#[doc(hidden)]
250impl snow::types::Dh for Keypair {
251 fn name(&self) -> &'static str {
252 "25519"
253 }
254 fn pub_len(&self) -> usize {
255 32
256 }
257 fn priv_len(&self) -> usize {
258 32
259 }
260 fn pubkey(&self) -> &[u8] {
261 self.public.as_ref()
262 }
263 fn privkey(&self) -> &[u8] {
264 self.secret.as_ref()
265 }
266
267 fn set(&mut self, sk: &[u8]) {
268 let mut secret = [0u8; 32];
269 secret.copy_from_slice(sk);
270 self.secret = SecretKey(secret); self.public = PublicKey(x25519(secret, X25519_BASEPOINT_BYTES));
272 secret.zeroize();
273 }
274
275 fn generate(&mut self, rng: &mut dyn snow::types::Random) {
276 let mut secret = [0u8; 32];
277 rng.fill_bytes(&mut secret);
278 self.secret = SecretKey(secret); self.public = PublicKey(x25519(secret, X25519_BASEPOINT_BYTES));
280 secret.zeroize();
281 }
282
283 fn dh(&self, pk: &[u8], shared_secret: &mut [u8]) -> Result<(), snow::Error> {
284 let mut p = [0; 32];
285 p.copy_from_slice(&pk[..32]);
286 let ss = x25519(self.secret.0, p);
287 shared_secret[..32].copy_from_slice(&ss[..]);
288 Ok(())
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use crate::protocol::PARAMS_XX;
296 use once_cell::sync::Lazy;
297
298 #[test]
299 fn handshake_hashes_disagree_if_prologue_differs() {
300 let alice = xx_builder(b"alice prologue").build_initiator().unwrap();
301 let bob = xx_builder(b"bob prologue").build_responder().unwrap();
302
303 let alice_handshake_hash = alice.get_handshake_hash();
304 let bob_handshake_hash = bob.get_handshake_hash();
305
306 assert_ne!(alice_handshake_hash, bob_handshake_hash)
307 }
308
309 #[test]
310 fn handshake_hashes_agree_if_prologue_is_the_same() {
311 let alice = xx_builder(b"shared knowledge").build_initiator().unwrap();
312 let bob = xx_builder(b"shared knowledge").build_responder().unwrap();
313
314 let alice_handshake_hash = alice.get_handshake_hash();
315 let bob_handshake_hash = bob.get_handshake_hash();
316
317 assert_eq!(alice_handshake_hash, bob_handshake_hash)
318 }
319
320 fn xx_builder(prologue: &'static [u8]) -> snow::Builder<'static> {
321 noise_params_into_builder(PARAMS_XX.clone(), prologue, TEST_KEY.secret(), None)
322 }
323
324 static TEST_KEY: Lazy<Keypair> = Lazy::new(Keypair::new);
326}