-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Encrypted + unencrypted codec examples
- Loading branch information
RJ Rybarczyk
committed
Oct 3, 2024
1 parent
b820b23
commit 0af6182
Showing
3 changed files
with
293 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
use binary_sv2::{binary_codec_sv2, Deserialize, Serialize}; | ||
use codec_sv2::{ | ||
HandshakeRole, Initiator, NoiseEncoder, Responder, StandardEitherFrame, StandardNoiseDecoder, | ||
State, Sv2Frame, | ||
}; | ||
use const_sv2::{ | ||
INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE, RESPONDER_EXPECTED_HANDSHAKE_MESSAGE_SIZE, | ||
}; | ||
use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; | ||
use std::{ | ||
convert::TryInto, | ||
io::{Read, Write}, | ||
net::{TcpListener, TcpStream}, | ||
}; | ||
|
||
// Arbitrary message type. | ||
// Supported Sv2 message types are listed in the [Sv2 Spec Message | ||
// Types](https://github.com/stratum-mining/sv2-spec/blob/main/08-Message-Types.md). | ||
const CUSTOM_MSG_TYPE: u8 = 0xff; | ||
|
||
// Emulate a TCP connection | ||
const TCP_ADDR: &str = "127.0.0.1:3333"; | ||
const RECEIVER_PUBLIC_K: &str = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72"; | ||
const RECEIVER_PRIVATE_K: &str = "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n"; | ||
const RECEIVER_CERT_VALIDITY: std::time::Duration = std::time::Duration::from_secs(3600); | ||
|
||
// Example message type. | ||
// In practice, all Sv2 messages are defined in the following crates: | ||
// * `common_messages_sv2` | ||
// * `mining_sv2` | ||
// * `job_declaration_sv2` | ||
// * `template_distribution_sv2` | ||
#[derive(Debug, Serialize, Deserialize, Clone)] | ||
pub struct CustomMessage { | ||
nonce: u16, | ||
} | ||
|
||
fn main() { | ||
// Start a receiving listener | ||
let listener_receiver = TcpListener::bind(TCP_ADDR).expect("Failed to bind TCP listener"); | ||
|
||
// Start a sender stream | ||
let mut stream_sender: TcpStream = | ||
TcpStream::connect(TCP_ADDR).expect("Failed to connect to TCP stream"); | ||
|
||
// Start a receiver stream | ||
let mut stream_receiver: TcpStream = listener_receiver | ||
.incoming() | ||
.next() | ||
.expect("Failed to accept incoming TCP stream") | ||
.expect("Failed to connect to incoming TCP stream"); | ||
|
||
// Handshake | ||
let receiver_public_k: Secp256k1PublicKey = RECEIVER_PUBLIC_K | ||
.to_string() | ||
.try_into() | ||
.expect("Failed to convert receiver public key to Secp256k1PublicKey"); | ||
|
||
let receiver_private_k: Secp256k1SecretKey = RECEIVER_PRIVATE_K | ||
.to_string() | ||
.try_into() | ||
.expect("Failed to convert receiver private key to Secp256k1PublicKey"); | ||
|
||
let initiator = Initiator::from_raw_k(receiver_public_k.into_bytes()) | ||
.expect("Failed to create initiator role from raw pub key"); | ||
|
||
let responder = Responder::from_authority_kp( | ||
&receiver_public_k.into_bytes(), | ||
&receiver_private_k.into_bytes(), | ||
RECEIVER_CERT_VALIDITY, | ||
) | ||
.expect("Failed to initialize responder from pub/key pair and/or cert"); | ||
|
||
let mut sender_state = codec_sv2::State::initialized(HandshakeRole::Initiator(initiator)); | ||
let mut receiver_state = codec_sv2::State::initialized(HandshakeRole::Responder(responder)); | ||
|
||
let first_message = sender_state | ||
.step_0() | ||
.expect("Initiator failed first step of handshake"); | ||
let first_message: [u8; RESPONDER_EXPECTED_HANDSHAKE_MESSAGE_SIZE] = first_message | ||
.get_payload_when_handshaking() | ||
.try_into() | ||
.expect("Handshake remote invlaid message"); | ||
|
||
let (second_message, receiver_state) = receiver_state | ||
.step_1(first_message) | ||
.expect("Responder failed second step of handshake"); | ||
let second_message: [u8; INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE] = second_message | ||
.get_payload_when_handshaking() | ||
.try_into() | ||
.expect("Handshake remote invlaid message"); | ||
|
||
let sender_state = sender_state | ||
.step_2(second_message) | ||
.expect("Initiator failed third step of handshake"); | ||
|
||
let mut sender_state = match sender_state { | ||
State::Transport(c) => State::with_transport_mode(c), | ||
_ => panic!("todo"), | ||
}; | ||
|
||
let mut receiver_state = match receiver_state { | ||
State::Transport(c) => State::with_transport_mode(c), | ||
_ => panic!("todo"), | ||
}; | ||
|
||
// Create a message | ||
let nonce = 1337; | ||
let msg = CustomMessage { nonce }; | ||
let msg_type = CUSTOM_MSG_TYPE; | ||
// Unique identifier of the extension describing the protocol message, as defined by Sv2 Framing | ||
let extension_type = 0; | ||
// This message is intended for the receiver, so set to false | ||
let channel_msg = false; | ||
|
||
let frame = StandardEitherFrame::<CustomMessage>::Sv2( | ||
Sv2Frame::from_message(msg, msg_type, extension_type, channel_msg) | ||
.expect("Failed to create the frame"), | ||
); | ||
|
||
let mut encoder = NoiseEncoder::<CustomMessage>::new(); | ||
let encoded_frame = encoder | ||
.encode(frame, &mut sender_state) | ||
.expect("Failed to encode the frame"); | ||
|
||
// Send the encoded frame | ||
stream_sender | ||
.write_all(encoded_frame.as_slice()) | ||
.expect("Failed to send the encoded frame"); | ||
|
||
// Receiver side | ||
let mut decoder = StandardNoiseDecoder::<CustomMessage>::new(); | ||
let decoder_buf = decoder.writable(); | ||
// Read the frame header into the decoder buffer | ||
stream_receiver | ||
.read_exact(decoder_buf) | ||
.expect("Failed to read the encoded frame header"); | ||
|
||
// This returns a `MissingBytes` error because it only reads the header as there is no payload | ||
// in memory yet. Therefore, we safely ignore the error as the important thing here is that we | ||
// loaded the `decoder.missing_b` with the expected frame payload size | ||
let _ = decoder.next_frame(&mut receiver_state); | ||
|
||
// Now the decoder buffer has the expected size of the frame payload | ||
let decoder_buf = decoder.writable(); | ||
|
||
// Read the payload into the decoder buffer | ||
stream_receiver | ||
.read_exact(decoder_buf) | ||
.expect("Failed to read the encoded frame payload"); | ||
|
||
// INCORRECT PANIC HERE (DO NOT MERGE): | ||
// Decode the frame | ||
let _decoded_frame = decoder | ||
.next_frame(&mut receiver_state) | ||
.expect("Failed to decode the frame"); | ||
|
||
// let decoded_frame_header = decoded_frame | ||
// .get_header() | ||
// .expect("Failed to get the frame header"); | ||
// let decoded_msg: CustomMessage = binary_sv2::from_bytes(decoded_frame.payload()) | ||
// .expect("Failed to extract the message from the payload"); | ||
// | ||
// // Assert that the decoded message is as expected | ||
// assert_eq!(decoded_frame_header.msg_type(), CUSTOM_MSG_TYPE); | ||
// assert_eq!(decoded_msg.nonce, nonce); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
use binary_sv2::{binary_codec_sv2, Deserialize, Serialize}; | ||
use codec_sv2::{Encoder, StandardDecoder, StandardSv2Frame, Sv2Frame}; | ||
use std::{ | ||
convert::TryInto, | ||
io::{Read, Write}, | ||
net::{TcpListener, TcpStream}, | ||
}; | ||
|
||
// Arbitrary message type. | ||
// Supported Sv2 message types are listed in the [Sv2 Spec Message | ||
// Types](https://github.com/stratum-mining/sv2-spec/blob/main/08-Message-Types.md). | ||
const CUSTOM_MSG_TYPE: u8 = 0xff; | ||
|
||
// Emulate a TCP connection | ||
const TCP_ADDR: &str = "127.0.0.1:3333"; | ||
|
||
// Example message type. | ||
// In practice, all Sv2 messages are defined in the following crates: | ||
// * `common_messages_sv2` | ||
// * `mining_sv2` | ||
// * `job_declaration_sv2` | ||
// * `template_distribution_sv2` | ||
#[derive(Debug, Serialize, Deserialize, Clone)] | ||
pub struct CustomMessage { | ||
nonce: u16, | ||
} | ||
|
||
fn main() { | ||
// Start a receiving listener | ||
let listener_receiver = TcpListener::bind(TCP_ADDR).expect("Failed to bind TCP listener"); | ||
|
||
// Start a sender stream | ||
let stream_sender: TcpStream = | ||
TcpStream::connect(TCP_ADDR).expect("Failed to connect to TCP stream"); | ||
|
||
// Start a receiver stream | ||
let stream_receiver: TcpStream = listener_receiver | ||
.incoming() | ||
.next() | ||
.expect("Failed to accept incoming TCP stream") | ||
.expect("Failed to connect to incoming TCP stream"); | ||
|
||
// Server Side | ||
|
||
// Create a message | ||
let nonce = 1337; | ||
let msg = CustomMessage { nonce }; | ||
let msg_type = CUSTOM_MSG_TYPE; | ||
// Unique identifier of the extension describing the protocol message, as defined by Sv2 Framing | ||
let extension_type = 0; | ||
// This message is intended for the receiver, so set to false | ||
let channel_msg = false; | ||
sender_side(stream_sender, msg, msg_type, extension_type, channel_msg); | ||
|
||
// Receiver Side | ||
let mut decoded_frame = receiver_side(stream_receiver); | ||
|
||
let decoded_frame_header = decoded_frame | ||
.get_header() | ||
.expect("Failed to get the frame header"); | ||
let decoded_msg: CustomMessage = binary_sv2::from_bytes(decoded_frame.payload()) | ||
.expect("Failed to extract the message from the payload"); | ||
|
||
// Assert that the decoded message is as expected | ||
assert_eq!(decoded_frame_header.msg_type(), CUSTOM_MSG_TYPE); | ||
assert_eq!(decoded_msg.nonce, nonce); | ||
} | ||
|
||
fn sender_side( | ||
mut stream_sender: TcpStream, | ||
msg: CustomMessage, | ||
msg_type: u8, | ||
extension_type: u16, | ||
channel_msg: bool, | ||
) { | ||
// Create the frame | ||
let frame = | ||
StandardSv2Frame::<CustomMessage>::from_message(msg, msg_type, extension_type, channel_msg) | ||
.expect("Failed to create the frame"); | ||
|
||
// Encode the frame | ||
let mut encoder = Encoder::<CustomMessage>::new(); | ||
let encoded_frame = encoder | ||
.encode(frame.clone()) | ||
.expect("Failed to encode the frame"); | ||
|
||
// Send the encoded frame | ||
stream_sender | ||
.write_all(encoded_frame) | ||
.expect("Failed to send the encoded frame"); | ||
} | ||
|
||
fn receiver_side(mut stream_receiver: TcpStream) -> Sv2Frame<CustomMessage, Vec<u8>> { | ||
// Initialize the decoder | ||
let mut decoder = StandardDecoder::<CustomMessage>::new(); | ||
|
||
// At this point, the decoder buffer can only read a frame header because the | ||
// decoder.missing_b is initialized with a header size | ||
let decoder_buf = decoder.writable(); | ||
|
||
// Read the frame header into the decoder buffer | ||
stream_receiver | ||
.read_exact(decoder_buf) | ||
.expect("Failed to read the encoded frame header"); | ||
|
||
// This returns a `MissingBytes` error because it only reads the header as there is no payload | ||
// in memory yet. Therefore, we safely ignore the error as the important thing here is that we | ||
// loaded the `decoder.missing_b` with the expected frame payload size | ||
let _ = decoder.next_frame(); | ||
|
||
// Now the decoder buffer has the expected size of the frame payload | ||
let decoder_buf = decoder.writable(); | ||
|
||
// Read the payload into the decoder buffer | ||
stream_receiver | ||
.read_exact(decoder_buf) | ||
.expect("Failed to read the encoded frame payload"); | ||
|
||
// Decode the frame | ||
let decoded_frame = decoder.next_frame().expect("Failed to decode the frame"); | ||
|
||
return decoded_frame; | ||
} |