• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

butlergroup / rust-libp2p / 18610913338

18 Oct 2025 04:41AM UTC coverage: 78.379% (+2.5%) from 75.842%
18610913338

push

github

butlergroup
	modified:   .github/workflows/ci.yml

36944 of 47135 relevant lines covered (78.38%)

37728.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.08
/transports/noise/src/lib.rs
1
// Copyright 2019 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

21
//! [Noise protocol framework][noise] support for libp2p.
22
//!
23
//! > **Note**: This crate is still experimental and subject to major breaking changes
24
//! > both on the API and the wire protocol.
25
//!
26
//! This crate provides `libp2p_core::InboundUpgrade` and `libp2p_core::OutboundUpgrade`
27
//! implementations for various noise handshake patterns (currently `IK`, `IX`, and `XX`)
28
//! over a particular choice of Diffie–Hellman key agreement (currently only X25519).
29
//!
30
//! > **Note**: Only the `XX` handshake pattern is currently guaranteed to provide
31
//! > interoperability with other libp2p implementations.
32
//!
33
//! All upgrades produce as output a pair, consisting of the remote's static public key
34
//! and a `NoiseOutput` which represents the established cryptographic session with the
35
//! remote, implementing `futures::io::AsyncRead` and `futures::io::AsyncWrite`.
36
//!
37
//! # Usage
38
//!
39
//! Example:
40
//!
41
//! ```
42
//! use libp2p_core::{transport::MemoryTransport, upgrade, Transport};
43
//! use libp2p_identity as identity;
44
//! use libp2p_noise as noise;
45
//!
46
//! # fn main() {
47
//! let id_keys = identity::Keypair::generate_ed25519();
48
//! let noise = noise::Config::new(&id_keys).unwrap();
49
//! let builder = MemoryTransport::default()
50
//!     .upgrade(upgrade::Version::V1)
51
//!     .authenticate(noise);
52
//! // let transport = builder.multiplex(...);
53
//! # }
54
//! ```
55
//!
56
//! [noise]: http://noiseprotocol.org/
57

58
#![cfg_attr(docsrs, feature(doc_cfg))]
59

60
mod io;
61
mod protocol;
62

63
use std::{collections::HashSet, fmt::Write, pin::Pin};
64

65
use futures::prelude::*;
66
pub use io::Output;
67
use libp2p_core::{
68
    upgrade::{InboundConnectionUpgrade, OutboundConnectionUpgrade},
69
    UpgradeInfo,
70
};
71
use libp2p_identity as identity;
72
use libp2p_identity::PeerId;
73
use multiaddr::Protocol;
74
use multihash::Multihash;
75
use snow::params::NoiseParams;
76

77
use crate::{
78
    handshake::State,
79
    io::handshake,
80
    protocol::{noise_params_into_builder, AuthenticKeypair, Keypair, PARAMS_XX},
81
};
82

83
/// The configuration for the noise handshake.
84
#[derive(Clone)]
85
pub struct Config {
86
    dh_keys: AuthenticKeypair,
87
    params: NoiseParams,
88
    webtransport_certhashes: Option<HashSet<Multihash<64>>>,
89

90
    /// Prologue to use in the noise handshake.
91
    ///
92
    /// The prologue can contain arbitrary data that will be hashed into the noise handshake.
93
    /// For the handshake to succeed, both parties must set the same prologue.
94
    ///
95
    /// For further information, see <https://noiseprotocol.org/noise.html#prologue>.
96
    prologue: Vec<u8>,
97
}
98

99
impl Config {
100
    /// Construct a new configuration for the noise handshake using the XX handshake pattern.
101
    pub fn new(identity: &identity::Keypair) -> Result<Self, Error> {
6,988✔
102
        let noise_keys = Keypair::new().into_authentic(identity)?;
6,988✔
103

104
        Ok(Self {
6,988✔
105
            dh_keys: noise_keys,
6,988✔
106
            params: PARAMS_XX.clone(),
6,988✔
107
            webtransport_certhashes: None,
6,988✔
108
            prologue: vec![],
6,988✔
109
        })
6,988✔
110
    }
6,988✔
111

112
    /// Set the noise prologue.
113
    pub fn with_prologue(mut self, prologue: Vec<u8>) -> Self {
×
114
        self.prologue = prologue;
×
115
        self
×
116
    }
×
117

118
    /// Set WebTransport certhashes extension.
119
    ///
120
    /// In case of initiator, these certhashes will be used to validate the ones reported by
121
    /// responder.
122
    ///
123
    /// In case of responder, these certhashes will be reported to initiator.
124
    pub fn with_webtransport_certhashes(mut self, certhashes: HashSet<Multihash<64>>) -> Self {
32✔
125
        self.webtransport_certhashes = Some(certhashes).filter(|h| !h.is_empty());
32✔
126
        self
32✔
127
    }
32✔
128

129
    fn into_responder<S: AsyncRead + AsyncWrite>(self, socket: S) -> Result<State<S>, Error> {
12,003✔
130
        let session = noise_params_into_builder(
12,003✔
131
            self.params,
12,003✔
132
            &self.prologue,
12,003✔
133
            self.dh_keys.keypair.secret(),
12,003✔
134
            None,
12,003✔
135
        )
136
        .build_responder()?;
12,003✔
137

138
        let state = State::new(
12,003✔
139
            socket,
12,003✔
140
            session,
12,003✔
141
            self.dh_keys.identity,
12,003✔
142
            None,
12,003✔
143
            self.webtransport_certhashes,
12,003✔
144
        );
145

146
        Ok(state)
12,003✔
147
    }
12,003✔
148

149
    fn into_initiator<S: AsyncRead + AsyncWrite>(self, socket: S) -> Result<State<S>, Error> {
11,841✔
150
        let session = noise_params_into_builder(
11,841✔
151
            self.params,
11,841✔
152
            &self.prologue,
11,841✔
153
            self.dh_keys.keypair.secret(),
11,841✔
154
            None,
11,841✔
155
        )
156
        .build_initiator()?;
11,841✔
157

158
        let state = State::new(
11,841✔
159
            socket,
11,841✔
160
            session,
11,841✔
161
            self.dh_keys.identity,
11,841✔
162
            None,
11,841✔
163
            self.webtransport_certhashes,
11,841✔
164
        );
165

166
        Ok(state)
11,841✔
167
    }
11,841✔
168
}
169

170
impl UpgradeInfo for Config {
171
    type Info = &'static str;
172
    type InfoIter = std::iter::Once<Self::Info>;
173

174
    fn protocol_info(&self) -> Self::InfoIter {
24,048✔
175
        std::iter::once("/noise")
24,048✔
176
    }
24,048✔
177
}
178

179
impl<T> InboundConnectionUpgrade<T> for Config
180
where
181
    T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
182
{
183
    type Output = (PeerId, Output<T>);
184
    type Error = Error;
185
    type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
186

187
    fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
12,003✔
188
        async move {
12,003✔
189
            let mut state = self.into_responder(socket)?;
12,003✔
190

191
            handshake::recv_empty(&mut state).await?;
12,003✔
192
            handshake::send_identity(&mut state).await?;
11,827✔
193
            handshake::recv_identity(&mut state).await?;
11,823✔
194

195
            let (pk, io) = state.finish()?;
11,367✔
196

197
            Ok((pk.to_peer_id(), io))
11,367✔
198
        }
11,424✔
199
        .boxed()
12,003✔
200
    }
12,003✔
201
}
202

203
impl<T> OutboundConnectionUpgrade<T> for Config
204
where
205
    T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
206
{
207
    type Output = (PeerId, Output<T>);
208
    type Error = Error;
209
    type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
210

211
    fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
11,841✔
212
        async move {
11,841✔
213
            let mut state = self.into_initiator(socket)?;
11,841✔
214

215
            handshake::send_empty(&mut state).await?;
11,841✔
216
            handshake::recv_identity(&mut state).await?;
11,839✔
217
            handshake::send_identity(&mut state).await?;
11,506✔
218

219
            let (pk, io) = state.finish()?;
11,506✔
220

221
            Ok((pk.to_peer_id(), io))
11,502✔
222
        }
11,508✔
223
        .boxed()
11,841✔
224
    }
11,841✔
225
}
226

227
/// libp2p_noise error type.
228
#[derive(Debug, thiserror::Error)]
229
#[non_exhaustive]
230
pub enum Error {
231
    #[error(transparent)]
232
    Io(#[from] std::io::Error),
233
    #[error(transparent)]
234
    Noise(#[from] snow::Error),
235
    #[error("Invalid public key")]
236
    InvalidKey(#[from] libp2p_identity::DecodingError),
237
    #[error("Only keys of length 32 bytes are supported")]
238
    InvalidLength,
239
    #[error("Remote authenticated with an unexpected public key")]
240
    UnexpectedKey,
241
    #[error("The signature of the remote identity's public key does not verify")]
242
    BadSignature,
243
    #[error("Authentication failed")]
244
    AuthenticationFailed,
245
    #[error("failed to decode protobuf ")]
246
    InvalidPayload(#[from] DecodeError),
247
    #[error(transparent)]
248
    #[allow(clippy::enum_variant_names)]
249
    SigningError(#[from] libp2p_identity::SigningError),
250
    #[error("Expected WebTransport certhashes ({}) are not a subset of received ones ({})", certhashes_to_string(.0), certhashes_to_string(.1))]
251
    UnknownWebTransportCerthashes(HashSet<Multihash<64>>, HashSet<Multihash<64>>),
252
}
253

254
#[derive(Debug, thiserror::Error)]
255
#[error(transparent)]
256
pub struct DecodeError(quick_protobuf::Error);
257

258
fn certhashes_to_string(certhashes: &HashSet<Multihash<64>>) -> String {
×
259
    let mut s = String::new();
×
260

261
    for hash in certhashes {
×
262
        write!(&mut s, "{}", Protocol::Certhash(*hash)).unwrap();
×
263
    }
×
264

265
    s
×
266
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc