This is an idiomatic C++ API for Monocypher. Monocypher is:
an easy to use, easy to deploy, auditable crypto library written in portable C. It approaches the size of TweetNaCl and the speed of Libsodium.
This API here is:
Unofficial: It's not part of Monocypher, but for convenience includes it as a Git submodule.
C++: Requires C++17 or later.
Idiomatic: Cryptographic entities are C++ classes, mostly subclasses of std::array
. Arrays can be easily concatenated or sliced. Options like key sizes and algorithms are template parameters. Operations are methods.
Namespaced: All symbols are in the C++ namespace monocypher
. Nothing is defined at global scope, not even the Monocypher C API. This prevents symbol collisions in binaries that also use libSodium or OpenSSL, all of which use the same C crypto_
prefix as regular Monocypher.
Safe:
monocypher::key_exchange::public_key
) to a function expecting an Ed25519 public key (monocypher::public_key
).std::array
objects, which are value types, so you can't accidentally pass invalid pointers, pass a pointer to data of the wrong size, or return a dangling pointer to a local array.==
and !=
operators use constant-time comparisons instead of regular memcmp
, to avoid timing attacks.|
operator, unlike the typical series of fragile memcpy
operations used in C, where it's too easy to get offsets or array sizes wrong.Functionality | Algorithm(s) |
---|---|
Cryptographic digests | Blake2b, SHA-512, Blake3*, SHA-256* |
Password-to-key derivation | Argon2i |
Diffie-Hellman key exchange | Curve25519 (raw or with HChaCha20) |
Authenticated encryption | XChaCha20 or XSalsa20*, with Poly1305 |
Digital signatures | Ed25519 (with Blake2b or SHA-512) |
* denotes optional algorithms not implemented in Monocypher itself. XSalsa20 is from tweetnacl, SHA-256 is from Brad Conte’s crypto-algorithms (both public-domain), and Blake3 is from the reference C implementation (Apache2 or CC).
You should be OK on recent versions of Linux, Windows, and Apple platforms, using up-to-date versions of Clang, GCC or MSVC, and CMake 3.16 or later. That's what the CI tests cover.
git submodule update --init
.build_and_test.sh
. This uses CMake to build the library and some unit tests, and runs the tests.If your project uses CMake to build, all you hve to do is update your CMakeLists.txt
, adding the line add_subdirectory(monocypher-cpp)
and adding MonocypherCpp
to your target's target_link_libraries
.
If you don't use CMake:
include
directory to your compiler's include path.src/Monocypher.cc
to your project's source file list.#include "Monocypher.hh"
in source files where you want to use Monocypher.src/Monocypher-ed25519.cc
and #include "Monocypher-ed25519.hh"
. Ditto for SHA-256, XSalsa20, which have their own headers and source files.vendor/BLAKE3/c
, which has some specializations for different CPU types.After building, read the Monocypher documentation to learn how to use the API! The correspondence between the functions documented there, and the classes/methods here, should be clear. You can also consult tests/MonocypherCppTests.cc
as a source of examples.
⚠️ You do not need to compile or include the Monocypher C files in
vendor/monocypher/
. The C++ source files compile and include them for you indirectly, wrapping their symbols in a C++ namespace.
Upgraded the Monocypher library from 3.1.3 to 4.0.1. There were a lot of API changes in the C API, but most of them don't affect the C++ API. I've even added (trivial) wrappers for some functionality that was removed.
The change you will notice is to the signature API. Monocypher used to keep the Ed25519 secret and public keys separate. But in 4.0 Loup decided to include the public key in the secret key, as libSodium does. This is because signing and verification use both keys, and there was a danger that application code might accidentally pass a mismatched pair, producing garbage results. The C API now only takes the secret key, which is actually both keys in one.
I already had a key_pair
struct that combined the two keys, so that stays the same. The breaking change is that signing_key
is now renamed key_pair::seed
, and you can't use it directly to sign and verify anymore; only the key_pair
does that. Wherever you were signing and verifying with the signing_key
, alone, you'll now need to construct a key_pair
from it and then call the key_pair
. Also consider changing your code to use key_pair
instead of seed
; it's only 32 bytes larger and you'll save time on every signature or verification.
PS: When reading the Monocypher C API docs, keep in mind that what they call the "secret key" corresponds to the key_pair
struct in the C++ API.
byte_array
pointing to crypto data at some address. Currently you can just do e.g. ((public_key*)keyPtr)->check(...)
.byte_array::randomize()
, which tries to call arc4_randombuf
where available. The fallback is std::random_device
, which usually wraps the platform's RNG. But if your platform has no secure RNG (probably only true on embedded systems...) then random_device
will happily provide low-entry pseudorandom output, which could lead to security problems. In that case you'll need to find your own source of randomness and modify the randomize()
method to call it instead.