Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust docs noise_sv2 #1111

Merged
merged 12 commits into from
Oct 14, 2024
31 changes: 31 additions & 0 deletions protocols/v2/noise-sv2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

# noise_sv2

[![crates.io](https://img.shields.io/crates/v/const_sv2.svg)](https://crates.io/crates/const_sv2)
[![docs.rs](https://docs.rs/const_sv2/badge.svg)](https://docs.rs/const_sv2)
[![rustc+](https://img.shields.io/badge/rustc-1.75.0%2B-lightgrey.svg)](https://blog.rust-lang.org/2023/12/28/Rust-1.75.0.html)
[![license](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/stratum-mining/stratum/blob/main/LICENSE.md)
[![codecov](https://codecov.io/gh/stratum-mining/stratum/branch/main/graph/badge.svg?flag=noise_sv2-coverage)](https://codecov.io/gh/stratum-mining/stratum)

`noise_sv2` is primarily intended to secure communication in the Stratum V2 (Sv2) protocol. It handles the necessary Noise handshakes, encrypts outgoing messages, and decrypts incoming responses, ensuring privacy and integrity across the communication link between Sv2 roles. See the [Protocol Security specification](https://github.com/stratum-mining/sv2-spec/blob/main/04-Protocol-Security.md) for more details.

## Key Capabilities
* **Secure Communication**: Provides encryption and authentication for messages exchanged between different Sv2 roles.
* **Cipher Support**: Includes support for both `AES-GCM` and `ChaCha20-Poly1305`.
* **Handshake Roles**: Implements the `Initiator` and `Responder` roles required by the Noise handshake, allowing both sides of a connection to establish secure communication.
* **Cryptographic Helpers**: Facilitates the management of cryptographic state and encryption operations.

## Usage
To include this crate in your project, run:

```bash
cargo add noise_sv2
Shourya742 marked this conversation as resolved.
Show resolved Hide resolved
Shourya742 marked this conversation as resolved.
Show resolved Hide resolved
```

### Examples

This crate provides example on establishing a secure line:

1. **[Noise Handshake Example](https://github.com/stratum-mining/stratum/blob/main/protocols/v2/noise-sv2/examples/handshake.rs)**:
Establish a secure line of communication between an Initiator and Responder via the Noise
protocol, allowing for the encryption and decryption of a secret message.
68 changes: 68 additions & 0 deletions protocols/v2/noise-sv2/examples/handshake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// # Noise Protocol Handshake
//
// This example demonstrates how to use the `noise-sv2` crate to establish a Noise handshake
// between and initiator and responder, and encrypt and decrypt a secret message. It showcases how
// to:
//
// - Generate a cryptographic keypair using the `secp256k1` library.
// - Perform a Noise handshake between an initiator and responder.
// - Transition from handshake to secure communication mode.
// - Encrypt a message as the initiator role.
// - Decrypt the message as the responder role.
//
// ## Run
//
// ```sh
// cargo run --example handshake
// ```

use noise_sv2::{Initiator, Responder};
use secp256k1::{Keypair, Parity, Secp256k1};

// Even parity used in the Schnorr signature process
const PARITY: Parity = Parity::Even;
// Validity duration of the responder's certificate, seconds
const RESPONDER_CERT_VALIDITY: u32 = 3600;

// Generates a secp256k1 public/private key pair for the responder.
fn generate_key() -> Keypair {
let secp = Secp256k1::new();
let (secret_key, _) = secp.generate_keypair(&mut rand::thread_rng());
let kp = Keypair::from_secret_key(&secp, &secret_key);
if kp.x_only_public_key().1 == PARITY {
kp
} else {
generate_key()
}
}

fn main() {
let mut secret_message = "Ciao, Mondo!".as_bytes().to_vec();

let responder_key_pair = generate_key();

let mut initiator = Initiator::new(Some(responder_key_pair.public_key().into()));
let mut responder = Responder::new(responder_key_pair, RESPONDER_CERT_VALIDITY);

let first_message = initiator
.step_0()
.expect("Initiator failed first step of handshake");

let (second_message, mut responder_state) = responder
.step_1(first_message)
.expect("Responder failed second step of handshake");

let mut initiator_state = initiator
.step_2(second_message)
.expect("Initiator failed third step of handshake");

initiator_state
.encrypt(&mut secret_message)
.expect("Initiator failed to encrypt the secret message");
assert!(secret_message != "Ciao, Mondo!".as_bytes().to_vec());

responder_state
.decrypt(&mut secret_message)
.expect("Responder failed to decrypt the secret message");
assert!(secret_message == "Ciao, Mondo!".as_bytes().to_vec());
}
50 changes: 50 additions & 0 deletions protocols/v2/noise-sv2/src/aed_cipher.rs
plebhash marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,16 +1,64 @@
// # AEAD Cipher
//
// Abstracts the encryption and decryption operations for authenticated encryption with associated
// data (AEAD) ciphers used in the Noise protocol.
//
// The [`AeadCipher`] trait provides a unified interface for AEAD ciphers, including
// [`ChaCha20Poly1305`] and [`Aes256Gcm`], allowing flexible cryptographic operations in different
// contexts.
//
// The trait supports core AEAD operations, including:
//
// - Key initialization via the `from_key` method to derive a cipher instance from a 32-byte key.
// - Authenticated encryption via the `encrypt` method to securely encrypt data with a nonce and
// additional associated data (AAD).
// - Authenticated decryption via the `decrypt` method to securely decrypt data using the provided
// nonce and AAD.
//
// ## Usage
//
// The `AeadCipher` trait can be implemented for any AEAD cipher, enabling encryption and decryption
// of Noise protocol messages. Two default implementations are provided for the
// [`ChaCha20Poly1305`] and [`Aes256Gcm`] ciphers.

use aes_gcm::Aes256Gcm;
use chacha20poly1305::{aead::Buffer, AeadInPlace, ChaCha20Poly1305, ChaChaPoly1305, KeyInit};

// Defines the interface for AEAD ciphers.
//
// The [`AeadCipher`] trait provides a standard interface for initializing AEAD ciphers, and for
// performing encryption and decryption operations with additional Authenticated Associated Data (AAD). This trait is implemented
// by either the [`ChaCha20Poly1305`] or [`Aes256Gcm`] specific cipher types, allowing them to be
// used interchangeably in cryptographic protocols. It is utilized by the
// [`crate::handshake::HandshakeOp`] trait to secure the handshake process.
//
// The `T: Buffer` represents the data buffer to be encrypted or decrypted. The buffer must
// implement the [`Buffer`] trait, which provides necessary operations for in-place encryption and
// decryption.
plebhash marked this conversation as resolved.
Show resolved Hide resolved
plebhash marked this conversation as resolved.
Show resolved Hide resolved
pub trait AeadCipher {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fi3 whats the goal behind this trait and then implementing it for ChaChaPoly1305 if the ChaCha.. already have some AEAD traits implemented for it https://docs.rs/chacha20poly1305/latest/src/chacha20poly1305/lib.rs.html#241 which is used in our implementation without any changes https://github.com/stratum-mining/stratum/pull/1111/files#diff-af2c2f10de68656c4249abc945c50c903ccfcd35bf169ce3a4779f1c4e5245e1L33?

Copy link
Collaborator

@plebhash plebhash Sep 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the existance of AeadCipher trait feels redundant.

see #1130 (comment)

// Creates a new instance of the cipher from a 32-byte key.
//
// Initializes the AEAD cipher with the provided key (`k`), preparing it for
// encryption and decryption operations.
fn from_key(k: [u8; 32]) -> Self;

// Encrypts the data in place using the provided 12-byte `nonce` and AAD (`ad`).
//
// Performs authenticated encryption on the provided mutable data buffer (`data`), modifying
// it in place to contain the ciphertext. The encryption is performed using the provided nonce
// and AAD, which ensures that the data has not been tampered with during transit.
fn encrypt<T: Buffer>(
&mut self,
nonce: &[u8; 12],
ad: &[u8],
data: &mut T,
) -> Result<(), aes_gcm::Error>;

// Decrypts the data in place using the provided 12-byte nonce (`n`) and AAD (`ad`).
//
// Performs authenticated decryption on the provided mutable data buffer, modifying it in
// place to contain the plaintext. The decryption is performed using the provided nonce and
// AAD, ensuring that the data has not been tampered with during transit.
fn decrypt<T: Buffer>(
&mut self,
nonce: &[u8; 12],
Expand Down Expand Up @@ -47,6 +95,7 @@ impl AeadCipher for Aes256Gcm {
fn from_key(k: [u8; 32]) -> Self {
Aes256Gcm::new(&k.into())
}

fn encrypt<T: Buffer>(
&mut self,
nonce: &[u8; 12],
Expand All @@ -55,6 +104,7 @@ impl AeadCipher for Aes256Gcm {
) -> Result<(), aes_gcm::Error> {
self.encrypt_in_place(nonce.into(), ad, data)
}

fn decrypt<T: Buffer>(
&mut self,
nonce: &[u8; 12],
Expand Down
Loading
Loading