Library / SDK
LoupVaillant/Monocypher avatar
LoupVaillant/Monocypher

Monocypher: a small auditable crypto library in portable C

An easy to use, easy to deploy crypto library

794 stars118 forksCNOASSERTION

At a glance

What is it?
Monocypher is a crypto library written in portable C that covers authenticated encryption, hashing, password hashing, key exchange, signatures and steganography in a package small enough to read, and it is distributed as two source files you can drop into a project. The judgement is that its unusual strength is auditability, backed by formal analysis tooling, and that its unusual weakness is that the compatibility options around Ed25519 and SHA-512 live in separate optional files.
Who is it for?
Monocypher fits an embedded project or a codebase that has to justify its cryptography line by line, because the whole library is small enough to review and it ships with Frama-c and TIS interpreter scripts rather than only a unit test suite.
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 3 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A crypto library small enough to read in one sitting

Monocypher is described as an auditable crypto library written in portable C, and the positioning is about size and reviewability rather than about feature count. The README puts it as approaching the size of TweetNaCl and the speed of libsodium, which is a claim about how little code has to be trusted, not about what it does.

The distribution makes that concrete. The easiest way to use the library is to include src/monocypher.h and src/monocypher.c directly in a project, and those two files compile as C since C99 and as C++ since C++98. There is no build system to integrate, no dependency to resolve and no package index to query. A project that needs four primitives can vendor two files and read both of them.

One thing to understand before downloading anything. The repository is labelled the developer edition, described in the README as the bleeding edge version that is not yet released. The versioned tarballs live on the project site, and the README points to the latest tarball, to the source file and to the header file as direct downloads for people who just want to use the library.

The repository also carries two continuous integration badges, one for TrustInSoft and one for GitHub Actions, so the code is built and tested in more than one pipeline.

Six primitives, and two of them live in optional files

The feature list is short enough to read in one pass, which is unusual for a crypto library.

Authenticated encryption uses XChaCha20 with Poly1305, and the README cites RFC 8439 for it. Hashing and key derivation use BLAKE2b, with SHA-512 available as an option. Password hashing uses Argon2. Public key cryptography uses X25519 key exchanges, and public key signatures use EdDSA with Ed25519. The last entry is the unusual one, steganography and password authenticated key exchange using Elligator 2, which is a way of encoding a public key so that it looks like an ordinary random string.

The optional part matters more than the list does. If you need SHA-512 or Ed25519, you have to grab src/optional/monocypher-ed25519.h and src/optional/monocypher-ed25519.c as well, or add them to your project by hand. If you compile or install Monocypher with the makefile, those files are included automatically, so the trap is only for people who copy the two core files and stop there.

That split keeps the default library smaller, at the price of a build configuration that has to be right for the primitives you actually call.

Three installation routes, and the flags that come with them

There are three ways to get Monocypher onto a system, and they exist for different kinds of project.

The first is the vendor route, copying the header and the source file into the tree. The second is the library route, running make and then taking either the static library lib/libmonocypher.a or the shared library lib/libmonocypher.so. The third is the system route, running make and then make install as root, which installs into /usr/local by default and can be redirected with PREFIX and DESTDIR.

The compiler defaults matter, because they are aggressive. The default compiler is gcc -std=c99 and the default flags are -pedantic -Wall -Wextra -O3 -march=native. The -march=native flag in particular optimises for the machine doing the build, which is fine for a developer machine and wrong for a distributed binary. The README shows how to override both:

bash
$ make CC="clang -std=c11" CFLAGS="-O2"

An installed library comes with a pkg-config file, and the README gives the two command lines that use it, one to compile with the cflags and one to link with the libs:

bash
$ gcc program.c $(pkg-config monocypher --cflags) -c
$ gcc program.o $(pkg-config monocypher --libs)   -o program

There are also installation sub targets for people who want to skip the man pages or the pkg-config file: install-lib, install-doc and install-pc.

The test suite is presented as a precondition, not a nicety

The test section of the README is unusually direct about what a user is expected to do. Run make test, and it prints the tests and ends with All tests OK! If the word failure or Error appears anywhere in the output, something has gone wrong.

The instruction that follows is the important one: do not use Monocypher without running those tests at least once. The reasoning is implicit but reasonable. A crypto library is copied into a project file by file, so a build environment that miscompiles it, a platform where the integer assumptions do not hold or a compiler that mis-handles one of the routines is exactly the situation a test run would catch, and it is the situation a user is least likely to notice later.

Beyond the make target there are two shell scripts. tests/test.sh runs the same suite under the Clang sanitisers and under Valgrind, and tests/coverage.sh checks coverage. Both are the kind of check that a small project can afford to run in continuous integration and that a vendored copy usually skips, which is the other argument for running them once at integration time.

The manual lives at monocypher.org/manual and in the doc directory of the repository, with one page per primitive, linked from the feature list above.

Formal analysis with Frama-c and the TIS interpreter

Most crypto libraries ship unit tests. Monocypher also ships the scripts to have its code analysed more formally, and this is the strongest argument for choosing it in a setting where the cryptography has to be justified.

Two tools are used. Frama-c is a static analysis framework, and the README gives the two scripts, tests/formal-analysis.sh and tests/frama-c.sh, with the instruction that Frama-c must be installed and that frama-c.sh holds the recommended settings. The TIS interpreter from TrustInSoft is the second, and it is run through tests/formal-analysis.sh as well:

bash
$ tis-interpreter.sh --cc -Dvolatile= tests/formal-analysis/*.c

The README then explains a wrinkle that anyone running this will hit. The TIS interpreter sometimes fails to evaluate correct programs that use the volatile keyword, and volatile is used in Monocypher only as an attempt to prevent dead store elimination for memory wipes. The -cc -Dvolatile= option works around that by ignoring volatile altogether.

That is a small but revealing detail. Memory wipes matter in a crypto library, because leaving a secret in memory after use is a real leak, and the author has thought about how to keep the compiler from optimising the wipe away, and has also thought about what that means for the analysis tools.

Two preprocessor switches and a script that renames your symbols

Three customisation hooks cover the cases where the defaults do not fit a project.

The first is the BLAKE2_NO_UNROLLING flag. By default Monocypher unrolls the BLAKE2b inner loop, and the README states that doing so is over 25 percent faster on modern processors. Some embedded processors run the unrolled loop slower, possibly because of the cost of fetching five kilobytes of additional code. Compiling with -DBLAKE2_NO_UNROLLING produces a binary about five kilobytes smaller, and in some cases faster. That is a concrete engineering trade with a measurable size figure attached to it, which is the kind of detail a general purpose library tends to hide behind an abstraction.

The second is MONOCYPHER_CPP_NAMESPACE, which lets a C++ project wrap the whole API in a namespace. When it is not defined, Monocypher assumes it is being compiled as C and adds an extern C declaration when the header is detected inside C++ code.

The third is change-prefix.sh, a script that renames every function by replacing the crypto_ prefix with one of your choosing, which is how you avoid a name clash when the library is linked into a codebase that has its own crypto_ symbols. The README gives the invocation, and the script is in the repository root next to dist.sh and the makefile.

A three year gap between releases, and two files the tarball adds

The release history explains how to read the repository version. Version 4.0.1 was published on 2023-03-18, 4.0.2 on 2023-09-03, and 4.0.3 on 2026-06-15, with the last push on 2026-10-18. So the tagged releases are sparse, with a three year gap between the second and the third, while the repository itself keeps moving. The version in the tree is ahead of any release, which is the definition of a developer edition.

The contributor notes explain what a clone does not have. The tests/vectors.h header is missing from the repository because generating it requires libsodium, and the instruction is to go to tests/gen/ and run make. The HTML version of the manual is missing too, because it is generated by the doc/doc_gen.sh script and needs mandoc and Python 3.

Both are packaging differences rather than functional ones, but they matter for anyone who wants to run the test suite, since the vectors header is what the tests compare against. To produce a tarball with the right name, make dist does it using git describe, and the repository root also holds AUTHORS.md, CHANGELOG.md, LICENCE.md, tis.config and the monocypher.pc file that pkg-config reads.

Editorial conclusion

Monocypher fits an embedded project or a codebase that has to justify its cryptography line by line, because the whole library is small enough to review and it ships with Frama-c and TIS interpreter scripts rather than only a unit test suite. It is the wrong choice if you need the full protocol surface of a general purpose library, since Ed25519 and SHA-512 sit in optional files that you must add yourself, and it is the wrong choice if you want a package manager workflow, because the upstream distribution is a tarball and a source drop rather than a versioned dependency with a long support window. Before you adopt it, run make test on your platform as the README insists, decide whether the optional compatibility files are needed, and check the LICENCE.md file in the repository, since the licence is a custom one that GitHub cannot classify.

Frequently asked questions

How do I install Monocypher?

The simplest route is to include src/monocypher.h and src/monocypher.c in your project, which compiles as C since C99 and as C++ since C++98. The alternatives are running make and taking lib/libmonocypher.a or lib/libmonocypher.so, or running make and then make install as root, with PREFIX and DESTDIR available to redirect the location.

Does Monocypher support Ed25519 and SHA-512?

Yes, as optional extras. The optional files src/optional/monocypher-ed25519.h and src/optional/monocypher-ed25519.c have to be added to the project by hand, or they are included automatically when you build with the makefile.

What tests come with Monocypher?

make test runs the suite and ends with All tests OK!, and the README says not to use the library without running it at least once. tests/test.sh runs the same suite under the Clang sanitisers and under Valgrind, and tests/coverage.sh checks coverage.

Can Monocypher be formally analysed?

Yes. The repository ships tests/formal-analysis.sh and tests/frama-c.sh for analysis with Frama-c, and the TIS interpreter can be run over the same sources with tis-interpreter.sh --cc -Dvolatile= tests/formal-analysis/*.c.

Official sources

  1. Issues
  2. LoupVaillant/Monocypher on GitHub
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/loupvaillant-monocypher.svg)](https://hysenlabs.com/projects/loupvaillant-monocypher)

Was this useful?