libhydrogen trades API breadth for a two primitive core
A lightweight, secure, easy-to-use crypto library suitable for constrained environments.
At a glance
- What is it?
- libhydrogen is a small C99 crypto library built entirely on Curve25519 and the Gimli permutation, aimed at embedded projects where code size, stack usage and auditability matter more than a long list of algorithms.
- Who is it for?
- Engineers shipping firmware on microcontrollers, or anyone who wants a crypto dependency small enough to read end to end, will find libhydrogen a good fit. Projects that need AES-GCM, a FIPS validated module, algorithm agility, or wire compatibility with other crypto stacks should stay on libsodium or a similar library.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two building blocks under every function the library exposes
The README is unusually blunt about the crypto core: 100% built using just two cryptographic building blocks, the Curve25519 elliptic curve and the Gimli permutation. On top of those two, the library offers a consistent high level API inspired by libsodium, exposing simple functions that solve common problems rather than handing you raw primitives to assemble yourself.
That single decision explains most of what you will and will not find in the code. There is no AES-GCM, no SHA-2 family, no ChaCha20 exposed as a choice, and no way to negotiate an algorithm at runtime. The README also lists having multiple primitives serving the same purpose as an explicit non goal, so even adding an alternative later is not on the table.
The trade is deliberate and, for constrained targets, defensible. A smaller primitive set means fewer ways to misuse the library and far less surface to audit. The cost is that a firmware team with a compliance requirement for a specific approved algorithm, or an existing protocol that mandates a particular cipher, will not find what it needs here.
One file per operation is the auditability argument
The implementation strategy is stated plainly: implemented as one tiny file for every set of operation, and adding a single .c file to your project is all it takes to use libhydrogen in your project. The tree follows that pattern. At the top sit hydrogen.c and hydrogen.h, and the impl directory holds core.h, gimli-core.h, hash.h, kdf.h, kx.h, pwhash.h, random.h, secretbox.h, sign.h and x25519.h, with gimli-core carrying aarch64, portable and sse2 variants under it.
The rest of the repository shows how many environments the authors expected this to run in. There is a Makefile for Unix hosts plus Makefile.arduino, Makefile.chibios and Makefile.particle, alongside meson.build, CMakeLists.txt, a cmake directory, build.zig and build.zig.zon. A tests directory holds the test binary, and tis-ci holds the test tooling configuration.
For a reviewer this is the interesting part. If your threat model requires reading the crypto code, a library that splits its operations into small, separately readable files is far easier to check than one monolithic translation unit. The flip side is that the header set is the public contract, and the wiki, not the README, is where that contract is described.
Zero dynamic allocation and a 128 byte stack ceiling
The README states that the library performs zero dynamic memory allocations and has low stack requirements, giving a median of 32 bytes and a maximum of 128 bytes. It uses these numbers to argue that the library is usable in constrained environments such as microcontrollers.
Treat those figures as per call costs rather than as a budget for your whole application. Stack use adds up along a call path, and a protocol handler that calls several functions in a loop will carry the sum of them, not the largest one. The README also says the library attempts to mitigate the implications of accidental misuse, even on systems with an unreliable PRG and or no clock, which is reassuring about failure behaviour but is not a substitute for checking how your own code manages buffers.
The absence of dynamic allocation also puts the buffer management on you. Every function that produces output expects the caller to supply storage, which suits firmware where the heap is either absent or forbidden, and is less convenient for server side code where allocating a buffer would be routine.
Building the library and its test binary with the bundled Makefile
The default Makefile target is all, which depends on lib and test, and lib produces the static archive libhydrogen.a. The test binary is compiled straight from the two source files with the compiler flags and warning set defined at the top of the Makefile:
$(CC) $(CFLAGS) -O3 -o tests/tests hydrogen.c tests/tests.cThe test target removes any stale marker, runs the binary and writes a completion marker only if the run succeeds, which is why the clean target also deletes tests/tests.done:
rm -f tests/tests.done
tests/tests && touch tests/tests.doneTwo details in the flag list are worth noticing for a project that compiles with strict warnings. The build uses -Wall, -Wextra, -Wmissing-prototypes, -Wmissing-declarations, -Wredundant-decls, -Wstrict-prototypes and -Wswitch-enum, so the headers are expected to be self consistent and every switch on an enum is expected to cover the enum. The default CFLAGS also include -fno-exceptions, and the object list includes the implementation headers so that edits to them trigger a rebuild. Run make in a checkout and expect a static archive plus a tests/tests executable; the archive alone is what you link against.
Installing hydrogen.h and libhydrogen.a onto a Unix host
The install target depends on lib and honours a PREFIX variable that defaults to /usr/local, so a different location is a matter of overriding that variable at invocation time rather than editing the file. The recipes try to install as root first and fall back to an unprivileged install, and they finish with a loader cache refresh that is allowed to fail:
install -o 0 -g 0 -m 0755 libhydrogen.a $(PREFIX)/lib 2> /dev/null || install -m 0755 libhydrogen.a $(PREFIX)/lib
install -o 0 -g 0 -m 0644 hydrogen.h $(PREFIX)/include 2> /dev/null || install -m 0644 hydrogen.h $(PREFIX)/include
ldconfig 2> /dev/null || trueThe two install lines place a static library in the library directory and a single public header in the include directory, which matches the one file integration story: a project only needs hydrogen.h and hydrogen.c. The uninstall target removes exactly those two installed paths, and a clean checkout is restored with the clean target, which deletes the archive, the object file and the test binary.
Because the library is a static archive with no shared object target in this Makefile, there is no runtime dependency to configure and no shared library ABI to track between releases. That is a genuine advantage for firmware, and a nuisance for a distribution that expects a versioned shared object in the system library path.
The README shows no call site, so the wiki carries the API
Here is the honest limitation of the on screen documentation: the README contains no example of calling the library. It names the functions by area, for instance a key exchange API based on the Noise protocol, but it does not show a single invocation, a buffer size, or a return value. The README states plainly that the documentation is maintained in the libhydrogen wiki, and that wiki is where you will have to look for signatures before writing code.
The networking story is also incomplete by design. A simple key exchange API based on the Noise protocol is available, and a STROBE-based transport API will be implemented. That future tense means no transport layer ships in the current tree, so anything beyond a key exchange is yours to build.
A second generation of the library exists alongside the current one. The legacy code, which leveraged XChaCha20, SipHashX, BLAKE2SX and Curve25519, remains available in the v0 branch, and it is a different set of primitives from the current Curve25519 plus Gimli design. Pick that branch only if you specifically need its algorithms, since the two are not interchangeable in behaviour or in API.
What libhydrogen refuses to do
The non goals section is more informative than most feature lists. Networking is out of scope, interoperability with other libraries is out of scope, having several primitives that do the same job is out of scope, and replacing libsodium is explicitly not the aim, because the stated aim is to keep the number of APIs and the code size down to a minimum.
Read together, those four lines rule out a whole class of projects. If your team needs to interoperate with a peer running a different crypto stack, or needs to match an existing protocol byte for byte, this library cannot help you without you writing that layer yourself. If you need a hosted service to call a widely audited library that your compliance team already accepts, adding a different implementation creates review work rather than removing it.
Where the library does help is a device that talks only to itself or to an application you also control, where you want the crypto dependency to be small enough that one person can read it and small enough to fit alongside application code in a few kilobytes of flash. The Arduino support and the cryptographically secure random number generation on Arduino boards are aimed squarely at that case.
Maintenance state, licensing and the absence of tagged releases
The repository is not archived, and the last push was on 2026-09-28, so the code is being worked on rather than frozen. The repository has no GitHub releases at all, which means there is no tagged artefact to pin in a dependency lock file and no release notes to read. Versioning happens through branches, with master as the default branch and v0 holding the legacy code.
Continuous integration is visible through the badge set at the top of the README: a GitHub Actions CI workflow, a CodeQL analysis workflow, a Coverity Scan build status, and an Open Collective page for financial contributors. Those badges indicate that scanning is wired up, but they say nothing about the size of the community or the speed of review.
On licensing, the README says the whole code is released under a single, very liberal license, ISC. The repository itself is marked as Other, a custom licence GitHub cannot classify, with a LICENSE file at the root. Read that file before shipping anything, and treat it as the authoritative text rather than the README summary. This is a licensing question to confirm with whoever owns your compliance obligations, not advice about what the terms mean.
Editorial conclusion
Engineers shipping firmware on microcontrollers, or anyone who wants a crypto dependency small enough to read end to end, will find libhydrogen a good fit. Projects that need AES-GCM, a FIPS validated module, algorithm agility, or wire compatibility with other crypto stacks should stay on libsodium or a similar library. Before adopting, read the LICENSE file yourself, since the README describes the licence as ISC while the repository marks it as a custom licence, and confirm in the wiki that the functions you need carry the stack and buffer costs your firmware can absorb.
Frequently asked questions
Is libhydrogen released under the ISC licence?
The README states that the whole code is released under a single, very liberal licence, ISC. The repository itself is marked as Other, a custom licence GitHub cannot classify, and the root LICENSE file is the authoritative text, so read it before shipping a product.
Can libhydrogen replace libsodium in my project?
No, and the README says so directly: replacing libsodium is not a goal, because libhydrogen tries to keep the number of APIs and the code size down to a minimum. It also rules out interoperability with other libraries and having multiple primitives serve the same purpose.
Does libhydrogen work on Arduino boards?
Yes. The README lists the Arduino IDE among the supported environments and says the library can generate cryptographically secure random numbers even on Arduino boards. The repository also ships Makefile.arduino next to Makefile.chibios and Makefile.particle for those targets.
Where can I find examples of using the libhydrogen API?
The README contains no code example, and it states that the documentation is maintained in the libhydrogen wiki at github.com/jedisct1/libhydrogen/wiki. The only runnable sample in the repository is the tests/tests binary that the Makefile test target builds and runs.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jedisct1-libhydrogen)Was this useful?