.
                                        .
         *
                                              
                    .
                                    .
                *
                                        
                      .
                                              .
            *
                                    *
                  .
                                        
                           *
                                              
                    .
                                    .
       *
                                        .
                      .
                                              
            .
                                    
                  .
                                        *
              
                                              .
                    
                                    .
                *
                                        
                      .
                                              .
                                   *
                                    
                  .
                                        .
              *
                                              
                    .
                                    
                *
                                        *
                      .
                                              
            .
                                    
                  .
                                        .
..-.--*--.__-__..._.--..-._.---....~__..._.--..~._.---.--..__
       -.--~--._  __..._.--..~._.--- - -.____.--_--'`_---..~.
                     .--..~._                     .--..~._
          -.-               .-.        .              -.-    
~.__..--._~._--..__.~.__..--._~._--..__.~.__..--._~._--..__.
  --.__..--._~._--..__.--.__..--._~._--..__.--.__..--._~._--
            .--._~._              .--._~._              .--
        -._             -._               -._             -._
__..--.._..--.__..--._~._--..__..--.._..--.__..--._~._--..__.
  ~--.__..--._~._--..__.~--.__..--._~._--..__.~--.__..--._~.
            .--._~._              .--._~._              .--
        -._                  -._         -.        -._     
._~.__..--._~._--..__.._~.__..--._~._--..__.._~.__..--._~._-
  .__..--._~._--..__..__..--._~._--..__..__..--._~._--..__.
          .--._~._              .--._~._              .--._
      -._             -._               -._             -._
--.__..--._~._--..__..--..__..--._~._--..__..--..__..--._~.
  .__..--._~._--..__..__..--._~._--..__..__..--._~._--..__.
        .--._~._--..              .--._~._--..              
    -._             -._       -._             -._       -._
..__.._~.__..--._~._--..__.._~.__..--._~._--..__.._~.__..--
  .*~.*_..--._~._--..__.._~.__..--._~._--..__.._~.__..--._~.
    .--._~._--..      .--._~._--..      .--._~._--..      
-._         -._   -._         -._   -._         -._   -._
_..__..--._~._--..    _..__..--._~._--..      _..__..--._~._
  ~.*_..--._~._--      ~.*_..--._~._--      ~.*_..--._~._
    .--._~.         .--._~.         .--._~.         
-._       -._   -._       -._   -._       -._   
.__..--._~._--    .__..--._~._--    .__..--._~._--    
  .*_..--._~.       .*_..--._~.       .*_..--._~.   
    .--._~           .--._~           .--._~     
-._     -._       -._     -._       -._     -._   
_..--._~._        _..--._~._        _..--._~._    
  *_..--._         *_..--._         *_..--._   
    .--._            .--._            .--._   
-._    -._        -._    -._        -._    -.
.--._~._          .--._~._          .--._~. 
  _..--._          _..--._          _..--._
    .-._             .-._             .-._
-._   -._    .--._~._      -._   -._    .__..--._~._    -._   
_._~._          _._~._        .*_..--._~.    _._~.
  ..--._    .--._~      ..--._    .--._~    ..-.
    -._       -._     -._       -._     -._
-._   -._    _..--._~._    -._   -._    *_..--._    -._
.~._      .--._    .~._      .--._      .~.
  .-._    -._    .-._    -._    .-._    .-.
    ._      ._      ._      ._      .
-._    .--._~._    -._    _..--._    -._                
  ._    *_..--._    ._    .--._    ._                 
    .    -._    .    -._    .               
   
-._    .__..--._~._    -._    .*_..--._    
  .    .--._~    .    -._    
    -._    _..--._~._    .
      *_..--._    
        .--._    
          -._
            .
      

Push Decoding to bip324?

// #Rust #Io

Can push-decoding/pull-encoding be useful for the bip324 library?

The part that I am most curious about is the handshake. Because it is a mouthful and tough to digest. In the BIP, it is described as a “1.5 round-trip” protocol, because technically, each side only has to perform one roundtrip plus another half.

  1. The initiator writes their key and garbage.
  2. The responder reads the initator’s key, and with their key, creates the secret materials.
  3. The responder writes the entirety of their responsibilities: key, garbage, garbage terminator, decoys, version packet.
  4. The initiator reads the responder’s key, creates the secret materials.
  5. The initiator writes the rest of their responsibilities: garbage terminator, decoys, version packet.

Each party writes a key, garbage, garbage terminator, decoys, and version packet. The last three however are dependent on the secret materials, which requires both keys. That is why the absolute lowest number of operations per-side is inverse. The initiator could write/read/write. The responder could read/write/read. But each side is kind of one and a half round-trips.

In practice, it makes sense to at least define a few more steps, even if they get optimized away under the hood. There is some trickiness to figuring out exactly how many bytes to read on each side. Buffer management is a bit complicated since it depends on the state of the handshake (e.g. how many garbage bytes? How many bytes for the next package which might be a decoy?).

Here is a more symmetrical breakdown. Let’s assume both parties pick some random garbage and decoy packets upfront and toss them into some HandshakeState struct. The flow, on both sides, goes through five states before turning into a beautiful cipher.

  1. Initialized // User picks their garbage and decoys.
    • write_key() -> (<Key + Garbage Encodable>) // Generates local key for the session, combines it with the garbage and returns the encodable to be written out.
  2. Key Sent
    • read_key(<Key Decodable>) -> () // Accepts a decoded key, generates secret materials.
  3. Key Received
    • write_terminator_decoys_version() -> (<Terminator + Decoy + Version Encodable>) // Uses the decoys and newly minted secret materials to create a encodable for the garbage terminator, decoy packets, and version packet.
  4. Version Sent
    • read_garbage_terminator_decoys_version(<Garbage + Terminator + Decoy + Version Decodable>) -> (Cipher) // Decode and validate all the things sent my the remote other than the initial key.
  5. Version Received // Handshake is consumed for a cipher.

So this looks more like 2 symmetrical round trips (write/read, write/read) per side, but, as we saw above they could technically be combined given the current state of secret material knowledge. For example, the responder could do read_key first and then combine write_key and write_terminator_decoys_version, before finishing with read_garbage_terminator_decoys_version. Maybe some of these states could be combined, like Key Sent and Key Received, where an encodable and decodable are returned to the caller at the same time. But this opens them up to calling them in the wrong order, kinda defeating the point of the type safe machine.

The basic pattern I am following above is each state transition accepts a decoded decodable or returns a ready to encode encodable. This is where the push decode library allows the buffer management to be done outside of the handshake state machine logic. And thinking through the types, everything is pretty simple…until you hit that <Garbage + Terminator + Decoy + Version Decodable>. Stuff like the Key is a just a 64 byte array, easy-peasy to encode/decode. Even that <Terminator + Decoy + Version Encodable> is a vector plus some packets (kinda hand-waving that packets are easy to encode/decode). But decoding everything beyond the key is harder because it is bespoke and state dependent.

Let’s break it down. First, their is the garbage. The garbage itself is just vector of random bytes, but how does the decoder know when the garbage ends? It is no length-prefixed like a lot of network protocols. It has the ol’ terminator. A decoder would need to have this state, which is derived from the secret materials. While it won’t be able to let the I/O driver know how many bytes it requires, I guess it isn’t horribly different from a known length array, which has its length passed in as state to the decoder.

Ok assuming we decode the garbage, that leaves the decoys and version packets. These are just special BIP-324 packets. The main differentiator is that the first packet, no matter if decoy or version, will have the remote’s garbage authenticated in the AAD. So the garbage itself needs to passed in as state to the decoder for the packets. That isn’t too bad, but what would a package decoder look like? It will need to have the length and data ciphers, or at least a mutable reference to them, which is a large requirement bump from most decoders (I think). But, if that is possible, the decoder can then be used as the main decoder for an established channel where only packets are flyin back and forth.

Decoding a packet requires two reads. First you decode the three byte array which is decrypted with the length-specific cipher. You can then decode the next x bytes of the payload, which is pretty straight forward. The only really complexity here is how strange is it to give mutable references to the ciphers?