# Eiger Code Challenge The idea behind this write-up is to go through the design decisions taken and the thought process that went into writing the https://github.com/Yoga07/eiger-code-challenge solution. As mentioned in the repository's README, Casper's P2P node is the choice of implementation that has been taken on. We'll begin with how the solution satisfies the base requirements and the bonus requirements mentioned in the problem statement: ### Base requirements: - **Both the target node and the handshake code should compile at least on Linux.** - The solution code and the target node compile on Linux and macOS and have been verified to work on both platforms. There are a lot of C dependencies internally, therefore it wasn't compiled on Windows. - **The solution has to perform a full protocol-level (post-TCP/etc.) handshake with the target node** - The solution performs a TCP/TLS handshake with the Casper node at the Transport layer. It verifies the peer's certificates to match their TLS specifics, such as their choice of elliptic curve, signature digest, etc., where their primary emphasis is. - Once SSL connections are established, the solution proceeds to process the incoming protocol message `Message::Handshake` from the Casper peer. A reply Handshake message is sent with the correct and necessary details. - Casper peer validates the connection and the Handshake message and accepts the node into its network, thus completing the Handshake process. - Vice versa, the same process is repeated but in the opposite direction when the solution is set to be listener(supporting bi-directional handshakes). - **The provided instructions should include information on how to verify that the handshake has concluded** - Steps to verify the logs for handshake have also been mentioned in the README. - **The solution can not depend on the code of the target node (but it can share some of its dependencies).** - Apart from the hashing formats and Rust types, the solution does not depend on the code of the target node. - In fact, many of the protocol specific Rust types that were not publicly available from Casper had to be re-made into the solution to deserialize incoming messages from the Casper peer successfully. - **The submitted code can not reuse entire preexisting handshake implementations like libp2p_noise/XX.** - There is no use of preexisting handshake implementations in Casper; therefore, none was used in the solution. ### Bonus requirements: - ### Performance - The solution code is written to be very simplistic yet versatile. - The communications module has been entirely multi-threaded. - The polling rate for the connection pool has been to 1ms which chimes well with the overall performance of the node. - ### Versatility - There have been multiple measures taken to have the solution be versatile: - The solution can work in a bi-directional manner, i.e., it can - i) Be the listener and handle handshake messages from a Casper node - ii) Be the initiator and send out handshake messages to a Casper node - The communications module implements a connection pool, which stores all connections and simultaneously allows the solution to perform successful handshakes with multiple peers. - The generation of the digest of `chainspec.toml`, a Casper-specific configuration file needed for successful bootstrapping, has been recreated to stay consistent with the target node and not use fixed values. This can be easily circumvented by hardcoding the hash into the Handshake message, but the peer will reject the handshake if there is a change to the config. - Rather than isolating the solution to only handling messages, there is also an event loop run by the solution node just in case this code can be developed for other use cases. - ### Security - Casper's P2P node implementation relies on a strict TCP/TLS connection at the transport layer. Their choice of crypto specifics needs to be matched in the first place to establish a connection ``` /// Casper's chosen signature algorithm (**ECDSA with SHA512**). const SIGNATURE_ALGORITHM: Nid = Nid::ECDSA_WITH_SHA512; /// Casper's chosen underlying elliptic curve (**P-521**). const SIGNATURE_CURVE: Nid = Nid::SECP521R1; /// Casper's chosen signature algorithm (**SHA512**). pub const SIGNATURE_DIGEST: Nid = Nid::SHA512; ``` - Multiple Protocol-specific and Network-specific parameters are exchanged and verified during the handshake process for both nodes to be consistent. - ### Minimalism - Only the required number of dependencies have been used for the solution. - Simple argument parsers and simple loggers have been used to reduce bloat, maintain ease of use, and keep information emission consistent. - ### Uniqueness: - Casper is a novel P2P implementation that satisfies this challenge's requirements(non-bitcoin). - Has a robust and well-written networking mechanism that makes this challenge even more enjoyable. - Employs multiple specially tailored serialization formats for its messages. - Well-established handshake flows that separate Protocol payload from Network payload using the serialization as mentioned earlier formats. ---- ### High-level Sequence Diagram: ```sequence note over EigerNode: Generate TCP/TLS certs and keys EigerNode -> CasperNode: TCP/TLS connect note over CasperNode: Verify incoming TLS connection EigerNode -> CasperNode: Message::Handshake note over CasperNode: Verify incoming Message::Handshake CasperNode -> EigerNode: Message::Handshake note over CasperNode: Accept incoming conn into Network note over CasperNode: Begin sending Gossip and HealthCheck messages note over EigerNode: Verify reply Message::Handshake note over EigerNode: Listen further CasperNode -> EigerNode: Gossip Messages CasperNode -> EigerNode: HealthCheck Messages ``` ---- ### Limitations: The only thing that bugs me in this solution is that there is no workaround for us to not use `tokio` and `openssl` for the TCP/TLS connection. The limitation comes from the choice of ECDSA curve and signature hashing algorithm from Casper, i.e., NIST P-521 (a.k.a. secp521r1) elliptic curve and SHA512, respectively. There is no Web PKI crate in Rust at the moment that supports the P-521 curve with the SHA512 algorithm to implement the cryptography primitives that happen behind the screens. I did look into some work-in-progress crates such as [elliptic-curves](https://github.com/RustCrypto/elliptic-curves) or [nettle](https://sequoia-pgp.gitlab.io/nettle-rs/nettle/ecc/struct.Secp521r1.html#) but they EC curves either under construction and or unsafe to use due to C dependencies, i.e., not reliable when compared to the likes of `openssl`. Even [ring](https://docs.rs/ring/latest/ring/agreement/index.html) did not implement the P-521 curve yet! To overcome this, I initially started working on a different solution(the WIP branch can be found [here](https://github.com/Yoga07/eiger-code-challenge/tree/solution1)) in which I wrote up a bare-metal P2P node implementation using the QUIC protocol from the [quinn](https://github.com/quinn-rs/quinn) and decided to implement [Noise's XX handshake pattern](https://noiseexplorer.com/patterns/XX/) which use DHKE(Diffie-Hellman Key Exchange) mechanisms to establish trust. However, 80% through the implementation, I realized that I was drifting away from the actual goal of the problem statement. The problem statement focuses more on understanding a different P2P node implementation(and not writing up a new one), which ultimately corresponds to the grasping and adapting ability of the candidate. Therefore, I parked the Noise XX solution and decided to work on the solution submitted above. Since then, the submitted solution's focus has been more on learning and adapting to the tech that Casper has used and rebuilding a robust P2P node implementation that successfully handshakes and connects to Casper's network. Nonetheless, Solution 1(the WIP XX handshake protocol) has got me hooked, and I've decided to work on it in my spare time. Everyone needs a hobby, haha! Keep an eye out if you are interested. :)