Skip to content

Commit

Permalink
Merge pull request #20 from nyonson/proxy-v2-v2
Browse files Browse the repository at this point in the history
Refactor Handshake interface to be more sans-i/o
  • Loading branch information
nyonson authored Apr 11, 2024
2 parents dc43dac + 7604e9d commit e60e242
Show file tree
Hide file tree
Showing 6 changed files with 509 additions and 709 deletions.
29 changes: 0 additions & 29 deletions protocol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,6 @@

Alice and Bob initiate a connection by sending three messages to each other to derive a number of shared secrets. Alice begins the connection by deriving a public/private keypair over `secp256k1`, the typical Bitcoin curve. Alice is known as the initiator. She encodes the public key in the [Elligator Swift](https://eprint.iacr.org/2022/759.pdf) format (64-bytes), optionally pads it with some random garbage bytes, and sends the message to Bob. Bob, known as the responder, decodes the Elligator Swift public key, and derives an ephemeral public/private keypair himself. Using his public and private keys, as well as Alice's public key, Bob performs a variation of the Elliptic Curve Diffie Hellman algorithm to derive a shared key. From this shared key, Bob derives multiple keys and a session ID using the HKDF algorithm. Next, Bob creates garbage data, and sends his public key, garbage data, an encrypted packet using the garbage data, and a version negotiation to Alice. With Bob's public key, Alice derives the shared secret and ensures the decrypted packet is authenticated with the garbage Bob sent her. Finally, Alice sends a "garbage terminator" and an encrypted packet using her garbage data, so Bob may authenticate she derived the correct secret and he can decode her messages. Alice and Bob may now freely exchange encrypted messages over the Bitcoin P2P protocol.

The crate exposes 4 functions, of which each party need to call only two for a complete handshake. For encrypting and decrypting messages, a `PacketHandler` struct is exposed with two methods. All messages are expected to be a `Vec<u8>` arrays of bytes, as this structure works well with `TcpStream` from the standard library and Bitcoin P2P messages. To initiate a handshake Alice calls `initialize_v2_handshake` and `initiator_complete_v2_handshake`. Similarly, to respond to a V2 handshake, Bob calls `receive_v2_handshake` and `responder_complete_v2_handshake`. Each function creates the appropriate message as well as additional data or structures to complete the handshake. Errors thrown by each of these functions should result in disconnection from the peer.

```rust
use bip324::{initialize_v2_handshake, initiator_complete_v2_handshake, receive_v2_handshake, responder_complete_v2_handshake};
fn main() {
// Alice starts a connection with Bob by making a pub/priv keypair and sending a message to Bob.
let handshake_init = initialize_v2_handshake(None).unwrap();
// Bob parses Alice's message, generates his pub/priv key, and sends a message back.
let mut bob_handshake = receive_v2_handshake(handshake_init.message.clone()).unwrap();
// Alice finishes her handshake by using her keys from earlier, and sending a final message to Bob.
let alice_completion = initiator_complete_v2_handshake(bob_handshake.message.clone(), handshake_init).unwrap();
// Bob checks Alice derived the correct keys for the session by authenticating her first message.
let _bob_completion = responder_complete_v2_handshake(alice_completion.message.clone(), &mut bob_handshake).unwrap();
// Alice and Bob can freely exchange encrypted messages using the packet handler returned by each handshake.
let mut alice = alice_completion.packet_handler;
let mut bob = bob_handshake.packet_handler;
let message = b"Hello world".to_vec();
let encrypted_message_to_alice = bob.prepare_v2_packet(message.clone(), None, false).unwrap();
let messages = alice.receive_v2_packets(encrypted_message_to_alice, None).unwrap();
let secret_message = messages.first().unwrap().message.clone().unwrap();
assert_eq!(message, secret_message);
let message = b"Goodbye!".to_vec();
let encrypted_message_to_bob = alice.prepare_v2_packet(message.clone(), None, false).unwrap();
let messages = bob.receive_v2_packets(encrypted_message_to_bob, None).unwrap();
let secret_message = messages.first().unwrap().message.clone().unwrap();
assert_eq!(message, secret_message);
}
```

There are also `no_std` compliant versions of these functions which require an RNG to be initialized by the consumer.

## ChaCha20Poly1305
Expand Down
Loading

0 comments on commit e60e242

Please sign in to comment.