Fixed IV processing for CBC decryption with AES (x86ni implementation) when data...
[BearSSL] / test / test_crypto.c
index 33f31a6..fd0b396 100644 (file)
@@ -47,9 +47,9 @@ hextobin(unsigned char *dst, const char *src)
                if (c >= '0' && c <= '9') {
                        c -= '0';
                } else if (c >= 'A' && c <= 'F') {
-                       c -= ('A' - 10); \
+                       c -= ('A' - 10);
                } else if (c >= 'a' && c <= 'f') {
-                       c -= ('a' - 10); \
+                       c -= ('a' - 10);
                } else {
                        continue;
                }
@@ -591,7 +591,7 @@ test_HMAC_CT(const br_hash_class *digest_class,
 
        br_hmac_key_init(&kc, digest_class, key, key_len);
 
-       for (u = 0; u < 130; u ++) {
+       for (u = 0; u < 2; u ++) {
                for (v = 0; v < 130; v ++) {
                        size_t min_len, max_len;
                        size_t w;
@@ -3133,6 +3133,71 @@ test_AES_generic(char *name,
                        check_equals("KAT CBC AES decrypt (2)",
                                buf, plain, data_len);
                }
+
+               /*
+                * We want to check proper IV management for CBC:
+                * encryption and decryption must properly copy the _last_
+                * encrypted block as new IV, for all sizes.
+                */
+               for (u = 1; u <= 35; u ++) {
+                       br_hmac_drbg_context rng;
+                       unsigned char x;
+                       size_t key_len, data_len;
+                       size_t v;
+
+                       br_hmac_drbg_init(&rng, &br_sha256_vtable,
+                               "seed for AES/CBC", 16);
+                       x = u;
+                       br_hmac_drbg_update(&rng, &x, 1);
+                       data_len = u << 4;
+                       for (key_len = 16; key_len <= 32; key_len += 16) {
+                               unsigned char key[32];
+                               unsigned char iv[16], iv1[16], iv2[16];
+                               unsigned char plain[35 * 16];
+                               unsigned char tmp1[sizeof plain];
+                               unsigned char tmp2[sizeof plain];
+                               br_aes_gen_cbcenc_keys v_ec;
+                               br_aes_gen_cbcdec_keys v_dc;
+                               const br_block_cbcenc_class **ec;
+                               const br_block_cbcdec_class **dc;
+
+                               br_hmac_drbg_generate(&rng, key, key_len);
+                               br_hmac_drbg_generate(&rng, iv, sizeof iv);
+                               br_hmac_drbg_generate(&rng, plain, data_len);
+
+                               ec = &v_ec.vtable;
+                               ve->init(ec, key, key_len);
+                               memcpy(iv1, iv, sizeof iv);
+                               memcpy(tmp1, plain, data_len);
+                               ve->run(ec, iv1, tmp1, data_len);
+                               check_equals("IV CBC AES (1)",
+                                       tmp1 + data_len - 16, iv1, 16);
+                               memcpy(iv2, iv, sizeof iv);
+                               memcpy(tmp2, plain, data_len);
+                               for (v = 0; v < data_len; v += 16) {
+                                       ve->run(ec, iv2, tmp2 + v, 16);
+                               }
+                               check_equals("IV CBC AES (2)",
+                                       tmp2 + data_len - 16, iv2, 16);
+                               check_equals("IV CBC AES (3)",
+                                       tmp1, tmp2, data_len);
+
+                               dc = &v_dc.vtable;
+                               vd->init(dc, key, key_len);
+                               memcpy(iv1, iv, sizeof iv);
+                               vd->run(dc, iv1, tmp1, data_len);
+                               check_equals("IV CBC AES (4)", iv1, iv2, 16);
+                               check_equals("IV CBC AES (5)",
+                                       tmp1, plain, data_len);
+                               memcpy(iv2, iv, sizeof iv);
+                               for (v = 0; v < data_len; v += 16) {
+                                       vd->run(dc, iv2, tmp2 + v, 16);
+                               }
+                               check_equals("IV CBC AES (6)", iv1, iv2, 16);
+                               check_equals("IV CBC AES (7)",
+                                       tmp2, plain, data_len);
+                       }
+               }
        }
 
        if (vc != NULL) {
@@ -3157,7 +3222,6 @@ test_AES_generic(char *name,
                        data_len = hextobin(plain, KAT_AES_CTR[u + 2]);
                        hextobin(cipher, KAT_AES_CTR[u + 3]);
                        vc->init(xc, key, key_len);
-
                        memcpy(buf, plain, data_len);
                        vc->run(xc, iv, 1, buf, data_len);
                        check_equals("KAT CTR AES (1)", buf, cipher, data_len);
@@ -3271,6 +3335,60 @@ test_AES_ct64(void)
                1, 1);
 }
 
+static void
+test_AES_x86ni(void)
+{
+       const br_block_cbcenc_class *x_cbcenc;
+       const br_block_cbcdec_class *x_cbcdec;
+       const br_block_ctr_class *x_ctr;
+       int hcbcenc, hcbcdec, hctr;
+
+       x_cbcenc = br_aes_x86ni_cbcenc_get_vtable();
+       x_cbcdec = br_aes_x86ni_cbcdec_get_vtable();
+       x_ctr = br_aes_x86ni_ctr_get_vtable();
+       hcbcenc = (x_cbcenc != NULL);
+       hcbcdec = (x_cbcdec != NULL);
+       hctr = (x_ctr != NULL);
+       if (hcbcenc != hctr || hcbcdec != hctr) {
+               fprintf(stderr, "AES_x86ni availability mismatch (%d/%d/%d)\n",
+                       hcbcenc, hcbcdec, hctr);
+               exit(EXIT_FAILURE);
+       }
+       if (hctr) {
+               test_AES_generic("AES_x86ni",
+                       x_cbcenc, x_cbcdec, x_ctr, 1, 1);
+       } else {
+               printf("Test AES_x86ni: UNAVAILABLE\n");
+       }
+}
+
+static void
+test_AES_pwr8(void)
+{
+       const br_block_cbcenc_class *x_cbcenc;
+       const br_block_cbcdec_class *x_cbcdec;
+       const br_block_ctr_class *x_ctr;
+       int hcbcenc, hcbcdec, hctr;
+
+       x_cbcenc = br_aes_pwr8_cbcenc_get_vtable();
+       x_cbcdec = br_aes_pwr8_cbcdec_get_vtable();
+       x_ctr = br_aes_pwr8_ctr_get_vtable();
+       hcbcenc = (x_cbcenc != NULL);
+       hcbcdec = (x_cbcdec != NULL);
+       hctr = (x_ctr != NULL);
+       if (hcbcenc != hctr || hcbcdec != hctr) {
+               fprintf(stderr, "AES_pwr8 availability mismatch (%d/%d/%d)\n",
+                       hcbcenc, hcbcdec, hctr);
+               exit(EXIT_FAILURE);
+       }
+       if (hctr) {
+               test_AES_generic("AES_pwr8",
+                       x_cbcenc, x_cbcdec, x_ctr, 1, 1);
+       } else {
+               printf("Test AES_pwr8: UNAVAILABLE\n");
+       }
+}
+
 /*
  * DES known-answer tests. Order: plaintext, key, ciphertext.
  * (mostly from NIST SP 800-20).
@@ -4113,11 +4231,13 @@ static const struct {
 };
 
 static void
-test_Poly1305_ctmul(void)
+test_Poly1305_inner(const char *name, br_poly1305_run ipoly,
+       br_poly1305_run iref)
 {
        size_t u;
+       br_hmac_drbg_context rng;
 
-       printf("Test Poly1305_ctmul: ");
+       printf("Test %s: ", name);
        fflush(stdout);
 
        for (u = 0; KAT_POLY1305[u].skey; u ++) {
@@ -4133,27 +4253,50 @@ test_Poly1305_ctmul(void)
                hextobin(tag, KAT_POLY1305[u].stag);
 
                memcpy(data, plain, len);
-               br_poly1305_ctmul_run(key, nonce, data, len,
+               ipoly(key, nonce, data, len,
                        aad, aad_len, tmp, br_chacha20_ct_run, 1);
-               if (memcmp(data, cipher, len) != 0) {
-                       fprintf(stderr, "ChaCha20+Poly1305 KAT failed (1)\n");
-                       exit(EXIT_FAILURE);
-               }
-               if (memcmp(tmp, tag, 16) != 0) {
-                       fprintf(stderr, "ChaCha20+Poly1305 KAT failed (2)\n");
-                       exit(EXIT_FAILURE);
-               }
-               br_poly1305_ctmul_run(key, nonce, data, len,
+               check_equals("ChaCha20+Poly1305 KAT (1)", data, cipher, len);
+               check_equals("ChaCha20+Poly1305 KAT (2)", tmp, tag, 16);
+               ipoly(key, nonce, data, len,
                        aad, aad_len, tmp, br_chacha20_ct_run, 0);
-               if (memcmp(data, plain, len) != 0) {
-                       fprintf(stderr, "ChaCha20+Poly1305 KAT failed (3)\n");
+               check_equals("ChaCha20+Poly1305 KAT (3)", data, plain, len);
+               check_equals("ChaCha20+Poly1305 KAT (4)", tmp, tag, 16);
+
+               printf(".");
+               fflush(stdout);
+       }
+
+       printf(" ");
+       fflush(stdout);
+
+       /*
+        * We compare the "ipoly" and "iref" implementations together on
+        * a bunch of pseudo-random messages.
+        */
+       br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for Poly1305", 17);
+       for (u = 0; u < 100; u ++) {
+               unsigned char plain[100], aad[100], tmp[100];
+               unsigned char key[32], iv[12], tag1[16], tag2[16];
+
+               br_hmac_drbg_generate(&rng, key, sizeof key);
+               br_hmac_drbg_generate(&rng, iv, sizeof iv);
+               br_hmac_drbg_generate(&rng, plain, u);
+               br_hmac_drbg_generate(&rng, aad, u);
+               memcpy(tmp, plain, u);
+               memset(tmp + u, 0xFF, (sizeof tmp) - u);
+               ipoly(key, iv, tmp, u, aad, u, tag1,
+                       &br_chacha20_ct_run, 1);
+               memset(tmp + u, 0x00, (sizeof tmp) - u);
+               iref(key, iv, tmp, u, aad, u, tag2,
+                       &br_chacha20_ct_run, 0);
+               if (memcmp(tmp, plain, u) != 0) {
+                       fprintf(stderr, "cross enc/dec failed\n");
                        exit(EXIT_FAILURE);
                }
-               if (memcmp(tmp, tag, 16) != 0) {
-                       fprintf(stderr, "ChaCha20+Poly1305 KAT failed (4)\n");
+               if (memcmp(tag1, tag2, sizeof tag1) != 0) {
+                       fprintf(stderr, "cross MAC failed\n");
                        exit(EXIT_FAILURE);
                }
-
                printf(".");
                fflush(stdout);
        }
@@ -4162,6 +4305,41 @@ test_Poly1305_ctmul(void)
        fflush(stdout);
 }
 
+static void
+test_Poly1305_ctmul(void)
+{
+       test_Poly1305_inner("Poly1305_ctmul", &br_poly1305_ctmul_run,
+               &br_poly1305_i15_run);
+}
+
+static void
+test_Poly1305_ctmul32(void)
+{
+       test_Poly1305_inner("Poly1305_ctmul32", &br_poly1305_ctmul32_run,
+               &br_poly1305_i15_run);
+}
+
+static void
+test_Poly1305_i15(void)
+{
+       test_Poly1305_inner("Poly1305_i15", &br_poly1305_i15_run,
+               &br_poly1305_ctmul_run);
+}
+
+static void
+test_Poly1305_ctmulq(void)
+{
+       br_poly1305_run bp;
+
+       bp = br_poly1305_ctmulq_get();
+       if (bp == 0) {
+               printf("Test Poly1305_ctmulq: UNAVAILABLE\n");
+       } else {
+               test_Poly1305_inner("Poly1305_ctmulq", bp,
+                       &br_poly1305_ctmul_run);
+       }
+}
+
 /*
  * A 1024-bit RSA key, generated with OpenSSL.
  */
@@ -4367,6 +4545,14 @@ test_RSA_sign(const char *name, br_rsa_private fpriv,
        fflush(stdout);
 }
 
+static void
+test_RSA_i15(void)
+{
+       test_RSA_core("RSA i15 core", &br_rsa_i15_public, &br_rsa_i15_private);
+       test_RSA_sign("RSA i15 sign", &br_rsa_i15_private,
+               &br_rsa_i15_pkcs1_sign, &br_rsa_i15_pkcs1_vrfy);
+}
+
 static void
 test_RSA_i31(void)
 {
@@ -4383,6 +4569,34 @@ test_RSA_i32(void)
                &br_rsa_i32_pkcs1_sign, &br_rsa_i32_pkcs1_vrfy);
 }
 
+static void
+test_RSA_i62(void)
+{
+       br_rsa_public pub;
+       br_rsa_private priv;
+       br_rsa_pkcs1_sign sign;
+       br_rsa_pkcs1_vrfy vrfy;
+
+       pub = br_rsa_i62_public_get();
+       priv = br_rsa_i62_private_get();
+       sign = br_rsa_i62_pkcs1_sign_get();
+       vrfy = br_rsa_i62_pkcs1_vrfy_get();
+       if (pub) {
+               if (!priv || !sign || !vrfy) {
+                       fprintf(stderr, "Inconsistent i62 availability\n");
+                       exit(EXIT_FAILURE);
+               }
+               test_RSA_core("RSA i62 core", pub, priv);
+               test_RSA_sign("RSA i62 sign", priv, sign, vrfy);
+       } else {
+               if (priv || sign || vrfy) {
+                       fprintf(stderr, "Inconsistent i62 availability\n");
+                       exit(EXIT_FAILURE);
+               }
+               printf("Test RSA i62: UNAVAILABLE\n");
+       }
+}
+
 #if 0
 static void
 test_RSA_signatures(void)
@@ -4583,6 +4797,31 @@ test_GHASH(const char *name, br_ghash gh)
                check_equals("KAT GHASH", y, ref, sizeof ref);
        }
 
+       for (u = 0; u <= 1024; u ++) {
+               unsigned char key[32], iv[12];
+               unsigned char buf[1024 + 32];
+               unsigned char y0[16], y1[16];
+               char tmp[100];
+
+               memset(key, 0, sizeof key);
+               memset(iv, 0, sizeof iv);
+               br_enc32be(key, u);
+               memset(buf, 0, sizeof buf);
+               br_chacha20_ct_run(key, iv, 1, buf, sizeof buf);
+
+               memcpy(y0, buf, 16);
+               br_ghash_ctmul32(y0, buf + 16, buf + 32, u);
+               memcpy(y1, buf, 16);
+               gh(y1, buf + 16, buf + 32, u);
+               sprintf(tmp, "XREF %s (len = %u)", name, (unsigned)u);
+               check_equals(tmp, y0, y1, 16);
+
+               if ((u & 31) == 0) {
+                       printf(".");
+                       fflush(stdout);
+               }
+       }
+
        printf("done.\n");
        fflush(stdout);
 }
@@ -4605,6 +4844,32 @@ test_GHASH_ctmul64(void)
        test_GHASH("GHASH_ctmul64", br_ghash_ctmul64);
 }
 
+static void
+test_GHASH_pclmul(void)
+{
+       br_ghash gh;
+
+       gh = br_ghash_pclmul_get();
+       if (gh == 0) {
+               printf("Test GHASH_pclmul: UNAVAILABLE\n");
+       } else {
+               test_GHASH("GHASH_pclmul", gh);
+       }
+}
+
+static void
+test_GHASH_pwr8(void)
+{
+       br_ghash gh;
+
+       gh = br_ghash_pwr8_get();
+       if (gh == 0) {
+               printf("Test GHASH_pwr8: UNAVAILABLE\n");
+       } else {
+               test_GHASH("GHASH_pwr8", gh);
+       }
+}
+
 static void
 test_EC_inner(const char *sk, const char *sU,
        const br_ec_impl *impl, int curve)
@@ -4724,6 +4989,20 @@ test_EC_inner(const char *sk, const char *sU,
                        exit(EXIT_FAILURE);
                }
 
+               /*
+                * Also recomputed D = z*G with mulgen(). This must
+                * again match.
+                */
+               memset(eD, 0, ulen);
+               if (impl->mulgen(eD, bz, nlen, cd->curve) != ulen) {
+                       fprintf(stderr, "mulgen() failed: wrong length\n");
+                       exit(EXIT_FAILURE);
+               }
+               if (memcmp(eC, eD, nlen) != 0) {
+                       fprintf(stderr, "mulgen() / muladd() mismatch\n");
+                       exit(EXIT_FAILURE);
+               }
+
                /*
                 * Check with x*A = y*B. We do so by setting b = x and y = a.
                 */
@@ -4813,6 +5092,15 @@ test_EC_KAT(const char *name, const br_ec_impl *impl, uint32_t curve_mask)
        fflush(stdout);
 }
 
+static void
+test_EC_prime_i15(void)
+{
+       test_EC_KAT("EC_prime_i15", &br_ec_prime_i15,
+               (uint32_t)1 << BR_EC_secp256r1
+               | (uint32_t)1 << BR_EC_secp384r1
+               | (uint32_t)1 << BR_EC_secp521r1);
+}
+
 static void
 test_EC_prime_i31(void)
 {
@@ -4822,6 +5110,124 @@ test_EC_prime_i31(void)
                | (uint32_t)1 << BR_EC_secp521r1);
 }
 
+static void
+test_EC_p256_m15(void)
+{
+       test_EC_KAT("EC_p256_m15", &br_ec_p256_m15,
+               (uint32_t)1 << BR_EC_secp256r1);
+}
+
+static void
+test_EC_p256_m31(void)
+{
+       test_EC_KAT("EC_p256_m31", &br_ec_p256_m31,
+               (uint32_t)1 << BR_EC_secp256r1);
+}
+
+const struct {
+       const char *scalar;
+       const char *u_in;
+       const char *u_out;
+} C25519_KAT[] = {
+       { "A546E36BF0527C9D3B16154B82465EDD62144C0AC1FC5A18506A2244BA449AC4",
+         "E6DB6867583030DB3594C1A424B15F7C726624EC26B3353B10A903A6D0AB1C4C",
+         "C3DA55379DE9C6908E94EA4DF28D084F32ECCF03491C71F754B4075577A28552" },
+       { "4B66E9D4D1B4673C5AD22691957D6AF5C11B6421E0EA01D42CA4169E7918BA0D",
+         "E5210F12786811D3F4B7959D0538AE2C31DBE7106FC03C3EFC4CD549C715A493",
+         "95CBDE9476E8907D7AADE45CB4B873F88B595A68799FA152E6F8F7647AAC7957" },
+       { 0, 0, 0 }
+};
+
+static void
+test_EC_c25519(const char *name, const br_ec_impl *iec)
+{
+       unsigned char bu[32], bk[32], br[32];
+       size_t v;
+       int i;
+
+       printf("Test %s: ", name);
+       fflush(stdout);
+       for (v = 0; C25519_KAT[v].scalar; v ++) {
+               hextobin(bk, C25519_KAT[v].scalar);
+               hextobin(bu, C25519_KAT[v].u_in);
+               hextobin(br, C25519_KAT[v].u_out);
+               if (!iec->mul(bu, sizeof bu, bk, sizeof bk, BR_EC_curve25519)) {
+                       fprintf(stderr, "Curve25519 multiplication failed\n");
+                       exit(EXIT_FAILURE);
+               }
+               if (memcmp(bu, br, sizeof bu) != 0) {
+                       fprintf(stderr, "Curve25519 failed KAT\n");
+                       exit(EXIT_FAILURE);
+               }
+               printf(".");
+               fflush(stdout);
+       }
+       printf(" ");
+       fflush(stdout);
+
+       memset(bu, 0, sizeof bu);
+       bu[0] = 0x09;
+       memcpy(bk, bu, sizeof bu);
+       for (i = 1; i <= 1000; i ++) {
+               if (!iec->mul(bu, sizeof bu, bk, sizeof bk, BR_EC_curve25519)) {
+                       fprintf(stderr, "Curve25519 multiplication failed"
+                               " (iter=%d)\n", i);
+                       exit(EXIT_FAILURE);
+               }
+               for (v = 0; v < sizeof bu; v ++) {
+                       unsigned t;
+
+                       t = bu[v];
+                       bu[v] = bk[v];
+                       bk[v] = t;
+               }
+               if (i == 1 || i == 1000) {
+                       const char *sref;
+
+                       sref = (i == 1)
+                               ? "422C8E7A6227D7BCA1350B3E2BB7279F7897B87BB6854B783C60E80311AE3079"
+                               : "684CF59BA83309552800EF566F2F4D3C1C3887C49360E3875F2EB94D99532C51";
+                       hextobin(br, sref);
+                       if (memcmp(bk, br, sizeof bk) != 0) {
+                               fprintf(stderr,
+                                       "Curve25519 failed KAT (iter=%d)\n", i);
+                               exit(EXIT_FAILURE);
+                       }
+               }
+               if (i % 100 == 0) {
+                       printf(".");
+                       fflush(stdout);
+               }
+       }
+
+       printf(" done.\n");
+       fflush(stdout);
+}
+
+static void
+test_EC_c25519_i15(void)
+{
+       test_EC_c25519("EC_c25519_i15", &br_ec_c25519_i15);
+}
+
+static void
+test_EC_c25519_i31(void)
+{
+       test_EC_c25519("EC_c25519_i31", &br_ec_c25519_i31);
+}
+
+static void
+test_EC_c25519_m15(void)
+{
+       test_EC_c25519("EC_c25519_m15", &br_ec_c25519_m15);
+}
+
+static void
+test_EC_c25519_m31(void)
+{
+       test_EC_c25519("EC_c25519_m31", &br_ec_c25519_m31);
+}
+
 static const unsigned char EC_P256_PUB_POINT[] = {
        0x04, 0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D,
        0x31, 0xC9, 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D,
@@ -5194,7 +5600,8 @@ const ecdsa_kat_vector ECDSA_KAT[] = {
 };
 
 static void
-test_ECDSA_KAT(br_ecdsa_sign sign, br_ecdsa_vrfy vrfy, int asn1)
+test_ECDSA_KAT(const br_ec_impl *iec,
+       br_ecdsa_sign sign, br_ecdsa_vrfy vrfy, int asn1)
 {
        size_t u;
 
@@ -5221,28 +5628,28 @@ test_ECDSA_KAT(br_ecdsa_sign sign, br_ecdsa_vrfy vrfy, int asn1)
                        sig_len = hextobin(sig, kv->sraw);
                }
 
-               if (vrfy(&br_ec_prime_i31, hash, hash_len,
+               if (vrfy(iec, hash, hash_len,
                        kv->pub, sig, sig_len) != 1)
                {
                        fprintf(stderr, "ECDSA KAT verify failed (1)\n");
                        exit(EXIT_FAILURE);
                }
                hash[0] ^= 0x80;
-               if (vrfy(&br_ec_prime_i31, hash, hash_len,
+               if (vrfy(iec, hash, hash_len,
                        kv->pub, sig, sig_len) != 0)
                {
                        fprintf(stderr, "ECDSA KAT verify shoud have failed\n");
                        exit(EXIT_FAILURE);
                }
                hash[0] ^= 0x80;
-               if (vrfy(&br_ec_prime_i31, hash, hash_len,
+               if (vrfy(iec, hash, hash_len,
                        kv->pub, sig, sig_len) != 1)
                {
                        fprintf(stderr, "ECDSA KAT verify failed (2)\n");
                        exit(EXIT_FAILURE);
                }
 
-               sig2_len = sign(&br_ec_prime_i31, kv->hf, hash, kv->priv, sig2);
+               sig2_len = sign(iec, kv->hf, hash, kv->priv, sig2);
                if (sig2_len == 0) {
                        fprintf(stderr, "ECDSA KAT sign failed\n");
                        exit(EXIT_FAILURE);
@@ -5264,10 +5671,131 @@ test_ECDSA_i31(void)
        fflush(stdout);
        printf("[raw]");
        fflush(stdout);
-       test_ECDSA_KAT(&br_ecdsa_i31_sign_raw, &br_ecdsa_i31_vrfy_raw, 0);
+       test_ECDSA_KAT(&br_ec_prime_i31,
+               &br_ecdsa_i31_sign_raw, &br_ecdsa_i31_vrfy_raw, 0);
+       printf(" [asn1]");
+       fflush(stdout);
+       test_ECDSA_KAT(&br_ec_prime_i31,
+               &br_ecdsa_i31_sign_asn1, &br_ecdsa_i31_vrfy_asn1, 1);
+       printf(" done.\n");
+       fflush(stdout);
+}
+
+static void
+test_ECDSA_i15(void)
+{
+       printf("Test ECDSA/i15: ");
+       fflush(stdout);
+       printf("[raw]");
+       fflush(stdout);
+       test_ECDSA_KAT(&br_ec_prime_i15,
+               &br_ecdsa_i15_sign_raw, &br_ecdsa_i15_vrfy_raw, 0);
        printf(" [asn1]");
        fflush(stdout);
-       test_ECDSA_KAT(&br_ecdsa_i31_sign_asn1, &br_ecdsa_i31_vrfy_asn1, 1);
+       test_ECDSA_KAT(&br_ec_prime_i31,
+               &br_ecdsa_i15_sign_asn1, &br_ecdsa_i15_vrfy_asn1, 1);
+       printf(" done.\n");
+       fflush(stdout);
+}
+
+static void
+test_modpow_i31(void)
+{
+       br_hmac_drbg_context hc;
+       int k;
+
+       printf("Test ModPow/i31: ");
+
+       br_hmac_drbg_init(&hc, &br_sha256_vtable, "seed modpow", 11);
+       for (k = 10; k <= 500; k ++) {
+               size_t blen;
+               unsigned char bm[128], bx[128], bx1[128], bx2[128];
+               unsigned char be[128];
+               unsigned mask;
+               uint32_t x1[35], m1[35];
+               uint16_t x2[70], m2[70];
+               uint32_t tmp1[1000];
+               uint16_t tmp2[2000];
+
+               blen = (k + 7) >> 3;
+               br_hmac_drbg_generate(&hc, bm, blen);
+               br_hmac_drbg_generate(&hc, bx, blen);
+               br_hmac_drbg_generate(&hc, be, blen);
+               bm[blen - 1] |= 0x01;
+               mask = 0xFF >> ((int)(blen << 3) - k);
+               bm[0] &= mask;
+               bm[0] |= (mask - (mask >> 1));
+               bx[0] &= (mask >> 1);
+
+               br_i31_decode(m1, bm, blen);
+               br_i31_decode_mod(x1, bx, blen, m1);
+               br_i31_modpow_opt(x1, be, blen, m1, br_i31_ninv31(m1[1]),
+                       tmp1, (sizeof tmp1) / (sizeof tmp1[0]));
+               br_i31_encode(bx1, blen, x1);
+
+               br_i15_decode(m2, bm, blen);
+               br_i15_decode_mod(x2, bx, blen, m2);
+               br_i15_modpow_opt(x2, be, blen, m2, br_i15_ninv15(m2[1]),
+                       tmp2, (sizeof tmp2) / (sizeof tmp2[0]));
+               br_i15_encode(bx2, blen, x2);
+
+               check_equals("ModPow i31/i15", bx1, bx2, blen);
+
+               printf(".");
+               fflush(stdout);
+       }
+
+       printf(" done.\n");
+       fflush(stdout);
+}
+
+static void
+test_modpow_i62(void)
+{
+       br_hmac_drbg_context hc;
+       int k;
+
+       printf("Test ModPow/i62: ");
+
+       br_hmac_drbg_init(&hc, &br_sha256_vtable, "seed modpow", 11);
+       for (k = 10; k <= 500; k ++) {
+               size_t blen;
+               unsigned char bm[128], bx[128], bx1[128], bx2[128];
+               unsigned char be[128];
+               unsigned mask;
+               uint32_t x1[35], m1[35];
+               uint16_t x2[70], m2[70];
+               uint64_t tmp1[500];
+               uint16_t tmp2[2000];
+
+               blen = (k + 7) >> 3;
+               br_hmac_drbg_generate(&hc, bm, blen);
+               br_hmac_drbg_generate(&hc, bx, blen);
+               br_hmac_drbg_generate(&hc, be, blen);
+               bm[blen - 1] |= 0x01;
+               mask = 0xFF >> ((int)(blen << 3) - k);
+               bm[0] &= mask;
+               bm[0] |= (mask - (mask >> 1));
+               bx[0] &= (mask >> 1);
+
+               br_i31_decode(m1, bm, blen);
+               br_i31_decode_mod(x1, bx, blen, m1);
+               br_i62_modpow_opt(x1, be, blen, m1, br_i31_ninv31(m1[1]),
+                       tmp1, (sizeof tmp1) / (sizeof tmp1[0]));
+               br_i31_encode(bx1, blen, x1);
+
+               br_i15_decode(m2, bm, blen);
+               br_i15_decode_mod(x2, bx, blen, m2);
+               br_i15_modpow_opt(x2, be, blen, m2, br_i15_ninv15(m2[1]),
+                       tmp2, (sizeof tmp2) / (sizeof tmp2[0]));
+               br_i15_encode(bx2, blen, x2);
+
+               check_equals("ModPow i62/i15", bx1, bx2, blen);
+
+               printf(".");
+               fflush(stdout);
+       }
+
        printf(" done.\n");
        fflush(stdout);
 }
@@ -5332,18 +5860,36 @@ static const struct {
        STU(AES_small),
        STU(AES_ct),
        STU(AES_ct64),
+       STU(AES_pwr8),
+       STU(AES_x86ni),
        STU(DES_tab),
        STU(DES_ct),
        STU(ChaCha20_ct),
        STU(Poly1305_ctmul),
+       STU(Poly1305_ctmul32),
+       STU(Poly1305_ctmulq),
+       STU(Poly1305_i15),
+       STU(RSA_i15),
        STU(RSA_i31),
        STU(RSA_i32),
+       STU(RSA_i62),
        STU(GHASH_ctmul),
        STU(GHASH_ctmul32),
        STU(GHASH_ctmul64),
+       STU(GHASH_pclmul),
+       STU(GHASH_pwr8),
+       STU(EC_prime_i15),
        STU(EC_prime_i31),
-       /* STU(EC_prime_i32), */
+       STU(EC_p256_m15),
+       STU(EC_p256_m31),
+       STU(EC_c25519_i15),
+       STU(EC_c25519_i31),
+       STU(EC_c25519_m15),
+       STU(EC_c25519_m31),
+       STU(ECDSA_i15),
        STU(ECDSA_i31),
+       STU(modpow_i31),
+       STU(modpow_i62),
        { 0, 0 }
 };