Libsodium is now 13 years old!
I started that project to pursue Dan Bernstein’s desire to make cryptography simple to use. That meant exposing a limited set of high-level functions and parameters, providing a simple API, and writing documentation for users, not cryptographers. Libsodium’s goal was to expose APIs to perform operations, not low-level functions. Users shouldn’t even have to know or care about what algorithms are used internally. This is how I’ve always viewed libsodium.
Never breaking the APIs is also something I’m obsessed with. APIs may not be great, and if I could start over from scratch, I would have made them very different, but as a developer, the best APIs are not the most beautifully designed ones, but the ones that you don’t have to worry about because they don’t change and upgrades don’t require any changes in your application either. Libsodium started from the NaCl API, and still adheres to it.
These APIs exposed high-level functions, but also some lower-level functions that high-level functions wrap or depend on. Over the years, people started using these low-level functions directly. Libsodium started to be used as a toolkit of algorithms and low-level primitives.
That made me sad, especially since it is clearly documented that only APIs from builds with --enable-minimal are guaranteed to be tested and stable. But after all, it makes sense. When building custom protocols, having a single portable library with a consistent interface for different functions is far better than importing multiple dependencies, each with their own APIs and sometimes incompatibilities between them.
That’s a lot of code to maintain. It includes features and target platforms I don’t use but try to support for the community. I also maintain a large number of other open source projects.
Still, the security track record of libsodium is pretty good, with zero CVEs in 13 years even though it has gotten a lot of scrutiny.
However, while recently experimenting with adding support for batch signatures, I noticed inconsistent results with code originally written in Zig. The culprit was a check that was present in a function in Zig, but that I forgot to add in libsodium.
The bug
The function crypto_core_ed25519_is_valid_point() , a low-level function used to check if a given elliptic curve point is valid, was supposed to reject points that aren’t in the main cryptographic group, but some points were slipping through.
... continue reading