Skip to content

Commit

Permalink
fix(gossipsub): signed messages use monotonically increasing seq numbers
Browse files Browse the repository at this point in the history
This modifies the gossipsub implementation to use monotonically increasing sequence numbers for signed messages (as dictated by the specification). There is a discussion about this in #3453. This change will make rust-libp2p gossipsub align with the go-implementation when messages are signed.

Messages will however still use randomized sequence numbers when messages are unsigned for security reasons (as discussed in the issue linked).

This shouldn't change any user-level API, only the seqno behavior. It is fully backwards compatible.

Resolves #3453.

Pull-Request: #3551.
  • Loading branch information
AgeManning authored Mar 14, 2023
1 parent 2a18f7a commit eb5e269
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 8 deletions.
7 changes: 7 additions & 0 deletions protocols/gossipsub/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 0.44.2 - unreleased

- Signed messages now use sequential integers in the sequence number field.
See [PR 3551].

[PR 3551]: https://github.com/libp2p/rust-libp2p/pull/3551

# 0.44.1

- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].
Expand Down
16 changes: 11 additions & 5 deletions protocols/gossipsub/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ mod tests;
#[derive(Clone)]
pub enum MessageAuthenticity {
/// Message signing is enabled. The author will be the owner of the key and the sequence number
/// will be a random number.
/// will be linearly increasing.
Signed(Keypair),
/// Message signing is disabled.
///
Expand Down Expand Up @@ -155,6 +155,8 @@ enum PublishConfig {
keypair: Keypair,
author: PeerId,
inline_key: Option<Vec<u8>>,
last_seq_no: u64, // This starts from a random number and increases then overflows (if
// required)
},
Author(PeerId),
RandomAuthor,
Expand Down Expand Up @@ -190,6 +192,7 @@ impl From<MessageAuthenticity> for PublishConfig {
keypair,
author: public_key.to_peer_id(),
inline_key: key,
last_seq_no: rand::random(),
}
}
MessageAuthenticity::Author(peer_id) => PublishConfig::Author(peer_id),
Expand Down Expand Up @@ -2749,18 +2752,21 @@ where

/// Constructs a [`RawMessage`] performing message signing if required.
pub(crate) fn build_raw_message(
&self,
&mut self,
topic: TopicHash,
data: Vec<u8>,
) -> Result<RawMessage, PublishError> {
match &self.publish_config {
match &mut self.publish_config {
PublishConfig::Signing {
ref keypair,
author,
inline_key,
mut last_seq_no,
} => {
// Build and sign the message
let sequence_number: u64 = rand::random();
// Increment the last sequence number
last_seq_no = last_seq_no.wrapping_add(1);

let sequence_number = last_seq_no;

let signature = {
let message = proto::Message {
Expand Down
5 changes: 3 additions & 2 deletions protocols/gossipsub/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@
//! - **Sequence Numbers** - A message on the gossipsub network is identified by the source
//! [`libp2p_core::PeerId`] and a nonce (sequence number) of the message. The sequence numbers in
//! this implementation are sent as raw bytes across the wire. They are 64-bit big-endian unsigned
//! integers. They are chosen at random in this implementation of gossipsub, but are sequential in
//! the current go implementation.
//! integers. When messages are signed, they are monotonically increasing integers starting from a
//! random value and wrapping around u64::MAX. When messages are unsigned, they are chosen at random.
//! NOTE: These numbers are sequential in the current go implementation.
//!
//! # Peer Discovery
//!
Expand Down
2 changes: 1 addition & 1 deletion protocols/gossipsub/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ mod tests {

// generate an arbitrary GossipsubMessage using the behaviour signing functionality
let config = Config::default();
let gs: Behaviour =
let mut gs: Behaviour =
Behaviour::new(crate::MessageAuthenticity::Signed(keypair.0), config).unwrap();
let data = (0..g.gen_range(10..10024u32))
.map(|_| u8::arbitrary(g))
Expand Down

0 comments on commit eb5e269

Please sign in to comment.