For the past month or so, I have been working on porting Glenn Fiedler’s game networking library, Yojimbo, and its dependencies (Serialize, Netcode and Reliable) from C/++ to Jai (Jonathan Blow’s new programming language, which is currently still in private beta as of writing). Prior to this porting project, I was working on a 2D game in C++ (codename “RayNet”), which uses Raylib for most things, and Yojimbo for networking (hence the name). Raylib is mostly trivially replaceable, but Yojimbo is not. As such, the porting of Yojimbo and its dependencies from C/++ to Jai has three main goals (in roughly this order of importance):

  • Become competent in Jai, in order to assess its viability as a C/++ replacement.
  • Read the internals of Yojimbo, and its dependencies, in order to better understand my own dependencies.
  • Enable the porting of my 2D game from C++ to Jai, should I feel so inclined.

The porting project has been going very well. I have been greatly enjoying learning and using Jai. I am fairly confident at this point in saying that yes, Jai is indeed an extraordinarily viable alternative to C and C++ for new projects across a wide variety of domains, not the least of which is game development.

So far, I have ported the entirety of Netcode, Reliable and Serialize, along with their respective test suites, as well as the Yojimbo library and its test applications. The only remaining work is to port the Yojimbo test suite, which is roughly 2k lines of code. I have already ported ~10k lines of code, so this it not a huge deal.

However, there is one more dependency that Yojimbo has (well, indirectly, via Netcode) and which I’ve had to stub in order to get the tests passing. That dependency is libsodium. Libsodium’s job within Netcode is to provide encryption and authentication for network packets.

More specifically, Netcode calls crypto_aead_xchacha20poly1305_ietf_encrypt and a few other related functions. I’m familiar with the basics of public-key cryptography, but honestly haven’t read much about it. I’ve been thinking that it could be an educational adventure to, instead of depending on libsodium, implement the few functions that Netcode requires natively in Jai. Of course, the one thing I do know about encryption is that writing your encryption code is a terrible idea, and you should always use well-tested implementations. But hey, I’m a smart guy, and more than likely this is just for fun anyways.

So, I read. And watched, and listened. To all sorts of things. Wikipedia articles, YouTube videos (1, 2, 3), etc.

crypto_aead_xchacha20poly1305_ietf_encrypt, as the name implies, is an AEAD (Authenticated Encryption with Associated Data) construction, powered by the Extended (x) ChaCha20 stream cipher, accompanied with a Poly1305 hash acting as a MAC (message authentication code). The IETF variation of ChaCha uses a longer, 96-bit nonce (vs. the normal 64-bit nonce), in order to reduce the chance of collisions when using random nonces (as opposed to sequential nonces, as are typically used in the default construction). Using a random nonce (“nonce” is a sort of portmanteau of “number used once”) allows you to avoid the problem of coordinating nonce usage across multiple systems using the same key (in this case, the client and the server are both using a shared key, derived from their own private key and the other end’s public key), which would inadvertantly cause nonces to be used twice, once when sending from server to client, and again when sending from client to server. Another way to prevent this issue, is to, for example, have the server always use odd nonces while the client always uses even nonces (or vice versa). Random nonces are just easier to to coordinate, as you simply don’t have to (given enough entropy to avoid accidental collisions, which would reduce the efficacy of the encryption).

While researching, one document that I came across was RFC 7539 “ChaCha20 and Poly1305 for IETF Protocols”. In Section 2.4.2, the document provides an input test vector, consisting of a key, nonce, initial counter and example plaintext, along with the expected keystream produced and ciphertext output. This is to help implementors verify the correctness of their implementations. For the example plaintext, the following string is used:

Ladies and Gentlemen of the class of ‘99: If I could offer you only one tip for the future, sunscreen would be it.

This is a rather peculiar looking sentence. It quite obviously sounds like a commencement address, and doesn’t seem to have anything to do with cryptography. Naturally, I googled It. And alas, the punchline:

Everybody’s Free (To Wear sunscreen) Baz Luhrmann - Classic 90’s music

(unfortunately, music videos are not embeddable due to YouTube copyright nonsense).

A valuable, albeit entirely unrelated and tangential, lecture on life.

It’s always nice to see a bit of humor in a serious technical publication.