p256-x86_64_test.cc revision 8ff035535f7cf2903f02bbe94d2fa10b7ab855f1
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 <gtest/gtest.h> 25 26#include <openssl/bn.h> 27#include <openssl/mem.h> 28 29#include "../bn/internal.h" 30#include "../../test/file_test.h" 31#include "../../test/test_util.h" 32#include "p256-x86_64.h" 33 34 35// Disable tests if BORINGSSL_SHARED_LIBRARY is defined. These tests need access 36// to internal functions. 37#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \ 38 !defined(OPENSSL_SMALL) && !defined(BORINGSSL_SHARED_LIBRARY) 39 40TEST(P256_X86_64Test, SelectW5) { 41 // Fill a table with some garbage input. 42 P256_POINT table[16]; 43 for (size_t i = 0; i < 16; i++) { 44 OPENSSL_memset(table[i].X, 3 * i, sizeof(table[i].X)); 45 OPENSSL_memset(table[i].Y, 3 * i + 1, sizeof(table[i].Y)); 46 OPENSSL_memset(table[i].Z, 3 * i + 2, sizeof(table[i].Z)); 47 } 48 49 for (int i = 0; i <= 16; i++) { 50 P256_POINT val; 51 ecp_nistz256_select_w5(&val, table, i); 52 53 P256_POINT expected; 54 if (i == 0) { 55 OPENSSL_memset(&expected, 0, sizeof(expected)); 56 } else { 57 expected = table[i-1]; 58 } 59 60 EXPECT_EQ(Bytes(reinterpret_cast<const char *>(&expected), sizeof(expected)), 61 Bytes(reinterpret_cast<const char *>(&val), sizeof(val))); 62 } 63} 64 65TEST(P256_X86_64Test, SelectW7) { 66 // Fill a table with some garbage input. 67 P256_POINT_AFFINE table[64]; 68 for (size_t i = 0; i < 64; i++) { 69 OPENSSL_memset(table[i].X, 2 * i, sizeof(table[i].X)); 70 OPENSSL_memset(table[i].Y, 2 * i + 1, sizeof(table[i].Y)); 71 } 72 73 for (int i = 0; i <= 64; i++) { 74 P256_POINT_AFFINE val; 75 ecp_nistz256_select_w7(&val, table, i); 76 77 P256_POINT_AFFINE expected; 78 if (i == 0) { 79 OPENSSL_memset(&expected, 0, sizeof(expected)); 80 } else { 81 expected = table[i-1]; 82 } 83 84 EXPECT_EQ(Bytes(reinterpret_cast<const char *>(&expected), sizeof(expected)), 85 Bytes(reinterpret_cast<const char *>(&val), sizeof(val))); 86 } 87} 88 89static bool GetFieldElement(FileTest *t, BN_ULONG out[P256_LIMBS], 90 const char *name) { 91 std::vector<uint8_t> bytes; 92 if (!t->GetBytes(&bytes, name)) { 93 return false; 94 } 95 96 if (bytes.size() != BN_BYTES * P256_LIMBS) { 97 ADD_FAILURE() << "Invalid length: " << name; 98 return false; 99 } 100 101 // |byte| contains bytes in big-endian while |out| should contain |BN_ULONG|s 102 // in little-endian. 103 OPENSSL_memset(out, 0, P256_LIMBS * sizeof(BN_ULONG)); 104 for (size_t i = 0; i < bytes.size(); i++) { 105 out[P256_LIMBS - 1 - (i / BN_BYTES)] <<= 8; 106 out[P256_LIMBS - 1 - (i / BN_BYTES)] |= bytes[i]; 107 } 108 109 return true; 110} 111 112static std::string FieldElementToString(const BN_ULONG a[P256_LIMBS]) { 113 std::string ret; 114 for (size_t i = P256_LIMBS-1; i < P256_LIMBS; i--) { 115 char buf[2 * BN_BYTES + 1]; 116 BIO_snprintf(buf, sizeof(buf), BN_HEX_FMT2, a[i]); 117 ret += buf; 118 } 119 return ret; 120} 121 122static testing::AssertionResult ExpectFieldElementsEqual( 123 const char *expected_expr, const char *actual_expr, 124 const BN_ULONG expected[P256_LIMBS], const BN_ULONG actual[P256_LIMBS]) { 125 if (OPENSSL_memcmp(expected, actual, sizeof(BN_ULONG) * P256_LIMBS) == 0) { 126 return testing::AssertionSuccess(); 127 } 128 129 return testing::AssertionFailure() 130 << "Expected: " << FieldElementToString(expected) << " (" 131 << expected_expr << ")\n" 132 << "Actual: " << FieldElementToString(actual) << " (" << actual_expr 133 << ")"; 134} 135 136#define EXPECT_FIELD_ELEMENTS_EQUAL(a, b) \ 137 EXPECT_PRED_FORMAT2(ExpectFieldElementsEqual, a, b) 138 139static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) { 140 static const uint8_t kP[] = { 141 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 144 }; 145 146 bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), z(BN_new()); 147 bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr)); 148 if (!x || !y || !z || !p || 149 !bn_set_words(x.get(), in->X, P256_LIMBS) || 150 !bn_set_words(y.get(), in->Y, P256_LIMBS) || 151 !bn_set_words(z.get(), in->Z, P256_LIMBS)) { 152 return false; 153 } 154 155 // Coordinates must be fully-reduced. 156 if (BN_cmp(x.get(), p.get()) >= 0 || 157 BN_cmp(y.get(), p.get()) >= 0 || 158 BN_cmp(z.get(), p.get()) >= 0) { 159 return false; 160 } 161 162 OPENSSL_memset(out, 0, sizeof(P256_POINT_AFFINE)); 163 164 if (BN_is_zero(z.get())) { 165 // The point at infinity is represented as (0, 0). 166 return true; 167 } 168 169 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new()); 170 bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new()); 171 if (!ctx || !mont || 172 !BN_MONT_CTX_set(mont.get(), p.get(), ctx.get()) || 173 // Invert Z. 174 !BN_from_montgomery(z.get(), z.get(), mont.get(), ctx.get()) || 175 !BN_mod_inverse(z.get(), z.get(), p.get(), ctx.get()) || 176 !BN_to_montgomery(z.get(), z.get(), mont.get(), ctx.get()) || 177 // Convert (X, Y, Z) to (X/Z^2, Y/Z^3). 178 !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(), 179 ctx.get()) || 180 !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(), 181 ctx.get()) || 182 !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(), 183 ctx.get()) || 184 !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(), 185 ctx.get()) || 186 !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(), 187 ctx.get())) { 188 return false; 189 } 190 191 OPENSSL_memcpy(out->X, x->d, sizeof(BN_ULONG) * x->top); 192 OPENSSL_memcpy(out->Y, y->d, sizeof(BN_ULONG) * y->top); 193 return true; 194} 195 196static testing::AssertionResult ExpectPointsEqual( 197 const char *expected_expr, const char *actual_expr, 198 const P256_POINT_AFFINE *expected, const P256_POINT *actual) { 199 // There are multiple representations of the same |P256_POINT|, so convert to 200 // |P256_POINT_AFFINE| and compare. 201 P256_POINT_AFFINE affine; 202 if (!PointToAffine(&affine, actual)) { 203 return testing::AssertionFailure() 204 << "Could not convert " << actual_expr << " to affine: (" 205 << FieldElementToString(actual->X) << ", " 206 << FieldElementToString(actual->Y) << ", " 207 << FieldElementToString(actual->Z) << ")"; 208 } 209 210 if (OPENSSL_memcmp(expected, &affine, sizeof(P256_POINT_AFFINE)) != 0) { 211 return testing::AssertionFailure() 212 << "Expected: (" << FieldElementToString(expected->X) << ", " 213 << FieldElementToString(expected->Y) << ") (" << expected_expr 214 << "; affine)\n" 215 << "Actual: (" << FieldElementToString(affine.X) << ", " 216 << FieldElementToString(affine.Y) << ") (" << actual_expr << ")"; 217 } 218 219 return testing::AssertionSuccess(); 220} 221 222#define EXPECT_POINTS_EQUAL(a, b) EXPECT_PRED_FORMAT2(ExpectPointsEqual, a, b) 223 224static void TestNegate(FileTest *t) { 225 BN_ULONG a[P256_LIMBS], b[P256_LIMBS]; 226 ASSERT_TRUE(GetFieldElement(t, a, "A")); 227 ASSERT_TRUE(GetFieldElement(t, b, "B")); 228 229 // Test that -A = B. 230 BN_ULONG ret[P256_LIMBS]; 231 ecp_nistz256_neg(ret, a); 232 EXPECT_FIELD_ELEMENTS_EQUAL(b, ret); 233 234 OPENSSL_memcpy(ret, a, sizeof(ret)); 235 ecp_nistz256_neg(ret, ret /* a */); 236 EXPECT_FIELD_ELEMENTS_EQUAL(b, ret); 237 238 // Test that -B = A. 239 ecp_nistz256_neg(ret, b); 240 EXPECT_FIELD_ELEMENTS_EQUAL(a, ret); 241 242 OPENSSL_memcpy(ret, b, sizeof(ret)); 243 ecp_nistz256_neg(ret, ret /* b */); 244 EXPECT_FIELD_ELEMENTS_EQUAL(a, ret); 245} 246 247static void TestMulMont(FileTest *t) { 248 BN_ULONG a[P256_LIMBS], b[P256_LIMBS], result[P256_LIMBS]; 249 ASSERT_TRUE(GetFieldElement(t, a, "A")); 250 ASSERT_TRUE(GetFieldElement(t, b, "B")); 251 ASSERT_TRUE(GetFieldElement(t, result, "Result")); 252 253 BN_ULONG ret[P256_LIMBS]; 254 ecp_nistz256_mul_mont(ret, a, b); 255 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 256 257 ecp_nistz256_mul_mont(ret, b, a); 258 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 259 260 OPENSSL_memcpy(ret, a, sizeof(ret)); 261 ecp_nistz256_mul_mont(ret, ret /* a */, b); 262 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 263 264 OPENSSL_memcpy(ret, a, sizeof(ret)); 265 ecp_nistz256_mul_mont(ret, b, ret); 266 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 267 268 OPENSSL_memcpy(ret, b, sizeof(ret)); 269 ecp_nistz256_mul_mont(ret, a, ret /* b */); 270 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 271 272 OPENSSL_memcpy(ret, b, sizeof(ret)); 273 ecp_nistz256_mul_mont(ret, ret /* b */, a); 274 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 275 276 if (OPENSSL_memcmp(a, b, sizeof(a)) == 0) { 277 ecp_nistz256_sqr_mont(ret, a); 278 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 279 280 OPENSSL_memcpy(ret, a, sizeof(ret)); 281 ecp_nistz256_sqr_mont(ret, ret /* a */); 282 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 283 } 284} 285 286static void TestFromMont(FileTest *t) { 287 BN_ULONG a[P256_LIMBS], result[P256_LIMBS]; 288 ASSERT_TRUE(GetFieldElement(t, a, "A")); 289 ASSERT_TRUE(GetFieldElement(t, result, "Result")); 290 291 BN_ULONG ret[P256_LIMBS]; 292 ecp_nistz256_from_mont(ret, a); 293 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 294 295 OPENSSL_memcpy(ret, a, sizeof(ret)); 296 ecp_nistz256_from_mont(ret, ret /* a */); 297 EXPECT_FIELD_ELEMENTS_EQUAL(result, ret); 298} 299 300static void TestPointAdd(FileTest *t) { 301 P256_POINT a, b; 302 P256_POINT_AFFINE result; 303 ASSERT_TRUE(GetFieldElement(t, a.X, "A.X")); 304 ASSERT_TRUE(GetFieldElement(t, a.Y, "A.Y")); 305 ASSERT_TRUE(GetFieldElement(t, a.Z, "A.Z")); 306 ASSERT_TRUE(GetFieldElement(t, b.X, "B.X")); 307 ASSERT_TRUE(GetFieldElement(t, b.Y, "B.Y")); 308 ASSERT_TRUE(GetFieldElement(t, b.Z, "B.Z")); 309 ASSERT_TRUE(GetFieldElement(t, result.X, "Result.X")); 310 ASSERT_TRUE(GetFieldElement(t, result.Y, "Result.Y")); 311 312 P256_POINT ret; 313 ecp_nistz256_point_add(&ret, &a, &b); 314 EXPECT_POINTS_EQUAL(&result, &ret); 315 316 ecp_nistz256_point_add(&ret, &b, &a); 317 EXPECT_POINTS_EQUAL(&result, &ret); 318 319 OPENSSL_memcpy(&ret, &a, sizeof(ret)); 320 ecp_nistz256_point_add(&ret, &ret /* a */, &b); 321 EXPECT_POINTS_EQUAL(&result, &ret); 322 323 OPENSSL_memcpy(&ret, &a, sizeof(ret)); 324 ecp_nistz256_point_add(&ret, &b, &ret /* a */); 325 EXPECT_POINTS_EQUAL(&result, &ret); 326 327 OPENSSL_memcpy(&ret, &b, sizeof(ret)); 328 ecp_nistz256_point_add(&ret, &a, &ret /* b */); 329 EXPECT_POINTS_EQUAL(&result, &ret); 330 331 OPENSSL_memcpy(&ret, &b, sizeof(ret)); 332 ecp_nistz256_point_add(&ret, &ret /* b */, &a); 333 EXPECT_POINTS_EQUAL(&result, &ret); 334 335 P256_POINT_AFFINE a_affine, b_affine, infinity; 336 OPENSSL_memset(&infinity, 0, sizeof(infinity)); 337 ASSERT_TRUE(PointToAffine(&a_affine, &a)); 338 ASSERT_TRUE(PointToAffine(&b_affine, &b)); 339 340 // ecp_nistz256_point_add_affine does not work when a == b unless doubling the 341 // point at infinity. 342 if (OPENSSL_memcmp(&a_affine, &b_affine, sizeof(a_affine)) != 0 || 343 OPENSSL_memcmp(&a_affine, &infinity, sizeof(a_affine)) == 0) { 344 ecp_nistz256_point_add_affine(&ret, &a, &b_affine); 345 EXPECT_POINTS_EQUAL(&result, &ret); 346 347 OPENSSL_memcpy(&ret, &a, sizeof(ret)); 348 ecp_nistz256_point_add_affine(&ret, &ret /* a */, &b_affine); 349 EXPECT_POINTS_EQUAL(&result, &ret); 350 351 ecp_nistz256_point_add_affine(&ret, &b, &a_affine); 352 EXPECT_POINTS_EQUAL(&result, &ret); 353 354 OPENSSL_memcpy(&ret, &b, sizeof(ret)); 355 ecp_nistz256_point_add_affine(&ret, &ret /* b */, &a_affine); 356 EXPECT_POINTS_EQUAL(&result, &ret); 357 } 358 359 if (OPENSSL_memcmp(&a, &b, sizeof(a)) == 0) { 360 ecp_nistz256_point_double(&ret, &a); 361 EXPECT_POINTS_EQUAL(&result, &ret); 362 363 ret = a; 364 ecp_nistz256_point_double(&ret, &ret /* a */); 365 EXPECT_POINTS_EQUAL(&result, &ret); 366 } 367} 368 369TEST(P256_X86_64Test, TestVectors) { 370 return FileTestGTest("crypto/fipsmodule/ec/p256-x86_64_tests.txt", 371 [](FileTest *t) { 372 if (t->GetParameter() == "Negate") { 373 TestNegate(t); 374 } else if (t->GetParameter() == "MulMont") { 375 TestMulMont(t); 376 } else if (t->GetParameter() == "FromMont") { 377 TestFromMont(t); 378 } else if (t->GetParameter() == "PointAdd") { 379 TestPointAdd(t); 380 } else { 381 FAIL() << "Unknown test type:" << t->GetParameter(); 382 } 383 }); 384} 385 386#endif 387