Monocypher

Boring crypto that simply works

Test Suite

The test suite is run under normal conditions, then with various verification tools:

Constant time comparisons

Comparisons are pretty straightforward, but the bit twiddling involved still leaves room for error. The test suite uses property based tests that generates something like a couple million tests. They were designed through mutation testing: the comparison routines were modified incorrectly, to see if the tests would catch the error.

Initial versions of the tests didn't catch them all. The current version does. It is now pretty hard to implement incorrect comparisons that would pass the tests by accident.

Chacha20

Some test vectors came from RFC 7539. The rest were generated with Libsodium. They test every input length, from zero to twice the Chacha block size.

A couple test vectors were generated specifically to test counter overflow (it is expected to go back to zero).

Property based tests test the consistency of the streaming interface, consistency of the counter interface, and consistency when the input and output buffers are the same.

XChacha20

Test vectors were generated by Libsodium. No further tests were conducted, because they would be redundant with those of Chacha20 (XChacha20 differs only by its initialisation).

HChacha20

XChacha20 depends on HChacha20, so there is no need for further tests (any error in HChacha20 would fail the XChacha20 tests)

Poly1305

This one is tricky, because modular arithmetic often allows subtle errors to creep in in ways that are very hard to test.

We use test vectors from RFC 7539, which are specifically designed to catch errors that random tests wouldn't (most notably limb overflows). Other test vectors were generated by Libsodium. They test every input length, from zero to twice the Poly1305 block size.

Property based tests test the consistency of the streaming interface, and overlapping input/output buffers (which are allowed).

Additionally, a proof of correctness was conducted to further increase confidence. It is not machine checked, but it is fairly easy to review.

Blake2b

Test vectors were generated by Libsodium. They span every input length from zero to twice the Blake2b block size, all possible key sizes (from 0 to 64), and all possible output sizes (from 1 to 64).

Property based tests test the consistency of the streaming interface, and overlapping input/output buffers (which are allowed).

One line of code proved impossible to test: the overflow of the 64-bit limb of the 128-bit counter:

static void blake2b_incr(crypto_blake2b_ctx *ctx)
{
    u64   *x = ctx->input_offset;
    size_t y = ctx->input_idx;
    x[0] += y;
    if (x[0] < y) {
        x[1]++;   // NEVER REACHED
    }
}

We do not care, for two reasons:

SHA-512

Test vectors were generated by Libsodium. They span every input length from zero to twice the SHA-512 block size.

Property based tests test the consistency of the streaming interface, and overlapping input/output buffers (which are allowed).

Like Blake2b, one line of code proved impossible to test:

static void sha512_incr(u64 x[2], u64 y)
{
    x[1] += y;
    if (x[1] < y) {
        x[0]++;  // NEVER REACHED
    }
}

We do not care, for the same reasons as Blake2b.

Argon2i

Test vectors were generated by Libsodium. They span every working buffer size, from 384 blocks to 640 blocks (exceeding 512 blocks is important to reach all code paths in Argon2i), every output hash size from 16 to 256 bytes, and every number of iterations from 3 to 10.

There's also a test vector from the reference implementation, to make sure the key and additional data aren't swapped.

Property based tests test overlapping buffers (which are allowed, and may even make sense, to save a tiny bit of memory and ensure secret inputs are wiped as soon as possible).

X25519

This one also involves modular arithmetic. Confidence was reached by leveraging the ref10 reference implementation. The code was heavily edited for readability and compactness, but the structure stayed the same. This most likely preserved the absence of subtle limb overflows.

Test vectors were generated by Libsodium, and the first 1000 iterations of the Monte Carlo test are performed (so were the remaining 999000 iterations, but they are turned off by default).

EdDSA

Like X25519, EdDSA leverages existing implementations (ref10 and TweetNaCl). Subtle limb overflow errors are therefore as unlikely.

Test vectors were generated by Ed25519-Donna, which unlike Libsodium can use a custom hash instead of the usual SHA-512. We also added the Wycheproof Ed25519 test vectors since 2.0.4, to make sure the vulnerability found in 2.0.3 doesn't come back (we compile Monocypher with -DED25519_SHA512 to be compatible with those test vectors).

Property based tests test round trip (signed messages should pass verification, forged messages should be rejected), random input (including points outside the curve for verification), overlapping buffers (which are allowed), and the consistency of the incremental interface.

Authenticated encryption

Test vectors were generated by Libsodium (version 2.0.0 and later are compatible with Libsodium), and property based tests test round trip and the consistency of the incremental interface.