Home | History | Annotate | Download | only in ec
      1 /* Copyright (c) 2016, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 #if !defined(__STDC_FORMAT_MACROS)
     16 #define __STDC_FORMAT_MACROS
     17 #endif
     18 
     19 #include <openssl/base.h>
     20 
     21 #include <stdio.h>
     22 #include <string.h>
     23 
     24 #include <openssl/bn.h>
     25 #include <openssl/mem.h>
     26 
     27 #include "../bn/internal.h"
     28 #include "../test/file_test.h"
     29 #include "p256-x86_64.h"
     30 
     31 
     32 // Disable tests if BORINGSSL_SHARED_LIBRARY is defined. These tests need access
     33 // to internal functions.
     34 #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
     35     !defined(OPENSSL_SMALL) && !defined(BORINGSSL_SHARED_LIBRARY)
     36 
     37 static bool TestSelectW5() {
     38   // Fill a table with some garbage input.
     39   P256_POINT table[16];
     40   for (size_t i = 0; i < 16; i++) {
     41     OPENSSL_memset(table[i].X, 3 * i, sizeof(table[i].X));
     42     OPENSSL_memset(table[i].Y, 3 * i + 1, sizeof(table[i].Y));
     43     OPENSSL_memset(table[i].Z, 3 * i + 2, sizeof(table[i].Z));
     44   }
     45 
     46   for (int i = 0; i <= 16; i++) {
     47     P256_POINT val;
     48     ecp_nistz256_select_w5(&val, table, i);
     49 
     50     P256_POINT expected;
     51     if (i == 0) {
     52       OPENSSL_memset(&expected, 0, sizeof(expected));
     53     } else {
     54       expected = table[i-1];
     55     }
     56 
     57     if (OPENSSL_memcmp(&val, &expected, sizeof(P256_POINT)) != 0) {
     58       fprintf(stderr, "ecp_nistz256_select_w5(%d) gave the wrong value.\n", i);
     59       return false;
     60     }
     61   }
     62 
     63   return true;
     64 }
     65 
     66 static bool TestSelectW7() {
     67   // Fill a table with some garbage input.
     68   P256_POINT_AFFINE table[64];
     69   for (size_t i = 0; i < 64; i++) {
     70     OPENSSL_memset(table[i].X, 2 * i, sizeof(table[i].X));
     71     OPENSSL_memset(table[i].Y, 2 * i + 1, sizeof(table[i].Y));
     72   }
     73 
     74   for (int i = 0; i <= 64; i++) {
     75     P256_POINT_AFFINE val;
     76     ecp_nistz256_select_w7(&val, table, i);
     77 
     78     P256_POINT_AFFINE expected;
     79     if (i == 0) {
     80       OPENSSL_memset(&expected, 0, sizeof(expected));
     81     } else {
     82       expected = table[i-1];
     83     }
     84 
     85     if (OPENSSL_memcmp(&val, &expected, sizeof(P256_POINT_AFFINE)) != 0) {
     86       fprintf(stderr, "ecp_nistz256_select_w7(%d) gave the wrong value.\n", i);
     87       return false;
     88     }
     89   }
     90 
     91   return true;
     92 }
     93 
     94 static bool GetFieldElement(FileTest *t, BN_ULONG out[P256_LIMBS],
     95                             const char *name) {
     96   std::vector<uint8_t> bytes;
     97   if (!t->GetBytes(&bytes, name)) {
     98     return false;
     99   }
    100 
    101   if (bytes.size() != BN_BYTES * P256_LIMBS) {
    102     t->PrintLine("Invalid length: %s", name);
    103     return false;
    104   }
    105 
    106   // |byte| contains bytes in big-endian while |out| should contain |BN_ULONG|s
    107   // in little-endian.
    108   OPENSSL_memset(out, 0, P256_LIMBS * sizeof(BN_ULONG));
    109   for (size_t i = 0; i < bytes.size(); i++) {
    110     out[P256_LIMBS - 1 - (i / BN_BYTES)] <<= 8;
    111     out[P256_LIMBS - 1 - (i / BN_BYTES)] |= bytes[i];
    112   }
    113 
    114   return true;
    115 }
    116 
    117 static std::string FieldElementToString(const BN_ULONG a[P256_LIMBS]) {
    118   std::string ret;
    119   for (size_t i = P256_LIMBS-1; i < P256_LIMBS; i--) {
    120     char buf[2 * BN_BYTES + 1];
    121     BIO_snprintf(buf, sizeof(buf), BN_HEX_FMT2, a[i]);
    122     ret += buf;
    123   }
    124   return ret;
    125 }
    126 
    127 static bool ExpectFieldElementsEqual(FileTest *t, const char *message,
    128                                      const BN_ULONG expected[P256_LIMBS],
    129                                      const BN_ULONG actual[P256_LIMBS]) {
    130   if (OPENSSL_memcmp(expected, actual, sizeof(BN_ULONG) * P256_LIMBS) == 0) {
    131     return true;
    132   }
    133 
    134   t->PrintLine("%s", message);
    135   t->PrintLine("Expected: %s", FieldElementToString(expected).c_str());
    136   t->PrintLine("Actual:   %s", FieldElementToString(actual).c_str());
    137   return false;
    138 }
    139 
    140 static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) {
    141   static const uint8_t kP[] = {
    142       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    143       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
    144       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    145   };
    146 
    147   bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), z(BN_new());
    148   bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
    149   if (!x || !y || !z || !p ||
    150       !bn_set_words(x.get(), in->X, P256_LIMBS) ||
    151       !bn_set_words(y.get(), in->Y, P256_LIMBS) ||
    152       !bn_set_words(z.get(), in->Z, P256_LIMBS)) {
    153     return false;
    154   }
    155 
    156   // Coordinates must be fully-reduced.
    157   if (BN_cmp(x.get(), p.get()) >= 0 ||
    158       BN_cmp(y.get(), p.get()) >= 0 ||
    159       BN_cmp(z.get(), p.get()) >= 0) {
    160     return false;
    161   }
    162 
    163   OPENSSL_memset(out, 0, sizeof(P256_POINT_AFFINE));
    164 
    165   if (BN_is_zero(z.get())) {
    166     // The point at infinity is represented as (0, 0).
    167     return true;
    168   }
    169 
    170   bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
    171   bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
    172   if (!ctx || !mont ||
    173       !BN_MONT_CTX_set(mont.get(), p.get(), ctx.get()) ||
    174       // Invert Z.
    175       !BN_from_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
    176       !BN_mod_inverse(z.get(), z.get(), p.get(), ctx.get()) ||
    177       !BN_to_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
    178       // Convert (X, Y, Z) to (X/Z^2, Y/Z^3).
    179       !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
    180                              ctx.get()) ||
    181       !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
    182                              ctx.get()) ||
    183       !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
    184                              ctx.get()) ||
    185       !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
    186                              ctx.get()) ||
    187       !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
    188                              ctx.get())) {
    189     return false;
    190   }
    191 
    192   OPENSSL_memcpy(out->X, x->d, sizeof(BN_ULONG) * x->top);
    193   OPENSSL_memcpy(out->Y, y->d, sizeof(BN_ULONG) * y->top);
    194   return true;
    195 }
    196 
    197 static bool ExpectPointsEqual(FileTest *t, const char *message,
    198                               const P256_POINT_AFFINE *expected,
    199                               const P256_POINT *point) {
    200   // There are multiple representations of the same |P256_POINT|, so convert to
    201   // |P256_POINT_AFFINE| and compare.
    202   P256_POINT_AFFINE affine;
    203   if (!PointToAffine(&affine, point)) {
    204     t->PrintLine("%s", message);
    205     t->PrintLine("Could not convert to affine: (%s, %s, %s)",
    206                  FieldElementToString(point->X).c_str(),
    207                  FieldElementToString(point->Y).c_str(),
    208                  FieldElementToString(point->Z).c_str());
    209     return false;
    210   }
    211 
    212   if (OPENSSL_memcmp(expected, &affine, sizeof(P256_POINT_AFFINE)) != 0) {
    213     t->PrintLine("%s", message);
    214     t->PrintLine("Expected: (%s, %s)",
    215                  FieldElementToString(expected->X).c_str(),
    216                  FieldElementToString(expected->Y).c_str());
    217     t->PrintLine("Actual:   (%s, %s)", FieldElementToString(affine.X).c_str(),
    218                  FieldElementToString(affine.Y).c_str());
    219     return false;
    220   }
    221 
    222   return true;
    223 }
    224 
    225 static bool TestNegate(FileTest *t) {
    226   BN_ULONG a[P256_LIMBS], b[P256_LIMBS];
    227   if (!GetFieldElement(t, a, "A") ||
    228       !GetFieldElement(t, b, "B")) {
    229     return false;
    230   }
    231 
    232   // Test that -A = B.
    233   BN_ULONG ret[P256_LIMBS];
    234   ecp_nistz256_neg(ret, a);
    235   if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(A) was incorrect.", b,
    236                                 ret)) {
    237     return false;
    238   }
    239 
    240   OPENSSL_memcpy(ret, a, sizeof(ret));
    241   ecp_nistz256_neg(ret, ret);
    242   if (!ExpectFieldElementsEqual(
    243           t, "In-place ecp_nistz256_neg(A) was incorrect.", b, ret)) {
    244     return false;
    245   }
    246 
    247   // Test that -B = A.
    248   ecp_nistz256_neg(ret, b);
    249   if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(B) was incorrect.", a,
    250                                 ret)) {
    251     return false;
    252   }
    253 
    254   OPENSSL_memcpy(ret, b, sizeof(ret));
    255   ecp_nistz256_neg(ret, ret);
    256   if (!ExpectFieldElementsEqual(
    257           t, "In-place ecp_nistz256_neg(B) was incorrect.", a, ret)) {
    258     return false;
    259   }
    260 
    261   return true;
    262 }
    263 
    264 static bool TestMulMont(FileTest *t) {
    265   BN_ULONG a[P256_LIMBS], b[P256_LIMBS], result[P256_LIMBS];
    266   if (!GetFieldElement(t, a, "A") ||
    267       !GetFieldElement(t, b, "B") ||
    268       !GetFieldElement(t, result, "Result")) {
    269     return false;
    270   }
    271 
    272   BN_ULONG ret[P256_LIMBS];
    273   ecp_nistz256_mul_mont(ret, a, b);
    274   if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(A, B) was incorrect.",
    275                                 result, ret)) {
    276     return false;
    277   }
    278 
    279   ecp_nistz256_mul_mont(ret, b, a);
    280   if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(B, A) was incorrect.",
    281                                 result, ret)) {
    282     return false;
    283   }
    284 
    285   OPENSSL_memcpy(ret, a, sizeof(ret));
    286   ecp_nistz256_mul_mont(ret, ret, b);
    287   if (!ExpectFieldElementsEqual(
    288           t, "ecp_nistz256_mul_mont(ret = A, B) was incorrect.", result, ret)) {
    289     return false;
    290   }
    291 
    292   OPENSSL_memcpy(ret, a, sizeof(ret));
    293   ecp_nistz256_mul_mont(ret, b, ret);
    294   if (!ExpectFieldElementsEqual(
    295           t, "ecp_nistz256_mul_mont(B, ret = A) was incorrect.", result, ret)) {
    296     return false;
    297   }
    298 
    299   OPENSSL_memcpy(ret, b, sizeof(ret));
    300   ecp_nistz256_mul_mont(ret, a, ret);
    301   if (!ExpectFieldElementsEqual(
    302           t, "ecp_nistz256_mul_mont(A, ret = B) was incorrect.", result, ret)) {
    303     return false;
    304   }
    305 
    306   OPENSSL_memcpy(ret, b, sizeof(ret));
    307   ecp_nistz256_mul_mont(ret, ret, a);
    308   if (!ExpectFieldElementsEqual(
    309           t, "ecp_nistz256_mul_mont(ret = B, A) was incorrect.", result, ret)) {
    310     return false;
    311   }
    312 
    313   if (OPENSSL_memcmp(a, b, sizeof(a)) == 0) {
    314     ecp_nistz256_sqr_mont(ret, a);
    315     if (!ExpectFieldElementsEqual(t, "ecp_nistz256_sqr_mont(A) was incorrect.",
    316                                   result, ret)) {
    317       return false;
    318     }
    319 
    320     OPENSSL_memcpy(ret, a, sizeof(ret));
    321     ecp_nistz256_sqr_mont(ret, ret);
    322     if (!ExpectFieldElementsEqual(
    323             t, "ecp_nistz256_sqr_mont(ret = A) was incorrect.", result, ret)) {
    324       return false;
    325     }
    326   }
    327 
    328   return true;
    329 }
    330 
    331 static bool TestFromMont(FileTest *t) {
    332   BN_ULONG a[P256_LIMBS], result[P256_LIMBS];
    333   if (!GetFieldElement(t, a, "A") ||
    334       !GetFieldElement(t, result, "Result")) {
    335     return false;
    336   }
    337 
    338   BN_ULONG ret[P256_LIMBS];
    339   ecp_nistz256_from_mont(ret, a);
    340   if (!ExpectFieldElementsEqual(t, "ecp_nistz256_from_mont(A) was incorrect.",
    341                                 result, ret)) {
    342     return false;
    343   }
    344 
    345   OPENSSL_memcpy(ret, a, sizeof(ret));
    346   ecp_nistz256_from_mont(ret, ret);
    347   if (!ExpectFieldElementsEqual(
    348           t, "ecp_nistz256_from_mont(ret = A) was incorrect.", result, ret)) {
    349     return false;
    350   }
    351 
    352   return true;
    353 }
    354 
    355 static bool TestPointAdd(FileTest *t) {
    356   P256_POINT a, b;
    357   P256_POINT_AFFINE result;
    358   if (!GetFieldElement(t, a.X, "A.X") ||
    359       !GetFieldElement(t, a.Y, "A.Y") ||
    360       !GetFieldElement(t, a.Z, "A.Z") ||
    361       !GetFieldElement(t, b.X, "B.X") ||
    362       !GetFieldElement(t, b.Y, "B.Y") ||
    363       !GetFieldElement(t, b.Z, "B.Z") ||
    364       !GetFieldElement(t, result.X, "Result.X") ||
    365       !GetFieldElement(t, result.Y, "Result.Y")) {
    366     return false;
    367   }
    368 
    369   P256_POINT ret;
    370   ecp_nistz256_point_add(&ret, &a, &b);
    371   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(A, B) was incorrect.",
    372                          &result, &ret)) {
    373     return false;
    374   }
    375 
    376   ecp_nistz256_point_add(&ret, &b, &a);
    377   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, A) was incorrect.",
    378                          &result, &ret)) {
    379     return false;
    380   }
    381 
    382   OPENSSL_memcpy(&ret, &a, sizeof(ret));
    383   ecp_nistz256_point_add(&ret, &ret, &b);
    384   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
    385                          &result, &ret)) {
    386     return false;
    387   }
    388 
    389   OPENSSL_memcpy(&ret, &a, sizeof(ret));
    390   ecp_nistz256_point_add(&ret, &b, &ret);
    391   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, ret = A) was incorrect.",
    392                          &result, &ret)) {
    393     return false;
    394   }
    395 
    396   OPENSSL_memcpy(&ret, &b, sizeof(ret));
    397   ecp_nistz256_point_add(&ret, &a, &ret);
    398   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
    399                          &result, &ret)) {
    400     return false;
    401   }
    402 
    403   OPENSSL_memcpy(&ret, &b, sizeof(ret));
    404   ecp_nistz256_point_add(&ret, &ret, &a);
    405   if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = B, A) was incorrect.",
    406                          &result, &ret)) {
    407     return false;
    408   }
    409 
    410   P256_POINT_AFFINE a_affine, b_affine, infinity;
    411   OPENSSL_memset(&infinity, 0, sizeof(infinity));
    412   if (!PointToAffine(&a_affine, &a) ||
    413       !PointToAffine(&b_affine, &b)) {
    414     return false;
    415   }
    416 
    417   // ecp_nistz256_point_add_affine does not work when a == b unless doubling the
    418   // point at infinity.
    419   if (OPENSSL_memcmp(&a_affine, &b_affine, sizeof(a_affine)) != 0 ||
    420       OPENSSL_memcmp(&a_affine, &infinity, sizeof(a_affine)) == 0) {
    421     ecp_nistz256_point_add_affine(&ret, &a, &b_affine);
    422     if (!ExpectPointsEqual(t,
    423                            "ecp_nistz256_point_add_affine(A, B) was incorrect.",
    424                            &result, &ret)) {
    425       return false;
    426     }
    427 
    428     OPENSSL_memcpy(&ret, &a, sizeof(ret));
    429     ecp_nistz256_point_add_affine(&ret, &ret, &b_affine);
    430     if (!ExpectPointsEqual(
    431             t, "ecp_nistz256_point_add_affine(ret = A, B) was incorrect.",
    432             &result, &ret)) {
    433       return false;
    434     }
    435 
    436     ecp_nistz256_point_add_affine(&ret, &b, &a_affine);
    437     if (!ExpectPointsEqual(t,
    438                            "ecp_nistz256_point_add_affine(B, A) was incorrect.",
    439                            &result, &ret)) {
    440       return false;
    441     }
    442 
    443     OPENSSL_memcpy(&ret, &b, sizeof(ret));
    444     ecp_nistz256_point_add_affine(&ret, &ret, &a_affine);
    445     if (!ExpectPointsEqual(
    446             t, "ecp_nistz256_point_add_affine(ret = B, A) was incorrect.",
    447             &result, &ret)) {
    448       return false;
    449     }
    450   }
    451 
    452   if (OPENSSL_memcmp(&a, &b, sizeof(a)) == 0) {
    453     ecp_nistz256_point_double(&ret, &a);
    454     if (!ExpectPointsEqual(t, "ecp_nistz256_point_double(A) was incorrect.",
    455                            &result, &ret)) {
    456       return false;
    457     }
    458 
    459     ret = a;
    460     ecp_nistz256_point_double(&ret, &ret);
    461     if (!ExpectPointsEqual(
    462             t, "In-place ecp_nistz256_point_double(A) was incorrect.", &result,
    463             &ret)) {
    464       return false;
    465     }
    466   }
    467 
    468   return true;
    469 }
    470 
    471 int main(int argc, char **argv) {
    472   if (argc != 2) {
    473     fprintf(stderr, "%s TEST_FILE\n", argv[0]);
    474     return 1;
    475   }
    476 
    477   if (!TestSelectW5() ||
    478       !TestSelectW7()) {
    479     return 1;
    480   }
    481 
    482   return FileTestMain([](FileTest *t, void *) -> bool {
    483     if (t->GetParameter() == "Negate") {
    484       return TestNegate(t);
    485     }
    486     if (t->GetParameter() == "MulMont") {
    487       return TestMulMont(t);
    488     }
    489     if (t->GetParameter() == "FromMont") {
    490       return TestFromMont(t);
    491     }
    492     if (t->GetParameter() == "PointAdd") {
    493       return TestPointAdd(t);
    494     }
    495 
    496     t->PrintLine("Unknown test type: %s", t->GetParameter().c_str());
    497     return false;
    498   }, nullptr, argv[1]);
    499 }
    500 
    501 #else
    502 
    503 int main() {
    504   printf("PASS\n");
    505   return 0;
    506 }
    507 
    508 #endif
    509