An open API service indexing awesome lists of open source software.

https://github.com/honne23/simple_noise_handshake

A simplified rust project demonstrating the Noise protocol handshake on a public peer-to-peer node.
https://github.com/honne23/simple_noise_handshake

blockchain libp2p noise-protocol p2p rust tutorial-code

Last synced: 3 months ago
JSON representation

A simplified rust project demonstrating the Noise protocol handshake on a public peer-to-peer node.

Awesome Lists containing this project

README

          

# Simple noise handshake
This repository supplies a simplified implementation of the `Noise` handshake such that it only supports the `XX` handshake compatible with libp2p nodes (such as those on the `IPFS` network).

`Connections` are generic objects that can manage an underlying byte stream over the network. The `Multistream` connection has been implemented for the purposes of this repository.

`HandShakes` represent the logic for authentication handshakes that can take place over the network to secure a connection. This repository only allows you to `read` and `write` from a `SecureChannel`.

## Entrypoint
See `tests/` for examples on the usage of the library.

## Traits
Library defines the following traits to implement `Connection`s and `HandShake`s:

```rust
pub trait Connection {

/// Connect to a remote peer using their [std::net::SocketAddr]
fn connect(address: SocketAddr) -> Result>
where
Self: Sized;

/// Upgrade the connection to a [SecureChannel] for communication
fn upgrade<'a, H: HandShake<'a, Self> + 'a>(
connection: Self,
peer_id: Keypair,
) -> Result, Box>
where
Self: Sized + 'a;
}
```

```rust
pub trait HandShake<'a, C: Connection> {
/// Channel lifetime is tied to the lifetime of the Connection
type Channel<'channel>: SecureChannel;

/// Upgrade a connection into a secure channel, this method takes ownershup of the connection
/// so the raw connection can never be used to communicate.
/// [`Reader`] is a function that takes a connection and reads content from the underlying stream.
/// [`Writer`] is a function that takes a connection and and some encrypted content and write it to the underlying stream.
fn upgrade(
connection: C,
peer_id: Keypair,
reader: Reader,
writer: Writer,
) -> Result, Box>
where
C: Connection,
Reader: Fn(&mut C) -> Result, Box> + 'a,
Writer: Fn(&mut C, &[u8]) -> Result<(), Box> + 'a;
}

pub trait SecureChannel {
/// A function that allows a secure channel to securely write to the underlying stream.
fn write(&mut self, data: &[u8]) -> Result<(), Box>;

/// A function that allows a secure channel to read securely from the underlying stream.
fn read(&mut self) -> Result, Box>;
}
```

## Testing
## Peer list
Known working peers (tested):
- 147.75.84.175:4001 (Web3 Storage) https://github.com/web3-storage/web3.storage/blob/main/PEERS
- 139.178.88.145:4001 (Web3 Storage)
- 5.161.92.43:4001 (StorJ) https://docs.ipfs.tech/how-to/peering-with-content-providers/#content-provider-list

### All Tests:
```bash
cargo test
```
### All tests with debug output
```bash
cargo test -- -nocapture
```

### Only integration test and override default remote peer
```bash
export PEER_ADDR="139.178.88.145:4001"
cargo test --package noise_handshake --test noise_handshake_integration -- noise::test_handshake --exact --nocapture
```

### Verify output
The integration test should print out `YAMUX RESP: "\u{13}/multistream/1.0.0\n\u{f}/ipfs/id/1.0.0\n"` upon successful connection to a peer to
indicate that the `authentication` handshake and `multiplexer` has been negotiated.

## Where to go from here?
- The `CipherState` implemention is barebones and likely lacks quite a few security checks (such as bounds on the `Nonces`)
- At the moment there is no implementation for `async Connections`, these could straightforwardly be support by the `TokioTcpStream` as opposed to the `std::net::TcpStream` in use now.
- Multiplexing is not implemented correctly outside of the integration test, support for `Yamux` and more general multiplexing should be developed
- There are alot of `heap` allocations throughout, the hot-paths can likely be optimised to work more directly with slice references, it would be best to review this after implementing `async Connections` to ensure we don't run into borrower semantics indirectly.

## Peering sources
1. https://docs.ipfs.tech/how-to/peering-with-content-providers/#content-provider-list
2. https://github.com/web3-storage/web3.storage/blob/main/PEERS

## References
1. https://ipfs.io/ipfs/QmR7GSQM93Cx5eAg6a6yRzNde1FQv7uL6X1o4k7zrJa3LX/ipfs.draft3.pdf
2. https://github.com/libp2p/specs/blob/master/connections/README.md
3. https://github.com/libp2p/specs/blob/master/noise/README.md
4. https://noiseprotocol.org/noise.html
5. https://github.com/mcginty/snow
6. https://github.com/libp2p/rust-libp2p/tree/master/transports/noise
7. https://github.com/libp2p/go-libp2p/tree/master/p2p/security/noise