]> git.codecow.com Git - Monocypher.git/commitdiff
Reorganised tests
authorLoup Vaillant <loup@loup-vaillant.fr>
Mon, 5 Dec 2022 18:35:37 +0000 (19:35 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Mon, 5 Dec 2022 18:35:37 +0000 (19:35 +0100)
Separating by primitive/functionality makes it easier to find my tests.
Also, asserts makes things simpler.

tests/test.c
tests/utils.c
tests/utils.h

index e16530bc8cb2498ae35985cbfe69b8c90a0e05a7..b47038b479615ff753d6f2cf05bbb11bf44cb3d5 100644 (file)
 #include "utils.h"
 #include "vectors.h"
 
-#define CHACHA_BLOCK_SIZE    64
-#define POLY1305_BLOCK_SIZE  16
-#define BLAKE2B_BLOCK_SIZE  128
-#define SHA_512_BLOCK_SIZE  128
-
-////////////////////////////
-/// Tests aginst vectors ///
-////////////////////////////
+#define VECTORS(n) ASSERT_OK(vector_test(n, #n, nb_##n##_vectors, n##_vectors))
+
+////////////////////////////////
+/// Constant time comparison ///
+////////////////////////////////
+static void p_verify(size_t size, int (*compare)(const u8*, const u8*))
+{
+       printf("\tcrypto_verify%zu\n", size);
+       u8 a[64]; // size <= 64
+       u8 b[64]; // size <= 64
+       FOR (i, 0, 2) {
+               FOR (j, 0, 2) {
+                       // Set every byte to the chosen value, then compare
+                       FOR (k, 0, size) {
+                               a[k] = (u8)i;
+                               b[k] = (u8)j;
+                       }
+                       int cmp = compare(a, b);
+                       if (i == j) { ASSERT(cmp == 0); }
+                       else        { ASSERT(cmp != 0); }
+                       // Set only two bytes to the chosen value, then compare
+                       FOR (k, 0, size / 2) {
+                               FOR (l, 0, size) {
+                                       a[l] = 0;
+                                       b[l] = 0;
+                               }
+                               a[k] = (u8)i; a[k + size/2 - 1] = (u8)i;
+                               b[k] = (u8)j; b[k + size/2 - 1] = (u8)j;
+                               cmp = compare(a, b);
+                               if (i == j) { ASSERT(cmp == 0); }
+                               else        { ASSERT(cmp != 0); }
+                       }
+               }
+       }
+}
+
+static void test_verify()
+{
+       p_verify(16, crypto_verify16);
+       p_verify(32, crypto_verify32);
+       p_verify(64, crypto_verify64);
+}
+
+////////////////
+/// Chacha20 ///
+////////////////
+#define CHACHA_BLOCK_SIZE 64
+
 static void chacha20(vector_reader *reader)
 {
        vector key       = next_input(reader);
@@ -97,14 +137,6 @@ static void ietf_chacha20(vector_reader *reader)
        }
 }
 
-static void hchacha20(vector_reader *reader)
-{
-       vector key   = next_input(reader);
-       vector nonce = next_input(reader);
-       vector out   = next_output(reader);
-       crypto_hchacha20(out.buf, key.buf, nonce.buf);
-}
-
 static void xchacha20(vector_reader *reader)
 {
        vector key       = next_input(reader);
@@ -121,303 +153,33 @@ static void xchacha20(vector_reader *reader)
        }
 }
 
-static void poly1305(vector_reader *reader)
-{
-       vector key = next_input(reader);
-       vector msg = next_input(reader);
-       vector out = next_output(reader);
-       crypto_poly1305(out.buf, msg.buf, msg.size, key.buf);
-}
-
-static void aead_ietf(vector_reader *reader)
+static void hchacha20(vector_reader *reader)
 {
        vector key   = next_input(reader);
        vector nonce = next_input(reader);
-       vector ad    = next_input(reader);
-       vector text  = next_input(reader);
        vector out   = next_output(reader);
-       crypto_lock_aead(out.buf, out.buf + 16, key.buf, nonce.buf,
-                        ad.buf, ad.size, text.buf, text.size);
-}
-
-
-static void blake2b(vector_reader *reader)
-{
-       vector msg = next_input(reader);
-       vector key = next_input(reader);
-       vector out = next_output(reader);
-       crypto_blake2b_general(out.buf, out.size,
-                              key.buf, key.size,
-                              msg.buf, msg.size);
-}
-
-static void sha512(vector_reader *reader)
-{
-       vector in  = next_input(reader);
-       vector out = next_output(reader);
-       crypto_sha512(out.buf, in.buf, in.size);
-}
-
-static void hmac_sha512(vector_reader *reader)
-{
-       vector key = next_input(reader);
-       vector msg = next_input(reader);
-       vector out = next_output(reader);
-       crypto_hmac_sha512(out.buf, key.buf, key.size, msg.buf, msg.size);
-}
-
-static void argon2i(vector_reader *reader)
-{
-       u64    nb_blocks     = load64_le(next_input(reader).buf);
-       u64    nb_iterations = load64_le(next_input(reader).buf);
-       vector password      = next_input(reader);
-       vector salt          = next_input(reader);
-       vector key           = next_input(reader);
-       vector ad            = next_input(reader);
-       vector out           = next_output(reader);
-       void  *work_area     = alloc(nb_blocks * 1024);
-       crypto_argon2i_general(out.buf, (u32)out.size,
-                              work_area, (u32)nb_blocks, (u32)nb_iterations,
-                              password.buf, (u32)password.size,
-                              salt    .buf, (u32)salt    .size,
-                              key     .buf, (u32)key     .size,
-                              ad      .buf, (u32)ad      .size);
-       free(work_area);
-}
-
-static void x25519(vector_reader *reader)
-{
-       vector scalar = next_input(reader);
-       vector point  = next_input(reader);
-       vector out    = next_output(reader);
-       crypto_x25519(out.buf, scalar.buf, point.buf);
-}
-
-static void x25519_pk(vector_reader *reader)
-{
-       vector in  = next_input(reader);
-       vector out = next_output(reader);
-       crypto_x25519_public_key(out.buf, in.buf);
-}
-
-static void edDSA(vector_reader *reader)
-{
-       vector secret_k = next_input(reader);
-       vector public_k = next_input(reader);
-       vector msg      = next_input(reader);
-       vector out      = next_output(reader);
-       u8 fat_secret_key[64];
-       memcpy(fat_secret_key     , secret_k.buf, 32);
-       memcpy(fat_secret_key + 32, public_k.buf, 32);
-       crypto_eddsa_sign(out.buf, fat_secret_key, msg.buf, msg.size);
-}
-
-static void edDSA_pk(vector_reader *reader)
-{
-       vector in  = next_input(reader);
-       vector out = next_output(reader);
-       u8 seed      [32];
-       u8 secret_key[64];
-       u8 public_key[32];
-       memcpy(seed, in.buf, 32);
-       crypto_eddsa_key_pair(secret_key, public_key, seed);
-       memcpy(out.buf, public_key, 32);
-
-       u8 zeroes[32] = {0};
-       if (memcmp(seed, zeroes, 32)) {
-               printf("FAILURE: seed has not been wiped\n");
-               exit(1);
-       }
-       if (memcmp(secret_key, in.buf, 32)) {
-               printf("FAILURE: first half of secret key is not the seed\n");
-               exit(1);
-       }
-       if (memcmp(secret_key + 32, public_key, 32)) {
-               printf("FAILURE: second half of secret key is not the public key\n");
-               exit(1);
-       }
-}
-
-static void ed_25519(vector_reader *reader)
-{
-       vector secret_k = next_input(reader);
-       vector public_k = next_input(reader);
-       vector msg      = next_input(reader);
-       vector out      = next_output(reader);
-       u8 fat_secret_key[64];
-       memcpy(fat_secret_key     , secret_k.buf, 32);
-       memcpy(fat_secret_key + 32, public_k.buf, 32);
-       crypto_ed25519_sign(out.buf, fat_secret_key, msg.buf, msg.size);
-}
-
-static void ed_25519_pk(vector_reader *reader)
-{
-       vector in  = next_input(reader);
-       vector out = next_output(reader);
-       u8 seed      [32];
-       u8 secret_key[64];
-       u8 public_key[32];
-       memcpy(seed, in.buf, 32);
-       crypto_ed25519_key_pair(secret_key, public_key, seed);
-       memcpy(out.buf, public_key, 32);
-
-       u8 zeroes[32] = {0};
-       if (memcmp(seed, zeroes, 32)) {
-               printf("FAILURE: seed has not been wiped\n");
-               exit(1);
-       }
-       if (memcmp(secret_key, in.buf, 32)) {
-               printf("FAILURE: first half of secret key is not the seed\n");
-               exit(1);
-       }
-       if (memcmp(secret_key + 32, public_key, 32)) {
-               printf("FAILURE: second half of secret key is not the public key\n");
-               exit(1);
-       }
-}
-
-static void ed_25519_check(vector_reader *reader)
-{
-       vector public_k = next_input(reader);
-       vector msg      = next_input(reader);
-       vector sig      = next_input(reader);
-       vector out      = next_output(reader);
-       out.buf[0] = (u8)crypto_ed25519_check(sig.buf, public_k.buf,
-                                             msg.buf, msg.size);
-}
-
-static void iterate_x25519(u8 k[32], u8 u[32])
-{
-       u8 tmp[32];
-       crypto_x25519(tmp , k, u);
-       memcpy(u, k  , 32);
-       memcpy(k, tmp, 32);
-}
-
-static int test_x25519()
-{
-       u8 _1   [32] = {0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc,
-               0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f,
-               0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78,
-               0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79};
-       u8 k[32] = {9};
-       u8 u[32] = {9};
-
-       crypto_x25519_public_key(k, u);
-       int status = memcmp(k, _1, 32);
-       printf("%s: x25519 1\n", status != 0 ? "FAILED" : "OK");
-
-       u8 _1k  [32] = {0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55,
-               0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c,
-               0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87,
-               0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51};
-       FOR (i, 1, 1000) { iterate_x25519(k, u); }
-       status |= memcmp(k, _1k, 32);
-       printf("%s: x25519 1K\n", status != 0 ? "FAILED" : "OK");
-
-       // too long; didn't run
-       //u8 _1M[32] = {0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd,
-       //              0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f,
-       //              0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf,
-       //              0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24};
-       //FOR (i, 1000, 1000000) { iterate_x25519(k, u); }
-       //status |= memcmp(k, _1M, 32);
-       //printf("%s: x25519 1M\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
-
-static void elligator_dir(vector_reader *reader)
-{
-       vector in  = next_input(reader);
-       vector out = next_output(reader);
-       crypto_hidden_to_curve(out.buf, in.buf);
-}
-
-static void elligator_inv(vector_reader *reader)
-{
-       vector point   = next_input(reader);
-       u8     tweak   = next_input(reader).buf[0];
-       u8     failure = next_input(reader).buf[0];
-       vector out     = next_output(reader);
-       int    check   = crypto_curve_to_hidden(out.buf, point.buf, tweak);
-       if ((u8)check != failure) {
-               printf("Elligator inverse map: failure mismatch\n");
-               exit(1);
-       }
+       crypto_hchacha20(out.buf, key.buf, nonce.buf);
 }
 
-//////////////////////////////
-/// Self consistency tests ///
-//////////////////////////////
-static int p_verify(size_t size, int (*compare)(const u8*, const u8*))
+static void test_chacha20()
 {
-       int status = 0;
-       u8 a[64]; // size <= 64
-       u8 b[64]; // size <= 64
-       FOR (i, 0, 2) {
-               FOR (j, 0, 2) {
-                       // Set every byte to the chosen value, then compare
-                       FOR (k, 0, size) {
-                               a[k] = (u8)i;
-                               b[k] = (u8)j;
-                       }
-                       int cmp = compare(a, b);
-                       status |= (i == j ? cmp : ~cmp);
-                       // Set only two bytes to the chosen value, then compare
-                       FOR (k, 0, size / 2) {
-                               FOR (l, 0, size) {
-                                       a[l] = 0;
-                                       b[l] = 0;
-                               }
-                               a[k] = (u8)i; a[k + size/2 - 1] = (u8)i;
-                               b[k] = (u8)j; b[k + size/2 - 1] = (u8)j;
-                               cmp = compare(a, b);
-                               status |= (i == j ? cmp : ~cmp);
-                       }
-               }
+       VECTORS(chacha20);
+       printf("\tChacha20 (ctr)\n");
+       {
+               RANDOM_INPUT(key  ,  32);
+               RANDOM_INPUT(nonce,  24);
+               RANDOM_INPUT(plain, 128);
+               u8 out_full[128];
+               u8 out1     [64];
+               u8 out2     [64];
+               crypto_chacha20    (out_full, plain     , 128, key, nonce);
+               crypto_chacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
+               crypto_chacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
+               ASSERT_EQUAL(out_full     , out1, 64);
+               ASSERT_EQUAL(out_full + 64, out2, 64);
        }
-       printf("%s: crypto_verify%zu\n", status != 0 ? "FAILED" : "OK", size);
-       return status;
-}
-static int p_verify16(){ return p_verify(16, crypto_verify16); }
-static int p_verify32(){ return p_verify(32, crypto_verify32); }
-static int p_verify64(){ return p_verify(64, crypto_verify64); }
-
-static int p_chacha20_ctr()
-{
-       int status = 0;
-       RANDOM_INPUT(key  ,  32);
-       RANDOM_INPUT(nonce,  24);
-       RANDOM_INPUT(plain, 128);
-       u8 out_full[128];
-       u8 out1     [64];
-       u8 out2     [64];
-       crypto_chacha20    (out_full, plain     , 128, key, nonce);
-       crypto_chacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
-       crypto_chacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
-       status |= memcmp(out_full     , out1, 64);
-       status |= memcmp(out_full + 64, out2, 64);
-
-       crypto_ietf_chacha20    (out_full, plain     , 128, key, nonce);
-       crypto_ietf_chacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
-       crypto_ietf_chacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
-       status |= memcmp(out_full     , out1, 64);
-       status |= memcmp(out_full + 64, out2, 64);
-
-       crypto_xchacha20    (out_full, plain     , 128, key, nonce);
-       crypto_xchacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
-       crypto_xchacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
-       status |= memcmp(out_full     , out1, 64);
-       status |= memcmp(out_full + 64, out2, 64);
-
-       printf("%s: Chacha20 (ctr)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that Chacha20(nullptr) == Chacha20(all-zeroes)
-static int p_chacha20_stream()
-{
-       int status = 0;
+       printf("\tChacha20 (nullptr == zeroes)\n");
 #define INPUT_SIZE (CHACHA_BLOCK_SIZE * 2 + 1)
        FOR (i, 0, INPUT_SIZE) {
                u8 output_normal[INPUT_SIZE];
@@ -427,32 +189,56 @@ static int p_chacha20_stream()
                RANDOM_INPUT(nonce, 8);
                crypto_chacha20(output_normal, zeroes, i, key, nonce);
                crypto_chacha20(output_stream, 0     , i, key, nonce);
-               status |= memcmp(output_normal, output_stream, i);
+               ASSERT_EQUAL(output_normal, output_stream, i);
        }
-       printf("%s: Chacha20 (nullptr == zeroes)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that output and input can be the same pointer
-static int p_chacha20_same_ptr()
-{
+       printf("\tChacha20 (output == input)\n");
+       {
 #undef INPUT_SIZE
 #define INPUT_SIZE (CHACHA_BLOCK_SIZE * 4) // total input size
-       int status = 0;
-       u8  output[INPUT_SIZE];
-       RANDOM_INPUT(input, INPUT_SIZE);
-       RANDOM_INPUT(key  , 32);
-       RANDOM_INPUT(nonce, 8);
-       crypto_chacha20(output, input, INPUT_SIZE, key, nonce);
-       crypto_chacha20(input , input, INPUT_SIZE, key, nonce);
-       status |= memcmp(output, input, INPUT_SIZE);
-       printf("%s: Chacha20 (output == input)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
+               u8  output[INPUT_SIZE];
+               RANDOM_INPUT(input, INPUT_SIZE);
+               RANDOM_INPUT(key  , 32);
+               RANDOM_INPUT(nonce, 8);
+               crypto_chacha20(output, input, INPUT_SIZE, key, nonce);
+               crypto_chacha20(input , input, INPUT_SIZE, key, nonce);
+               ASSERT_EQUAL(output, input, INPUT_SIZE);
+       }
 
-static int p_hchacha20()
-{
-       int status = 0;
+       VECTORS(ietf_chacha20);
+       printf("\tietf Chacha20 (ctr)\n");
+       {
+               RANDOM_INPUT(key  ,  32);
+               RANDOM_INPUT(nonce,  24);
+               RANDOM_INPUT(plain, 128);
+               u8 out_full[128];
+               u8 out1     [64];
+               u8 out2     [64];
+               crypto_ietf_chacha20    (out_full, plain     , 128, key, nonce);
+               crypto_ietf_chacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
+               crypto_ietf_chacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
+               ASSERT_EQUAL(out_full     , out1, 64);
+               ASSERT_EQUAL(out_full + 64, out2, 64);
+       }
+
+       VECTORS(xchacha20);
+       printf("\tXChacha20 (ctr)\n");
+       {
+               RANDOM_INPUT(key  ,  32);
+               RANDOM_INPUT(nonce,  24);
+               RANDOM_INPUT(plain, 128);
+               u8 out_full[128];
+               u8 out1     [64];
+               u8 out2     [64];
+               crypto_xchacha20    (out_full, plain     , 128, key, nonce);
+               crypto_xchacha20_ctr(out1    , plain +  0,  64, key, nonce, 0);
+               crypto_xchacha20_ctr(out2    , plain + 64,  64, key, nonce, 1);
+               ASSERT_EQUAL(out_full     , out1, 64);
+               ASSERT_EQUAL(out_full + 64, out2, 64);
+       }
+
+       VECTORS(hchacha20);
+       printf("\tHChacha20 (overlap)\n");
        FOR (i, 0, 100) {
                RANDOM_INPUT(buffer, 80);
                size_t out_idx = rand64() % 48;
@@ -465,19 +251,31 @@ static int p_hchacha20()
                u8 out[32];
                crypto_hchacha20(out, key, in);
                crypto_hchacha20(buffer + out_idx, buffer + key_idx, buffer + in_idx);
-               status |= memcmp(out, buffer + out_idx, 32);
+               ASSERT_EQUAL(out, buffer + out_idx, 32);
        }
-       printf("%s: HChacha20 (overlap)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Tests that authenticating bit by bit yields the same mac than
-// authenticating all at once
-static int p_poly1305()
+
+/////////////////
+/// Poly 1305 ///
+/////////////////
+#define POLY1305_BLOCK_SIZE 16
+
+static void poly1305(vector_reader *reader)
 {
+       vector key = next_input(reader);
+       vector msg = next_input(reader);
+       vector out = next_output(reader);
+       crypto_poly1305(out.buf, msg.buf, msg.size, key.buf);
+}
+
+static void test_poly1305()
+{
+       VECTORS(poly1305);
+
+       printf("\tPoly1305 (incremental)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (POLY1305_BLOCK_SIZE * 4) // total input size
-       int status = 0;
        FOR (i, 0, INPUT_SIZE) {
                // outputs
                u8 mac_chunk[16];
@@ -496,40 +294,98 @@ static int p_poly1305()
                // Authenticate all at once
                crypto_poly1305(mac_whole, input, INPUT_SIZE, key);
 
-               // Compare the results (must be the same)
-               status |= memcmp(mac_chunk, mac_whole, 16);
+               // Compare the results
+               ASSERT_EQUAL(mac_chunk, mac_whole, 16);
        }
-       printf("%s: Poly1305 (incremental)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that the input and output buffers of poly1305 can overlap.
-static int p_poly1305_overlap()
-{
+       printf("\tPoly1305 (overlapping i/o)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (POLY1305_BLOCK_SIZE + (2 * 16)) // total input size
-       int status = 0;
        FOR (i, 0, POLY1305_BLOCK_SIZE + 16) {
                RANDOM_INPUT(input, INPUT_SIZE);
                RANDOM_INPUT(key  , 32);
                u8 mac  [16];
                crypto_poly1305(mac    , input + 16, POLY1305_BLOCK_SIZE, key);
                crypto_poly1305(input+i, input + 16, POLY1305_BLOCK_SIZE, key);
-               status |= memcmp(mac, input + i, 16);
+               ASSERT_EQUAL(mac, input + i, 16);
        }
-       printf("%s: Poly1305 (overlapping i/o)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Tests that hashing bit by bit yields the same hash than hashing all
-// at once.  Note: I figured we didn't need to test keyed mode, or
-// different hash sizes, again.  This test sticks to the simplified
-// interface.
-static int p_blake2b()
+////////////////////////////////
+/// Authenticated encryption ///
+////////////////////////////////
+static void aead_ietf(vector_reader *reader)
 {
+       vector key   = next_input(reader);
+       vector nonce = next_input(reader);
+       vector ad    = next_input(reader);
+       vector text  = next_input(reader);
+       vector out   = next_output(reader);
+       crypto_lock_aead(out.buf, out.buf + 16, key.buf, nonce.buf,
+                        ad.buf, ad.size, text.buf, text.size);
+}
+
+static void test_aead()
+{
+       VECTORS(aead_ietf);
+
+       printf("\taead (roundtrip)\n");
+       FOR (i, 0, 1000) {
+               RANDOM_INPUT(key      , 32);
+               RANDOM_INPUT(nonce    , 24);
+               RANDOM_INPUT(ad       ,  4);
+               RANDOM_INPUT(plaintext,  8);
+               u8 box[24], box2[24];
+               u8 out[8];
+               // AEAD roundtrip
+               crypto_lock_aead(box, box+16, key, nonce, ad, 4, plaintext, 8);
+               ASSERT_OK(crypto_unlock_aead(out, key, nonce, box, ad, 4, box+16, 8));
+               ASSERT_EQUAL(plaintext, out, 8);
+               box[0]++;
+               ASSERT_KO(crypto_unlock_aead(out, key, nonce, box, ad, 4, box+16, 8));
+
+               // Authenticated roundtrip (easy interface)
+               // Make and accept message
+               crypto_lock(box, box + 16, key, nonce, plaintext, 8);
+               ASSERT_OK(crypto_unlock(out, key, nonce, box, box + 16, 8));
+               // Make sure decrypted text and original text are the same
+               ASSERT_EQUAL(plaintext, out, 8);
+               // Make and reject forgery
+               box[0]++;
+               ASSERT_KO(crypto_unlock(out, key, nonce, box, box + 16, 8));
+               box[0]--; // undo forgery
+
+               // Same result for both interfaces
+               crypto_lock_aead(box2, box2 + 16, key, nonce, 0, 0, plaintext, 8);
+               ASSERT_EQUAL(box, box2, 24);
+       }
+}
+
+///////////////
+/// Blake2b ///
+///////////////
+#define BLAKE2B_BLOCK_SIZE 128
+
+static void blake2b(vector_reader *reader)
+{
+       vector msg = next_input(reader);
+       vector key = next_input(reader);
+       vector out = next_output(reader);
+       crypto_blake2b_general(out.buf, out.size,
+                              key.buf, key.size,
+                              msg.buf, msg.size);
+}
+
+static void test_blake2b()
+{
+       VECTORS(blake2b);
+
+       printf("\tBLAKE2b (incremental)\n");
+       // Note: I figured we didn't need to test keyed mode, or different
+       // hash sizes, a second time.  This test sticks to the simplified
+       // interface.
 #undef INPUT_SIZE
 #define INPUT_SIZE (BLAKE2B_BLOCK_SIZE * 4 - 32) // total input size
-       int status = 0;
        FOR (i, 0, INPUT_SIZE) {
                // outputs
                u8 hash_chunk[64];
@@ -548,36 +404,40 @@ static int p_blake2b()
                crypto_blake2b(hash_whole, input, INPUT_SIZE);
 
                // Compare the results (must be the same)
-               status |= memcmp(hash_chunk, hash_whole, 64);
+               ASSERT_EQUAL(hash_chunk, hash_whole, 64);
        }
-       printf("%s: BLAKE2b (incremental)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that the input and output buffers of BLAKE2b can overlap.
-static int p_blake2b_overlap()
-{
+       printf("\tBLAKE2b (overlapping i/o)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (BLAKE2B_BLOCK_SIZE + (2 * 64)) // total input size
-       int status = 0;
        FOR (i, 0, BLAKE2B_BLOCK_SIZE + 64) {
                u8 hash [64];
                RANDOM_INPUT(input, INPUT_SIZE);
                crypto_blake2b(hash   , input + 64, BLAKE2B_BLOCK_SIZE);
                crypto_blake2b(input+i, input + 64, BLAKE2B_BLOCK_SIZE);
-               status |= memcmp(hash, input + i, 64);
+               ASSERT_EQUAL(hash, input + i, 64);
        }
-       printf("%s: BLAKE2b (overlapping i/o)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Tests that hashing bit by bit yields the same hash than hashing all
-// at once. (for sha512)
-static int p_sha512()
+///////////////
+/// SHA 512 ///
+///////////////
+#define SHA_512_BLOCK_SIZE 128
+
+static void sha512(vector_reader *reader)
+{
+       vector in  = next_input(reader);
+       vector out = next_output(reader);
+       crypto_sha512(out.buf, in.buf, in.size);
+}
+
+static void test_sha512()
 {
+       VECTORS(sha512);
+
+       printf("\tSHA-512 (incremental)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (SHA_512_BLOCK_SIZE * 4 - 32) // total input size
-       int status = 0;
        FOR (i, 0, INPUT_SIZE) {
                // outputs
                u8 hash_chunk[64];
@@ -596,36 +456,41 @@ static int p_sha512()
                crypto_sha512(hash_whole, input, INPUT_SIZE);
 
                // Compare the results (must be the same)
-               status |= memcmp(hash_chunk, hash_whole, 64);
+               ASSERT_EQUAL(hash_chunk, hash_whole, 64);
        }
-       printf("%s: SHA-512 (incremental)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that the input and output buffers of crypto_sha_512 can overlap.
-static int p_sha512_overlap()
-{
+       printf("\tSHA-512 (overlapping i/o)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (SHA_512_BLOCK_SIZE + (2 * 64)) // total input size
-       int status = 0;
        FOR (i, 0, SHA_512_BLOCK_SIZE + 64) {
                u8 hash [64];
                RANDOM_INPUT(input, INPUT_SIZE);
                crypto_sha512(hash   , input + 64, SHA_512_BLOCK_SIZE);
                crypto_sha512(input+i, input + 64, SHA_512_BLOCK_SIZE);
-               status |= memcmp(hash, input + i, 64);
+               ASSERT_EQUAL(hash, input + i, 64);
        }
-       printf("%s: SHA-512 (overlapping i/o)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Tests that hashing bit by bit yields the same hash than hashing all
-// at once. (for hmac)
-static int p_hmac_sha512()
+
+////////////////////
+/// HMAC SHA 512 ///
+////////////////////
+static void hmac_sha512(vector_reader *reader)
+{
+       vector key = next_input(reader);
+       vector msg = next_input(reader);
+       vector out = next_output(reader);
+       crypto_hmac_sha512(out.buf, key.buf, key.size, msg.buf, msg.size);
+}
+
+static void test_hmac_sha512()
 {
+       VECTORS(hmac_sha512);
+
+
+       printf("\tHMAC SHA-512 (incremental)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (SHA_512_BLOCK_SIZE * 4 - 32) // total input size
-       int status = 0;
        FOR (i, 0, INPUT_SIZE) {
                // outputs
                u8 hash_chunk[64];
@@ -645,50 +510,63 @@ static int p_hmac_sha512()
                crypto_hmac_sha512(hash_whole, key, 32, input, INPUT_SIZE);
 
                // Compare the results (must be the same)
-               status |= memcmp(hash_chunk, hash_whole, 64);
+               ASSERT_EQUAL(hash_chunk, hash_whole, 64);
        }
-       printf("%s: HMAC SHA-512 (incremental)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Tests that the input and output buffers of HMAC can overlap.
-static int p_hmac_sha512_overlap()
-{
+       printf("\tHMAC SHA-512 (overlapping i/o)\n");
 #undef INPUT_SIZE
 #define INPUT_SIZE (SHA_512_BLOCK_SIZE + (2 * 64)) // total input size
-       int status = 0;
        FOR (i, 0, SHA_512_BLOCK_SIZE + 64) {
                u8 hash [64];
                RANDOM_INPUT(key  , 32);
                RANDOM_INPUT(input, INPUT_SIZE);
                crypto_hmac_sha512(hash   , key, 32, input + 64, SHA_512_BLOCK_SIZE);
                crypto_hmac_sha512(input+i, key, 32, input + 64, SHA_512_BLOCK_SIZE);
-               status |= memcmp(hash, input + i, 64);
+               ASSERT_EQUAL(hash, input + i, 64);
        }
-       printf("%s: HMAC SHA-512 (overlapping i/o)\n", status != 0 ? "FAILED":"OK");
-       return status;
 }
 
-static int p_argon2i_easy()
+///////////////
+/// Argon2i ///
+///////////////
+static void argon2i(vector_reader *reader)
 {
-       int   status    = 0;
-       void *work_area = alloc(8 * 1024);
-       RANDOM_INPUT(password , 32);
-       RANDOM_INPUT(salt     , 16);
-       u8 hash_general[32];
-       u8 hash_easy   [32];
-       crypto_argon2i_general(hash_general, 32, work_area, 8, 1,
-                              password, 32, salt, 16, 0, 0, 0, 0);
-       crypto_argon2i(hash_easy, 32, work_area, 8, 1, password, 32, salt, 16);
-       status |= memcmp(hash_general, hash_easy, 32);
+       u64    nb_blocks     = load64_le(next_input(reader).buf);
+       u64    nb_iterations = load64_le(next_input(reader).buf);
+       vector password      = next_input(reader);
+       vector salt          = next_input(reader);
+       vector key           = next_input(reader);
+       vector ad            = next_input(reader);
+       vector out           = next_output(reader);
+       void  *work_area     = alloc(nb_blocks * 1024);
+       crypto_argon2i_general(out.buf, (u32)out.size,
+                              work_area, (u32)nb_blocks, (u32)nb_iterations,
+                              password.buf, (u32)password.size,
+                              salt    .buf, (u32)salt    .size,
+                              key     .buf, (u32)key     .size,
+                              ad      .buf, (u32)ad      .size);
        free(work_area);
-       printf("%s: Argon2i (easy interface)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-static int p_argon2i_overlap()
+static void test_argon2i()
 {
-       int status          = 0;
+       VECTORS(argon2i);
+
+       printf("\tArgon2i (easy interface)\n");
+       {
+               void *work_area = alloc(8 * 1024);
+               RANDOM_INPUT(password , 32);
+               RANDOM_INPUT(salt     , 16);
+               u8 hash_general[32];
+               u8 hash_easy   [32];
+               crypto_argon2i_general(hash_general, 32, work_area, 8, 1,
+                                      password, 32, salt, 16, 0, 0, 0, 0);
+               crypto_argon2i(hash_easy, 32, work_area, 8, 1, password, 32, salt, 16);
+               ASSERT_EQUAL(hash_general, hash_easy, 32);
+               free(work_area);
+       }
+
+       printf("\tArgon2i (overlapping i/o)\n");
        u8 *work_area       = (u8*)alloc(8 * 1024);
        u8 *clean_work_area = (u8*)alloc(8 * 1024);
        FOR (i, 0, 10) {
@@ -712,19 +590,79 @@ static int p_argon2i_overlap()
                                       work_area + salt_offset, 16,
                                       work_area +  key_offset, 32,
                                       work_area +   ad_offset, 32);
-               status |= memcmp(hash1, hash2, 32);
+               ASSERT_EQUAL(hash1, hash2, 32);
        }
        free(work_area);
        free(clean_work_area);
-       printf("%s: Argon2i (overlapping i/o)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Tests that the shared key and secret key buffers of crypto_x25519 can
-// overlap.
-static int p_x25519_overlap()
+//////////////
+/// X25519 ///
+//////////////
+static void x25519(vector_reader *reader)
+{
+       vector scalar = next_input(reader);
+       vector point  = next_input(reader);
+       vector out    = next_output(reader);
+       crypto_x25519(out.buf, scalar.buf, point.buf);
+}
+
+static void x25519_pk(vector_reader *reader)
+{
+       vector in  = next_input(reader);
+       vector out = next_output(reader);
+       crypto_x25519_public_key(out.buf, in.buf);
+}
+
+static void iterate_x25519(u8 k[32], u8 u[32])
+{
+       u8 tmp[32];
+       crypto_x25519(tmp , k, u);
+       memcpy(u, k  , 32);
+       memcpy(k, tmp, 32);
+}
+
+static void test_x25519()
 {
-       int status = 0;
+       VECTORS(x25519);
+       VECTORS(x25519_pk);
+
+       {
+               printf("\tx25519 1\n");
+               u8 _1   [32] = {
+                       0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc,
+                       0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f,
+                       0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78,
+                       0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79
+               };
+               u8 k[32] = {9};
+               u8 u[32] = {9};
+               crypto_x25519_public_key(k, u);
+               ASSERT_EQUAL(k, _1, 32);
+
+               printf("\tx25519 1K\n");
+               u8 _1k  [32] = {
+                       0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55,
+                       0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c,
+                       0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87,
+                       0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51
+               };
+               FOR (i, 1, 1000) { iterate_x25519(k, u); }
+               ASSERT_EQUAL(k, _1k, 32);
+
+               // too long; didn't run
+               //printf("\tx25519 1M\n");
+               //u8 _1M[32] = {
+               //      0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd,
+               //      0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f,
+               //      0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf,
+               //      0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24
+               //};
+               //FOR (i, 1000, 1000000) { iterate_x25519(k, u); }
+               //ASSERT_EQUAL(k, _1M, 32);
+       }
+
+       printf("\tx25519 (overlapping i/o)\n");
        FOR (i, 0, 62) {
                u8 overlapping[94];
                u8 separate[32];
@@ -733,16 +671,108 @@ static int p_x25519_overlap()
                memcpy(overlapping + 31, sk, 32);
                crypto_x25519(overlapping + i, overlapping + 31, pk);
                crypto_x25519(separate, sk, pk);
-               status |= memcmp(separate, overlapping + i, 32);
+               ASSERT_EQUAL(separate, overlapping + i, 32);
+       }
+
+       printf("\tx25519_inverse\n");
+       {
+               RANDOM_INPUT(b, 32);
+               u8 base[32];  // random point (cofactor is cleared).
+               crypto_x25519_public_key(base, b);
+               // check round trip
+               FOR (i, 0, 50) {
+                       RANDOM_INPUT(sk, 32);
+                       u8 pk   [32];
+                       u8 blind[32];
+                       crypto_x25519(pk, sk, base);
+                       crypto_x25519_inverse(blind, sk, pk);
+                       ASSERT_EQUAL(blind, base, 32);
+               }
+
+               // check cofactor clearing
+               // (Multiplying by a low order point yields zero
+               u8 low_order[4][32] = {
+                       {0}, {1},
+                       {0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
+                        0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
+                        0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
+                        0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57,},
+                       {0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
+                        0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
+                        0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
+                        0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00,},
+               };
+               u8 zero[32] = {0};
+               FOR (i, 0, 32) {
+                       u8 blind[32];
+                       RANDOM_INPUT(sk, 32);
+                       crypto_x25519_inverse(blind, sk, low_order[i%4]);
+                       ASSERT_EQUAL(blind, zero, 32);
+               }
+       }
+
+       printf("\tx25519 inverse (overlapping i/o)\n");
+       FOR (i, 0, 62) {
+               u8 overlapping[94];
+               u8 separate[32];
+               RANDOM_INPUT(sk, 32);
+               RANDOM_INPUT(pk, 32);
+               memcpy(overlapping + 31, sk, 32);
+               crypto_x25519_inverse(overlapping + i, overlapping + 31, pk);
+               crypto_x25519_inverse(separate, sk, pk);
+               ASSERT_EQUAL(separate, overlapping + i, 32);
+       }
+}
+
+
+/////////////
+/// EdDSA ///
+/////////////
+static void edDSA(vector_reader *reader)
+{
+       vector secret_k = next_input(reader);
+       vector public_k = next_input(reader);
+       vector msg      = next_input(reader);
+       vector out      = next_output(reader);
+       u8 fat_secret_key[64];
+       memcpy(fat_secret_key     , secret_k.buf, 32);
+       memcpy(fat_secret_key + 32, public_k.buf, 32);
+       crypto_eddsa_sign(out.buf, fat_secret_key, msg.buf, msg.size);
+}
+
+static void edDSA_pk(vector_reader *reader)
+{
+       vector in  = next_input(reader);
+       vector out = next_output(reader);
+       u8 seed      [32];
+       u8 secret_key[64];
+       u8 public_key[32];
+       memcpy(seed, in.buf, 32);
+       crypto_eddsa_key_pair(secret_key, public_key, seed);
+       memcpy(out.buf, public_key, 32);
+
+       u8 zeroes[32] = {0};
+       if (memcmp(seed, zeroes, 32)) {
+               printf("FAILURE: seed has not been wiped\n");
+               exit(1);
+       }
+       if (memcmp(secret_key, in.buf, 32)) {
+               printf("FAILURE: first half of secret key is not the seed\n");
+               exit(1);
+       }
+       if (memcmp(secret_key + 32, public_key, 32)) {
+               printf("FAILURE: second half of secret key is not the public key\n");
+               exit(1);
        }
-       printf("%s: x25519 (overlapping i/o)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-static int p_eddsa_roundtrip()
+static void test_edDSA()
 {
+       VECTORS(edDSA);
+       VECTORS(edDSA_pk);
+
+       printf("\tEdDSA (roundtrip)\n");
 #define MESSAGE_SIZE 30
-       int status = 0;
        FOR (i, 0, MESSAGE_SIZE) {
                RANDOM_INPUT(message, MESSAGE_SIZE);
                RANDOM_INPUT(seed, 32);
@@ -751,39 +781,34 @@ static int p_eddsa_roundtrip()
                u8 signature[64];
                crypto_eddsa_key_pair(sk, pk, seed);
                crypto_eddsa_sign(signature, sk, message, i);
-               status |= crypto_eddsa_check(signature, pk, message, i);
+               ASSERT_OK(crypto_eddsa_check(signature, pk, message, i));
 
                // reject forgeries
                u8 zero   [64] = {0};
-               status |= !crypto_eddsa_check(zero , pk, message, i);
+               ASSERT_KO(crypto_eddsa_check(zero , pk, message, i));
                FOR (j, 0, 64) {
                        u8 forgery[64];
                        memcpy(forgery, signature, 64);
                        forgery[j] = signature[j] + 1;
-                       status |= !crypto_eddsa_check(forgery, pk, message, i);
+                       ASSERT_KO(crypto_eddsa_check(forgery, pk, message, i));
                }
        }
-       printf("%s: EdDSA (roundtrip)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-// Verifies that random signatures are all invalid.  Uses random
-// public keys to see what happens outside of the curve (it should
-// yield an invalid signature).
-static int p_eddsa_random()
-{
-       int status = 0;
-       FOR (i, 0, 100) {
+       printf("\tEdDSA (random)\n");
+       {
+               // Verifies that random signatures are all invalid.  Uses random
+               // public keys to see what happens outside of the curve (it should
+               // yield an invalid signature).
+               FOR (i, 0, 100) {
+                       RANDOM_INPUT(message, MESSAGE_SIZE);
+                       RANDOM_INPUT(pk, 32);
+                       RANDOM_INPUT(signature , 64);
+                       ASSERT_KO(crypto_eddsa_check(signature, pk, message, MESSAGE_SIZE));
+               }
+               // Testing S == L (for code coverage)
                RANDOM_INPUT(message, MESSAGE_SIZE);
                RANDOM_INPUT(pk, 32);
-               RANDOM_INPUT(signature , 64);
-               status |= ~crypto_eddsa_check(signature, pk, message, MESSAGE_SIZE);
-       }
-       // Testing S == L (for code coverage)
-       RANDOM_INPUT(message, MESSAGE_SIZE);
-       RANDOM_INPUT(pk, 32);
-       static const u8 signature[64] =
-               {
+               static const u8 signature[64] = {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
@@ -791,16 +816,10 @@ static int p_eddsa_random()
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
                };
-       status |= ~crypto_eddsa_check(signature, pk, message, MESSAGE_SIZE);
-
-       printf("%s: EdDSA (random)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
+               ASSERT_KO(crypto_eddsa_check(signature, pk, message, MESSAGE_SIZE));
+       }
 
-// Tests that the input and output buffers of crypto_sign() can overlap.
-static int p_eddsa_overlap()
-{
-       int status = 0;
+       printf("\tEdDSA (overlap)\n");
        FOR(i, 0, MESSAGE_SIZE + 64) {
 #undef INPUT_SIZE
 #define INPUT_SIZE (MESSAGE_SIZE + (2 * 64)) // total input size
@@ -812,52 +831,96 @@ static int p_eddsa_overlap()
                crypto_eddsa_key_pair(sk, pk, seed);
                crypto_eddsa_sign(signature, sk, input + 64, MESSAGE_SIZE);
                crypto_eddsa_sign(input+i  , sk, input + 64, MESSAGE_SIZE);
-               status |= memcmp(signature, input + i, 64);
+               ASSERT_EQUAL(signature, input + i, 64);
        }
-       printf("%s: EdDSA (overlap)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-static int p_aead()
+///////////////
+/// Ed25519 ///
+///////////////
+static void ed_25519(vector_reader *reader)
 {
-       int status = 0;
-       FOR (i, 0, 1000) {
-               RANDOM_INPUT(key      , 32);
-               RANDOM_INPUT(nonce    , 24);
-               RANDOM_INPUT(ad       ,  4);
-               RANDOM_INPUT(plaintext,  8);
-               u8 box[24], box2[24];
-               u8 out[8];
-               // AEAD roundtrip
-               crypto_lock_aead(box, box+16, key, nonce, ad, 4, plaintext, 8);
-               status |= crypto_unlock_aead(out, key, nonce, box, ad, 4, box+16, 8);
-               status |= memcmp(plaintext, out, 8);
-               box[0]++;
-               status |= !crypto_unlock_aead(out, key, nonce, box, ad, 4, box+16, 8);
+       vector secret_k = next_input(reader);
+       vector public_k = next_input(reader);
+       vector msg      = next_input(reader);
+       vector out      = next_output(reader);
+       u8 fat_secret_key[64];
+       memcpy(fat_secret_key     , secret_k.buf, 32);
+       memcpy(fat_secret_key + 32, public_k.buf, 32);
+       crypto_ed25519_sign(out.buf, fat_secret_key, msg.buf, msg.size);
+}
 
-               // Authenticated roundtrip (easy interface)
-               // Make and accept message
-               crypto_lock(box, box + 16, key, nonce, plaintext, 8);
-               status |= crypto_unlock(out, key, nonce, box, box + 16, 8);
-               // Make sure decrypted text and original text are the same
-               status |= memcmp(plaintext, out, 8);
-               // Make and reject forgery
-               box[0]++;
-               status |= !crypto_unlock(out, key, nonce, box, box + 16, 8);
-               box[0]--; // undo forgery
+static void ed_25519_pk(vector_reader *reader)
+{
+       vector in  = next_input(reader);
+       vector out = next_output(reader);
+       u8 seed      [32];
+       u8 secret_key[64];
+       u8 public_key[32];
+       memcpy(seed, in.buf, 32);
+       crypto_ed25519_key_pair(secret_key, public_key, seed);
+       memcpy(out.buf, public_key, 32);
 
-               // Same result for both interfaces
-               crypto_lock_aead(box2, box2 + 16, key, nonce, 0, 0, plaintext, 8);
-               status |= memcmp(box, box2, 24);
+       u8 zeroes[32] = {0};
+       if (memcmp(seed, zeroes, 32)) {
+               printf("FAILURE: seed has not been wiped\n");
+               exit(1);
+       }
+       if (memcmp(secret_key, in.buf, 32)) {
+               printf("FAILURE: first half of secret key is not the seed\n");
+               exit(1);
+       }
+       if (memcmp(secret_key + 32, public_key, 32)) {
+               printf("FAILURE: second half of secret key is not the public key\n");
+               exit(1);
+       }
+}
+
+static void ed_25519_check(vector_reader *reader)
+{
+       vector public_k = next_input(reader);
+       vector msg      = next_input(reader);
+       vector sig      = next_input(reader);
+       vector out      = next_output(reader);
+       out.buf[0] = (u8)crypto_ed25519_check(sig.buf, public_k.buf,
+                                             msg.buf, msg.size);
+}
+
+static void test_ed25519()
+{
+       VECTORS(ed_25519);
+       VECTORS(ed_25519_pk);
+       VECTORS(ed_25519_check);
+}
+
+/////////////////
+/// Elligator ///
+/////////////////
+static void elligator_dir(vector_reader *reader)
+{
+       vector in  = next_input(reader);
+       vector out = next_output(reader);
+       crypto_hidden_to_curve(out.buf, in.buf);
+}
+
+static void elligator_inv(vector_reader *reader)
+{
+       vector point   = next_input(reader);
+       u8     tweak   = next_input(reader).buf[0];
+       u8     failure = next_input(reader).buf[0];
+       vector out     = next_output(reader);
+       int    check   = crypto_curve_to_hidden(out.buf, point.buf, tweak);
+       if ((u8)check != failure) {
+               printf("Elligator inverse map: failure mismatch\n");
+               exit(1);
        }
-       printf("%s: aead (roundtrip)\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-// Elligator direct mapping must ignore the most significant bits
-static int p_elligator_direct_msb()
+static void test_elligator()
 {
-       int status = 0;
+       VECTORS(elligator_dir);
+
+       printf("\telligator direct (msb)\n");
        FOR (i, 0, 20) {
                RANDOM_INPUT(r, 32);
                u8 r1[32];  memcpy(r1, r, 32);  r1[31] = (r[31] & 0x3f) | 0x00;
@@ -869,18 +932,13 @@ static int p_elligator_direct_msb()
                u8 u2[32];  crypto_hidden_to_curve(u2, r2);
                u8 u3[32];  crypto_hidden_to_curve(u3, r3);
                u8 u4[32];  crypto_hidden_to_curve(u4, r4);
-               status |= memcmp(u, u1, 32);
-               status |= memcmp(u, u2, 32);
-               status |= memcmp(u, u3, 32);
-               status |= memcmp(u, u4, 32);
+               ASSERT_EQUAL(u, u1, 32);
+               ASSERT_EQUAL(u, u2, 32);
+               ASSERT_EQUAL(u, u3, 32);
+               ASSERT_EQUAL(u, u4, 32);
        }
-       printf("%s: elligator direct (msb)\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_elligator_direct_overlap()
-{
-       int status = 0;
+       printf("\telligator direct (overlapping i/o)\n");
        FOR (i, 0, 62) {
                u8 overlapping[94];
                u8 separate[32];
@@ -888,16 +946,12 @@ static int p_elligator_direct_overlap()
                memcpy(overlapping + 31, r, 32);
                crypto_hidden_to_curve(overlapping + i, overlapping + 31);
                crypto_hidden_to_curve(separate, r);
-               status |= memcmp(separate, overlapping + i, 32);
+               ASSERT_EQUAL(separate, overlapping + i, 32);
        }
-       printf("%s: elligator direct (overlapping i/o)\n",
-              status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_elligator_inverse_overlap()
-{
-       int status = 0;
+       VECTORS(elligator_inv);
+
+       printf("\telligator inverse (overlapping i/o)\n");
        FOR (i, 0, 62) {
                u8 overlapping[94];
                u8 separate[32];
@@ -906,20 +960,14 @@ static int p_elligator_inverse_overlap()
                memcpy(overlapping + 31, pk, 32);
                int a = crypto_curve_to_hidden(overlapping+i, overlapping+31, tweak);
                int b = crypto_curve_to_hidden(separate, pk, tweak);
-               status |= a - b;
+               ASSERT(a == b);
                if (a == 0) {
                        // The buffers are the same only if written to to begin with
-                       status |= memcmp(separate, overlapping + i, 32);
+                       ASSERT_EQUAL(separate, overlapping + i, 32);
                }
        }
-       printf("%s: elligator inverse (overlapping i/o)\n",
-              status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_elligator_x25519()
-{
-       int status = 0;
+       printf("\telligator x25519\n");
        int i = 0;
        while (i < 64) {
                RANDOM_INPUT(sk1, 32);
@@ -932,16 +980,16 @@ static int p_elligator_x25519()
                u8 pk1 [32];  crypto_x25519_public_key (pk1 , sk1);
 
                // Both dirty functions behave the same
-               status |= memcmp(pks, pkf, 32);
+               ASSERT_EQUAL(pks, pkf, 32);
 
                // Dirty functions behave cleanly if we clear the 3 lsb first
-               status |= memcmp(pksc, pk1, 32);
-               status |= memcmp(pkfc, pk1, 32);
+               ASSERT_EQUAL(pksc, pk1, 32);
+               ASSERT_EQUAL(pkfc, pk1, 32);
 
                // Dirty functions behave the same as the clean one if the lsb
                // are 0, differently if it is not
-               if ((sk1[0] & 7) == 0) { status |= memcmp(pk1, pkf, 32);      }
-               else                   { status |= memcmp(pk1, pkf, 32) == 0; }
+               if ((sk1[0] & 7) == 0) { ASSERT_EQUAL    (pk1, pkf, 32); }
+               else                   { ASSERT_DIFFERENT(pk1, pkf, 32); }
 
                // Maximise tweak diversity.
                // We want to set the bits 1 (sign) and 6-7 (padding)
@@ -951,25 +999,20 @@ static int p_elligator_x25519()
                        continue; // retry untill success (doesn't increment the tweak)
                }
                // Verify that the tweak's msb are copied to the representative
-               status |= (tweak >> 6) ^ (r[31] >> 6);
+               ASSERT((tweak >> 6) == (r[31] >> 6));
 
                // Round trip
                u8 pkr[32];  crypto_hidden_to_curve(pkr, r);
-               status |= memcmp(pkr, pkf, 32);
+               ASSERT_EQUAL(pkr, pkf, 32);
 
                // Dirty and safe keys are compatible
                u8 e1 [32];  crypto_x25519(e1, sk2, pk1);
                u8 e2 [32];  crypto_x25519(e2, sk2, pkr);
-               status |= memcmp(e1, e2, 32);
+               ASSERT_EQUAL(e1, e2, 32);
                i++;
        }
-       printf("%s: elligator x25519\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_elligator_key_pair()
-{
-       int status = 0;
+       printf("\telligator key pair\n");
        FOR(i, 0, 32) {
                RANDOM_INPUT(seed, 32);
                RANDOM_INPUT(sk2 , 32);
@@ -979,16 +1022,10 @@ static int p_elligator_key_pair()
                u8 pk1[32];  crypto_x25519_public_key(pk1, sk1);
                u8 e1 [32];  crypto_x25519(e1, sk2, pk1);
                u8 e2 [32];  crypto_x25519(e2, sk2, pkr);
-               status |= memcmp(e1, e2, 32);
+               ASSERT_EQUAL(e1, e2, 32);
        }
 
-       printf("%s: elligator key pair\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
-
-static int p_elligator_key_pair_overlap()
-{
-       int status = 0;
+       printf("\telligator key pair (overlapping i/o)\n");
        FOR (i, 0, 94) {
                u8 over[158];
                u8 sep [ 64];
@@ -997,75 +1034,17 @@ static int p_elligator_key_pair_overlap()
                memcpy(s2, s1, 32);
                crypto_hidden_key_pair(sep     , sep      + 32, s1);
                crypto_hidden_key_pair(over + i, over + i + 32, s2);
-               status |= memcmp(sep, over + i, 64);
-       }
-
-       printf("%s: elligator key pair (overlapping i/o)\n",
-              status != 0 ? "FAILED" : "OK");
-       return status;
-}
-
-static int p_x25519_inverse()
-{
-       int status = 0;
-       RANDOM_INPUT(b, 32);
-       u8 base[32];  // random point (cofactor is cleared).
-       crypto_x25519_public_key(base, b);
-       // check round trip
-       FOR (i, 0, 50) {
-               RANDOM_INPUT(sk, 32);
-               u8 pk   [32];
-               u8 blind[32];
-               crypto_x25519(pk, sk, base);
-               crypto_x25519_inverse(blind, sk, pk);
-               status |= memcmp(blind, base, 32);
-       }
-
-       // check cofactor clearing
-       // (Multiplying by a low order point yields zero
-       u8 low_order[4][32] = {
-               {0}, {1},
-               {0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
-                0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
-                0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
-                0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57,},
-               {0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
-                0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
-                0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
-                0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00,},
-       };
-       u8 zero[32] = {0};
-       FOR (i, 0, 32) {
-               u8 blind[32];
-               RANDOM_INPUT(sk, 32);
-               crypto_x25519_inverse(blind, sk, low_order[i%4]);
-               status |= memcmp(blind, zero, 32);
+               ASSERT_EQUAL(sep, over + i, 64);
        }
-       printf("%s: x25519_inverse\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-static int p_x25519_inverse_overlap()
-{
-       int status = 0;
-       FOR (i, 0, 62) {
-               u8 overlapping[94];
-               u8 separate[32];
-               RANDOM_INPUT(sk, 32);
-               RANDOM_INPUT(pk, 32);
-               memcpy(overlapping + 31, sk, 32);
-               crypto_x25519_inverse(overlapping + i, overlapping + 31, pk);
-               crypto_x25519_inverse(separate, sk, pk);
-               status |= memcmp(separate, overlapping + i, 32);
-       }
-       printf("%s: x25519 inverse (overlapping i/o)\n",
-              status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_from_eddsa()
+////////////////////////
+/// X25519 <-> EdDSA ///
+////////////////////////
+static void test_conversions()
 {
-       int status = 0;
+       printf("\tfrom_eddsa\n");
        FOR (i, 0, 32) {
                RANDOM_INPUT(ed_seed, 32);
                u8 secret   [64];
@@ -1073,15 +1052,10 @@ static int p_from_eddsa()
                u8 x_private[32]; crypto_from_eddsa_private(x_private, secret);
                u8 x_public1[32]; crypto_from_eddsa_public (x_public1, public);
                u8 x_public2[32]; crypto_x25519_public_key (x_public2, x_private);
-               status |= memcmp(x_public1, x_public2, 32);
+               ASSERT_EQUAL(x_public1, x_public2, 32);
        }
-       printf("%s: from_eddsa\n", status != 0 ? "FAILED" : "OK");
-       return status;
-}
 
-static int p_from_ed25519()
-{
-       int status = 0;
+       printf("\tfrom_ed25519\n");
        FOR (i, 0, 32) {
                RANDOM_INPUT(ed_seed, 32);
                u8 secret   [64];
@@ -1089,81 +1063,44 @@ static int p_from_ed25519()
                u8 x_private[32]; crypto_from_ed25519_private(x_private, secret);
                u8 x_public1[32]; crypto_from_ed25519_public (x_public1, public);
                u8 x_public2[32]; crypto_x25519_public_key (x_public2, x_private);
-               status |= memcmp(x_public1, x_public2, 32);
+               ASSERT_EQUAL(x_public1, x_public2, 32);
        }
-       printf("%s: from_ed25519\n", status != 0 ? "FAILED" : "OK");
-       return status;
 }
 
-int vector_test(void (*f)(vector_reader*),
-                const char *name, size_t nb_vectors, const char *vectors[]);
-
-#define TEST(name) vector_test(name, #name, nb_##name##_vectors, name##_vectors)
-
 int main(int argc, char *argv[])
 {
        if (argc > 1) {
                sscanf(argv[1], "%" PRIu64 "", &random_state);
        }
-       printf("\nRandom seed: %" PRIu64 "\n", random_state);
-
-       int status = 0;
-       printf("\nTest against vectors");
-       printf("\n--------------------\n");
-       status |= TEST(chacha20);
-       status |= TEST(ietf_chacha20);
-       status |= TEST(hchacha20);
-       status |= TEST(xchacha20);
-       status |= TEST(poly1305);
-       status |= TEST(aead_ietf);
-       status |= TEST(blake2b);
-       status |= TEST(sha512);
-       status |= TEST(hmac_sha512);
-       status |= TEST(argon2i);
-       status |= TEST(x25519);
-       status |= TEST(x25519_pk);
-       status |= TEST(edDSA);
-       status |= TEST(edDSA_pk);
-       status |= TEST(ed_25519);
-       status |= TEST(ed_25519_pk);
-       status |= TEST(ed_25519_check);
-       status |= TEST(elligator_dir);
-       status |= TEST(elligator_inv);
-       status |= test_x25519();
-       printf("\nProperty based tests");
-       printf("\n--------------------\n");
-       status |= p_verify16();
-       status |= p_verify32();
-       status |= p_verify64();
-       status |= p_chacha20_ctr();
-       status |= p_chacha20_stream();
-       status |= p_chacha20_same_ptr();
-       status |= p_hchacha20();
-       status |= p_poly1305();
-       status |= p_poly1305_overlap();
-       status |= p_blake2b();
-       status |= p_blake2b_overlap();
-       status |= p_sha512();
-       status |= p_sha512_overlap();
-       status |= p_hmac_sha512();
-       status |= p_hmac_sha512_overlap();
-       status |= p_argon2i_easy();
-       status |= p_argon2i_overlap();
-       status |= p_x25519_overlap();
-       status |= p_eddsa_roundtrip();
-       status |= p_eddsa_random();
-       status |= p_eddsa_overlap();
-       status |= p_aead();
-       status |= p_elligator_direct_msb();
-       status |= p_elligator_direct_overlap();
-       status |= p_elligator_inverse_overlap();
-       status |= p_elligator_x25519();
-       status |= p_elligator_key_pair();
-       status |= p_elligator_key_pair_overlap();
-       status |= p_x25519_inverse();
-       status |= p_x25519_inverse_overlap();
-       status |= p_from_eddsa();
-       status |= p_from_ed25519();
-       printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!");
-       return status;
+       printf("\nRandom seed = %" PRIu64 "\n\n", random_state);
+
+       printf("Comparisons:\n");
+       test_verify();
+
+       printf("Encryption:\n");
+       test_chacha20();
+       test_aead();
+
+       printf("Hashes:\n");
+       test_poly1305();
+       test_blake2b();
+       test_sha512();
+       test_hmac_sha512();
+       test_argon2i();
+
+       printf("X25519:\n");
+       test_x25519();
+
+       printf("EdDSA:\n");
+       test_edDSA();
+       test_ed25519();
+
+       printf("Elligator:\n");
+       test_elligator();
+
+       printf("Curve25519 conversions:\n");
+       test_conversions();
+
+       printf("\nAll tests OK!\n");
+       return 0;
 }
index f55f11e8c7b135c3b7f1b52cbc0bdb3c1b12a8e7..f7235f0cc0c562fb03be5dad10fca2edfdf7b312 100644 (file)
@@ -185,8 +185,9 @@ vector next_output(vector_reader *reader)
 int vector_test(void (*f)(vector_reader*),
                 const char *name, size_t nb_vectors, const char *vectors[])
 {
-       int status   = 0;
-       int nb_tests = 0;
+       int status = 0;
+       printf("\t%s\n", name);
+
        vector_reader in;
        in.size = nb_vectors;
        in.next = vectors;
@@ -202,10 +203,6 @@ int vector_test(void (*f)(vector_reader*),
                }
                free(in.out.buf);
                free(in.expected.buf);
-               nb_tests++;
        }
-       printf("%s %4d tests: %s\n",
-              status != 0 ? "FAILED" : "OK", nb_tests, name);
        return status;
 }
-
index 30db972a2ae12df636764997d376683e36040b18..d0f5e6fd7a794013a262606da01975769744fb4f 100644 (file)
@@ -63,14 +63,19 @@ typedef int64_t  i64;
 typedef uint64_t u64;
 
 #define FOR(i, start, end) for (size_t i = (start); i < (end); i++)
-#define SODIUM_INIT    \
-       do { \
-               if (sodium_init() == -1) { \
-                       printf("libsodium init failed.  Abort.\n"); \
-                       return 1; \
+#define SODIUM_INIT    ASSERT(sodium_init() != -1)
+#define RANDOM_INPUT(name, size) u8 name[size]; p_random(name, size)
+#define ASSERT(condition) do { \
+               if (!(condition)) { \
+                       fprintf(stderr, "Assert failure(%s, %d): %s\n", \
+                               __FILE__, __LINE__, #condition); \
+                       exit(1); \
                } \
        } while (0)
-#define RANDOM_INPUT(name, size) u8 name[size]; p_random(name, size)
+#define ASSERT_EQUAL(a, b, size)     ASSERT( memcmp(a, b, size) == 0)
+#define ASSERT_DIFFERENT(a, b, size) ASSERT(!memcmp(a, b, size) == 0)
+#define ASSERT_OK(exp)               ASSERT((exp) == 0)
+#define ASSERT_KO(exp)               ASSERT((exp) != 0)
 
 extern u64 random_state; // state of the RNG
 
@@ -99,7 +104,7 @@ void* alloc(size_t size);
 
 vector next_input (vector_reader *vectors);
 vector next_output(vector_reader *vectors);
-int vector_test(void (*f)(vector_reader*),
-                const char *name, size_t nb_vectors, const char *vectors[]);
+int  vector_test(void (*f)(vector_reader*),
+                 const char *name, size_t nb_vectors, const char *vectors[]);
 
 #endif // UTILS_H