libp2p_webrtc_utils/
noise.rs

1// Copyright 2022 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use futures::{AsyncRead, AsyncWrite, AsyncWriteExt};
22use libp2p_core::{
23    upgrade::{InboundConnectionUpgrade, OutboundConnectionUpgrade},
24    UpgradeInfo,
25};
26use libp2p_identity as identity;
27use libp2p_identity::PeerId;
28use libp2p_noise as noise;
29pub use noise::Error;
30
31use crate::fingerprint::Fingerprint;
32
33pub async fn inbound<T>(
34    id_keys: identity::Keypair,
35    stream: T,
36    client_fingerprint: Fingerprint,
37    server_fingerprint: Fingerprint,
38) -> Result<PeerId, Error>
39where
40    T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
41{
42    let noise = noise::Config::new(&id_keys)
43        .unwrap()
44        .with_prologue(noise_prologue(client_fingerprint, server_fingerprint));
45    let info = noise.protocol_info().next().unwrap();
46    // Note the roles are reversed because it allows the server (webrtc connection responder) to
47    // send application data 0.5 RTT earlier.
48    let (peer_id, mut channel) = noise.upgrade_outbound(stream, info).await?;
49
50    channel.close().await?;
51
52    Ok(peer_id)
53}
54
55pub async fn outbound<T>(
56    id_keys: identity::Keypair,
57    stream: T,
58    server_fingerprint: Fingerprint,
59    client_fingerprint: Fingerprint,
60) -> Result<PeerId, Error>
61where
62    T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
63{
64    let noise = noise::Config::new(&id_keys)
65        .unwrap()
66        .with_prologue(noise_prologue(client_fingerprint, server_fingerprint));
67    let info = noise.protocol_info().next().unwrap();
68    // Note the roles are reversed because it allows the server (webrtc connection responder) to
69    // send application data 0.5 RTT earlier.
70    let (peer_id, mut channel) = noise.upgrade_inbound(stream, info).await?;
71
72    channel.close().await?;
73
74    Ok(peer_id)
75}
76
77pub(crate) fn noise_prologue(
78    client_fingerprint: Fingerprint,
79    server_fingerprint: Fingerprint,
80) -> Vec<u8> {
81    let client = client_fingerprint.to_multihash().to_bytes();
82    let server = server_fingerprint.to_multihash().to_bytes();
83    const PREFIX: &[u8] = b"libp2p-webrtc-noise:";
84    let mut out = Vec::with_capacity(PREFIX.len() + client.len() + server.len());
85    out.extend_from_slice(PREFIX);
86    out.extend_from_slice(&client);
87    out.extend_from_slice(&server);
88    out
89}
90
91#[cfg(test)]
92mod tests {
93    use hex_literal::hex;
94
95    use super::*;
96
97    #[test]
98    fn noise_prologue_tests() {
99        let a = Fingerprint::raw(hex!(
100            "3e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870"
101        ));
102        let b = Fingerprint::raw(hex!(
103            "30fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99"
104        ));
105
106        let prologue1 = noise_prologue(a, b);
107        let prologue2 = noise_prologue(b, a);
108
109        assert_eq!(hex::encode(prologue1), "6c69627032702d7765627274632d6e6f6973653a12203e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870122030fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b99");
110        assert_eq!(hex::encode(prologue2), "6c69627032702d7765627274632d6e6f6973653a122030fc9f469c207419dfdd0aab5f27a86c973c94e40548db9375cca2e915973b9912203e79af40d6059617a0d83b83a52ce73b0c1f37a72c6043ad2969e2351bdca870");
111    }
112}