New "i62" code for big integers with 64x64->128 opcodes; also improved "i31" modular...
[BearSSL] / test / test_crypto.c
index 69b6f7d..47c6bf6 100644 (file)
@@ -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;
@@ -3157,7 +3157,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 +3270,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).
@@ -4137,24 +4190,12 @@ test_Poly1305_inner(const char *name, br_poly1305_run ipoly,
                memcpy(data, plain, 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);
-               }
+               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");
-                       exit(EXIT_FAILURE);
-               }
-               if (memcmp(tmp, tag, 16) != 0) {
-                       fprintf(stderr, "ChaCha20+Poly1305 KAT failed (4)\n");
-                       exit(EXIT_FAILURE);
-               }
+               check_equals("ChaCha20+Poly1305 KAT (3)", data, plain, len);
+               check_equals("ChaCha20+Poly1305 KAT (4)", tmp, tag, 16);
 
                printf(".");
                fflush(stdout);
@@ -4220,6 +4261,20 @@ test_Poly1305_i15(void)
                &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.
  */
@@ -4449,6 +4504,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)
@@ -4649,6 +4732,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);
 }
@@ -4671,6 +4779,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)
@@ -4912,12 +5046,123 @@ test_EC_prime_i31(void)
 }
 
 static void
-test_EC_p256_i15(void)
+test_EC_p256_m15(void)
 {
-       test_EC_KAT("EC_p256_i15", &br_ec_p256_i15,
+       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,
@@ -5388,6 +5633,108 @@ test_ECDSA_i15(void)
        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);
+}
+
 static int
 eq_name(const char *s1, const char *s2)
 {
@@ -5448,24 +5795,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_p256_i15),
-       /* 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 }
 };