Add some EC base point multiplication test vectors.

Probably worth having actual test vectors for these, rather than
checking our code against itself. Additionally, small negative numbers
have, in the past been valuable test vectors (see long comment in
point_add from OpenSSL's ecp_nistp521.c).

Change-Id: Ia5aa8a80eb5b6d0089c3601c5fec2364e699794d
Reviewed-on: https://boringssl-review.googlesource.com/26848
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
David Benjamin 2018-03-23 16:24:43 -04:00 committed by CQ bot account: commit-bot@chromium.org
parent 718c88c961
commit 50418afb7f
4 changed files with 3274 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
@ -28,6 +29,7 @@
#include <openssl/nid.h>
#include <openssl/obj.h>
#include "../../test/file_test.h"
#include "../../test/test_util.h"
#include "../bn/internal.h"
#include "internal.h"
@ -712,3 +714,113 @@ static std::string CurveToString(
INSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
CurveToString);
static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
std::string curve_name;
if (!t->GetAttribute(&curve_name, key)) {
return nullptr;
}
if (curve_name == "P-224") {
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
}
if (curve_name == "P-256") {
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
NID_X9_62_prime256v1));
}
if (curve_name == "P-384") {
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
}
if (curve_name == "P-521") {
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
}
t->PrintLine("Unknown curve '%s'", curve_name.c_str());
return nullptr;
}
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
std::vector<uint8_t> bytes;
if (!t->GetBytes(&bytes, key)) {
return nullptr;
}
return bssl::UniquePtr<BIGNUM>(
BN_bin2bn(bytes.data(), bytes.size(), nullptr));
}
TEST(ECTest, ScalarBaseMultVectors) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
ASSERT_TRUE(ctx);
FileTestGTest("crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt",
[&](FileTest *t) {
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
bssl::UniquePtr<BIGNUM> n = GetBIGNUM(t, "N");
ASSERT_TRUE(n);
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
bool is_infinity = BN_is_zero(x.get()) && BN_is_zero(y.get());
bssl::UniquePtr<BIGNUM> px(BN_new());
ASSERT_TRUE(px);
bssl::UniquePtr<BIGNUM> py(BN_new());
ASSERT_TRUE(py);
auto check_point = [&](const EC_POINT *p) {
if (is_infinity) {
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), p));
} else {
ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
group.get(), p, px.get(), py.get(), ctx.get()));
EXPECT_EQ(0, BN_cmp(x.get(), px.get()));
EXPECT_EQ(0, BN_cmp(y.get(), py.get()));
}
};
const EC_POINT *g = EC_GROUP_get0_generator(group.get());
bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
ASSERT_TRUE(p);
// Test single-point multiplication.
ASSERT_TRUE(EC_POINT_mul(group.get(), p.get(), n.get(), nullptr, nullptr,
ctx.get()));
check_point(p.get());
ASSERT_TRUE(
EC_POINT_mul(group.get(), p.get(), nullptr, g, n.get(), ctx.get()));
check_point(p.get());
// These tests take a very long time, but are worth running when we make
// non-trivial changes to the EC code.
#if 0
// Test two-point multiplication.
bssl::UniquePtr<BIGNUM> a(BN_new()), b(BN_new());
for (int i = -64; i < 64; i++) {
SCOPED_TRACE(i);
ASSERT_TRUE(BN_set_word(a.get(), abs(i)));
if (i < 0) {
ASSERT_TRUE(BN_sub(a.get(), EC_GROUP_get0_order(group.get()), a.get()));
}
ASSERT_TRUE(BN_copy(b.get(), n.get()));
ASSERT_TRUE(BN_sub(b.get(), b.get(), a.get()));
if (BN_is_negative(b.get())) {
ASSERT_TRUE(BN_add(b.get(), b.get(), EC_GROUP_get0_order(group.get())));
}
ASSERT_TRUE(
EC_POINT_mul(group.get(), p.get(), a.get(), g, b.get(), ctx.get()));
check_point(p.get());
EC_SCALAR a_scalar, b_scalar;
ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &a_scalar, a.get()));
ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &b_scalar, b.get()));
ASSERT_TRUE(ec_point_mul_scalar_public(group.get(), p.get(), &a_scalar, g,
&b_scalar, ctx.get()));
check_point(p.get());
}
#endif
});
}

View File

@ -0,0 +1,60 @@
/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
package main
import (
"crypto/elliptic"
"fmt"
"math/big"
)
const numPoints = 64
func printPadded(key string, n, max *big.Int) {
padded := make([]byte, len(max.Bytes()))
b := n.Bytes()
copy(padded[len(padded)-len(b):], b)
fmt.Printf("%s = %x\n", key, padded)
}
func printMultiples(name string, curve elliptic.Curve) {
n := new(big.Int)
for i := -numPoints; i <= numPoints; i++ {
fmt.Printf("Curve = %s\n", name)
n.SetInt64(int64(i))
if i < 0 {
n = n.Add(n, curve.Params().N)
}
fmt.Printf("# N = %d\n", i)
printPadded("N", n, curve.Params().N)
x, y := curve.ScalarBaseMult(n.Bytes())
printPadded("X", x, curve.Params().P)
printPadded("Y", y, curve.Params().P)
fmt.Printf("\n")
}
}
func main() {
fmt.Printf(`# This file contains multiples of the base point for various curves. The point
# at infinity is represented as X = 0, Y = 0.
#
# This file is generated by make_ec_scalar_base_mult_tests.go
`)
printMultiples("P-224", elliptic.P224())
printMultiples("P-256", elliptic.P256())
printMultiples("P-384", elliptic.P384())
printMultiples("P-521", elliptic.P521())
}

View File

@ -44,6 +44,7 @@ set(
crypto/evp/scrypt_tests.txt
crypto/fipsmodule/aes/aes_tests.txt
crypto/fipsmodule/bn/bn_tests.txt
crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt
crypto/fipsmodule/ec/p256-x86_64_tests.txt
crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt
crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt