fix(gossipsub): signed messages use monotonically increasing seq numbers

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.
This commit is contained in:
Age Manning
2023-03-14 11:06:01 +11:00
committed by GitHub
parent 2a18f7a5f0
commit eb5e269165
4 changed files with 22 additions and 8 deletions

View File

@ -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 # 0.44.1
- Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312]. - Migrate from `prost` to `quick-protobuf`. This removes `protoc` dependency. See [PR 3312].

View File

@ -80,7 +80,7 @@ mod tests;
#[derive(Clone)] #[derive(Clone)]
pub enum MessageAuthenticity { pub enum MessageAuthenticity {
/// Message signing is enabled. The author will be the owner of the key and the sequence number /// 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), Signed(Keypair),
/// Message signing is disabled. /// Message signing is disabled.
/// ///
@ -155,6 +155,8 @@ enum PublishConfig {
keypair: Keypair, keypair: Keypair,
author: PeerId, author: PeerId,
inline_key: Option<Vec<u8>>, inline_key: Option<Vec<u8>>,
last_seq_no: u64, // This starts from a random number and increases then overflows (if
// required)
}, },
Author(PeerId), Author(PeerId),
RandomAuthor, RandomAuthor,
@ -190,6 +192,7 @@ impl From<MessageAuthenticity> for PublishConfig {
keypair, keypair,
author: public_key.to_peer_id(), author: public_key.to_peer_id(),
inline_key: key, inline_key: key,
last_seq_no: rand::random(),
} }
} }
MessageAuthenticity::Author(peer_id) => PublishConfig::Author(peer_id), MessageAuthenticity::Author(peer_id) => PublishConfig::Author(peer_id),
@ -2749,18 +2752,21 @@ where
/// Constructs a [`RawMessage`] performing message signing if required. /// Constructs a [`RawMessage`] performing message signing if required.
pub(crate) fn build_raw_message( pub(crate) fn build_raw_message(
&self, &mut self,
topic: TopicHash, topic: TopicHash,
data: Vec<u8>, data: Vec<u8>,
) -> Result<RawMessage, PublishError> { ) -> Result<RawMessage, PublishError> {
match &self.publish_config { match &mut self.publish_config {
PublishConfig::Signing { PublishConfig::Signing {
ref keypair, ref keypair,
author, author,
inline_key, inline_key,
mut last_seq_no,
} => { } => {
// Build and sign the message // Increment the last sequence number
let sequence_number: u64 = rand::random(); last_seq_no = last_seq_no.wrapping_add(1);
let sequence_number = last_seq_no;
let signature = { let signature = {
let message = proto::Message { let message = proto::Message {

View File

@ -50,8 +50,9 @@
//! - **Sequence Numbers** - A message on the gossipsub network is identified by the source //! - **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 //! [`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 //! 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 //! integers. When messages are signed, they are monotonically increasing integers starting from a
//! the current go implementation. //! 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 //! # Peer Discovery
//! //!

View File

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