summaryrefslogtreecommitdiff
path: root/src/crypto/fipsmodule/ecdsa
diff options
context:
space:
mode:
authorRobert Sloan <varomodt@google.com>2018-11-12 13:38:50 -0800
committerRobert Sloan <varomodt@google.com>2018-11-12 13:51:26 -0800
commita51059f202525842fc0d628a408ad5a5e33a54e7 (patch)
tree5b28ee9547e63d78299aaedf791cc293a8518f07 /src/crypto/fipsmodule/ecdsa
parentcbf5ea62f9677735fb503a0a23ab3ee8c15ef40e (diff)
downloadboringssl-a51059f202525842fc0d628a408ad5a5e33a54e7.tar.gz
This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/7f7e5e231efec6e86d6c7d3fd1b759be1cece156..fa3aadcd40ec4fd27a6e9492ef099b3dcc6eb2af Test: BoringSSL CTS Presubmits. Change-Id: I5381241ee7b94e1076d04090a0bc468b7816a1a1
Diffstat (limited to 'src/crypto/fipsmodule/ecdsa')
-rw-r--r--src/crypto/fipsmodule/ecdsa/ecdsa.c61
-rw-r--r--src/crypto/fipsmodule/ecdsa/ecdsa_test.cc51
-rw-r--r--src/crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt343
3 files changed, 399 insertions, 56 deletions
diff --git a/src/crypto/fipsmodule/ecdsa/ecdsa.c b/src/crypto/fipsmodule/ecdsa/ecdsa.c
index f3ce2147..80371c3e 100644
--- a/src/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/src/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -98,40 +98,6 @@ static void digest_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
order->width);
}
-// field_element_to_scalar reduces |r| modulo |group->order|. |r| must
-// previously have been reduced modulo |group->field|.
-static int field_element_to_scalar(const EC_GROUP *group, BIGNUM *r) {
- // We must have p < 2×order, assuming p is not tiny (p >= 17). Thus rather we
- // can reduce by performing at most one subtraction.
- //
- // Proof: We only work with prime order curves, so the number of points on
- // the curve is the order. Thus Hasse's theorem gives:
- //
- // |order - (p + 1)| <= 2×sqrt(p)
- // p + 1 - order <= 2×sqrt(p)
- // p + 1 - 2×sqrt(p) <= order
- // p + 1 - 2×(p/4) < order (p/4 > sqrt(p) for p >= 17)
- // p/2 < p/2 + 1 < order
- // p < 2×order
- //
- // Additionally, one can manually check this property for built-in curves. It
- // is enforced for legacy custom curves in |EC_GROUP_set_generator|.
- //
- // TODO(davidben): Introduce |EC_FIELD_ELEMENT|, make this a function from
- // |EC_FIELD_ELEMENT| to |EC_SCALAR|, and cut out the |BIGNUM|. Does this need
- // to be constant-time for signing? |r| is the x-coordinate for kG, which is
- // public unless k was rerolled because |s| was zero.
- assert(!BN_is_negative(r));
- assert(BN_cmp(r, &group->field) < 0);
- if (BN_cmp(r, &group->order) >= 0 &&
- !BN_sub(r, r, &group->order)) {
- return 0;
- }
- assert(!BN_is_negative(r));
- assert(BN_cmp(r, &group->order) < 0);
- return 1;
-}
-
ECDSA_SIG *ECDSA_SIG_new(void) {
ECDSA_SIG *sig = OPENSSL_malloc(sizeof(ECDSA_SIG));
if (sig == NULL) {
@@ -193,12 +159,6 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
}
int ret = 0;
EC_POINT *point = NULL;
- BN_CTX_start(ctx);
- BIGNUM *X = BN_CTX_get(ctx);
- if (X == NULL) {
- OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
- goto err;
- }
EC_SCALAR r, s, u1, u2, s_inv_mont, m;
if (BN_is_zero(sig->r) ||
@@ -210,11 +170,7 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
}
// s_inv_mont = s^-1 in the Montgomery domain. This is
- // |ec_scalar_to_montgomery| followed by |ec_scalar_inv_montgomery|, but
- // |ec_scalar_inv_montgomery| followed by |ec_scalar_from_montgomery| is
- // equivalent and slightly more efficient.
- ec_scalar_inv_montgomery(group, &s_inv_mont, &s);
- ec_scalar_from_montgomery(group, &s_inv_mont, &s_inv_mont);
+ ec_scalar_inv_montgomery_vartime(group, &s_inv_mont, &s);
// u1 = m * s^-1 mod order
// u2 = r * s^-1 mod order
@@ -234,16 +190,14 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
- if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) {
+
+ int match;
+ if (!ec_cmp_x_coordinate(&match, group, point, sig->r, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
- if (!field_element_to_scalar(group, X)) {
- OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
- goto err;
- }
- // The signature is correct iff |X| is equal to |sig->r|.
- if (BN_ucmp(X, sig->r) != 0) {
+
+ if (!match) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
goto err;
}
@@ -251,7 +205,6 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
ret = 1;
err:
- BN_CTX_end(ctx);
BN_CTX_free(ctx);
EC_POINT_free(point);
return ret;
@@ -320,7 +273,7 @@ static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
goto err;
}
- if (!field_element_to_scalar(group, r)) {
+ if (!ec_field_element_to_scalar(group, r)) {
goto err;
}
} while (BN_is_zero(r));
diff --git a/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc b/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
index 258c128c..4c95df9e 100644
--- a/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
+++ b/src/crypto/fipsmodule/ecdsa/ecdsa_test.cc
@@ -68,6 +68,45 @@
#include "../../test/file_test.h"
+static bssl::UniquePtr<BIGNUM> HexToBIGNUM(const char *hex) {
+ BIGNUM *bn = nullptr;
+ BN_hex2bn(&bn, hex);
+ return bssl::UniquePtr<BIGNUM>(bn);
+}
+
+// Though we do not support secp160r1, it is reachable from the deprecated
+// custom curve APIs and has some unique properties (n is larger than p with the
+// difference crossing a word boundary on 32-bit), so test it explicitly.
+static bssl::UniquePtr<EC_GROUP> NewSecp160r1Group() {
+ static const char kP[] = "ffffffffffffffffffffffffffffffff7fffffff";
+ static const char kA[] = "ffffffffffffffffffffffffffffffff7ffffffc";
+ static const char kB[] = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ static const char kX[] = "4a96b5688ef573284664698968c38bb913cbfc82";
+ static const char kY[] = "23a628553168947d59dcc912042351377ac5fb32";
+ static const char kN[] = "0100000000000000000001f4c8f927aed3ca752257";
+
+ bssl::UniquePtr<BIGNUM> p = HexToBIGNUM(kP), a = HexToBIGNUM(kA),
+ b = HexToBIGNUM(kB), x = HexToBIGNUM(kX),
+ y = HexToBIGNUM(kY), n = HexToBIGNUM(kN);
+ if (!p || !a || !b || !x || !y || !n) {
+ return nullptr;
+ }
+
+ bssl::UniquePtr<EC_GROUP> group(
+ EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), nullptr));
+ if (!group) {
+ return nullptr;
+ }
+ bssl::UniquePtr<EC_POINT> g(EC_POINT_new(group.get()));
+ if (!g ||
+ !EC_POINT_set_affine_coordinates_GFp(group.get(), g.get(), x.get(),
+ y.get(), nullptr) ||
+ !EC_GROUP_set_generator(group.get(), g.get(), n.get(), BN_value_one())) {
+ return nullptr;
+ }
+ return group;
+}
+
enum API {
kEncodedAPI,
kRawAPI,
@@ -151,13 +190,18 @@ TEST(ECDSATest, BuiltinCurves) {
{ NID_X9_62_prime256v1, "secp256r1" },
{ NID_secp384r1, "secp384r1" },
{ NID_secp521r1, "secp521r1" },
+ { NID_secp160r1, "secp160r1" },
};
for (const auto &curve : kCurves) {
SCOPED_TRACE(curve.name);
- int nid = curve.nid;
- bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid));
+ bssl::UniquePtr<EC_GROUP> group;
+ if (curve.nid == NID_secp160r1) {
+ group = NewSecp160r1Group();
+ } else {
+ group.reset(EC_GROUP_new_by_curve_name(curve.nid));
+ }
ASSERT_TRUE(group);
const BIGNUM *order = EC_GROUP_get0_order(group.get());
@@ -278,6 +322,9 @@ static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
if (curve_name == "P-521") {
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
}
+ if (curve_name == "secp160r1") {
+ return NewSecp160r1Group();
+ }
ADD_FAILURE() << "Unknown curve: " << curve_name;
return nullptr;
diff --git a/src/crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt b/src/crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt
index aa2fbd3c..03975c8c 100644
--- a/src/crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt
+++ b/src/crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt
@@ -2431,3 +2431,346 @@ Y = 01862ed4f9d235afcc4e6b45e491da363104d4db7b97f12d869c40ab09a3c8c72519a9712ca7
Digest = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
R = 00ec0b91fa4386a8acdc0e46dd9c1d1775abbe0da8ead424aa4ace58e284a5be00e2c1ef95b6f4d861615564e1e7305656567f95275ce63b534420eae77ec37492c2
S = 01e1099fb389db498ab4cf23b4f06a74b9326878ae3c76ea13832e50702b30fe8303093a59cc9a0995f1dfc15e6f7dabca8a2acaf03ec005447d29fb429a252064ec
+
+
+# The following tests are intended to stress the final comparison in ECDSA.
+# ECDSA verification computes some curve point (x, y), picking the fully-reduced
+# representive of x mod p, and checking that x mod n is r. (n is the order of
+# the group and p defines the underlying prime field.)
+#
+# This makes the computation sensitive to values near n and p, and which of n or
+# p is larger. Additionally, there is an optimization that performs the
+# comparison mod p rather than n and compensates for the difference.
+#
+# These tests were generated by picking a target value of r and x, adjusting
+# both until x corresponded to a point on the curve, and then computing the
+# public key by solving for P in ECDSA's (x, y) = u1*G + u2*P. The digest is the
+# hash of "hello, world" with the suitably-sized SHA-2 hash, so the test vectors
+# are suitable for both message- and digest-based APIs.
+#
+# "x" in the comments refer to the x-coordinate of the computed point, not that
+# of the public key.
+
+# r = 3, x = 3 is valid.
+Curve = P-224
+X = f43eeb550591547d6a6479726b72be181d4ea26dea5516ae1c0b0ab3
+Y = e127deeb94536c67793ac172ba31f3a6f81efbbf2ab3d7868d0cc9f9
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00000000000000000000000000000000000000000000000000000003
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+
+# r = 3 + n, x = 3 is invalid. r must already be reduced.
+Curve = P-224
+X = f43eeb550591547d6a6479726b72be181d4ea26dea5516ae1c0b0ab3
+Y = e127deeb94536c67793ac172ba31f3a6f81efbbf2ab3d7868d0cc9f9
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a40
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+Invalid =
+
+# r = n-1, x = n-1 is the largest x without a reduction.
+Curve = P-224
+X = 32acb8d348f6ec350822227c4a90048733640317f7833dc9093a78f1
+Y = dd45cab24ef90b8d6437f128437ea847036a8912322a6738dccceaa3
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3c
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+
+# r = n-2, x = n-1 is incorrect.
+Curve = P-224
+X = 32acb8d348f6ec350822227c4a90048733640317f7833dc9093a78f1
+Y = dd45cab24ef90b8d6437f128437ea847036a8912322a6738dccceaa3
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3b
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+Invalid =
+
+# r = 3, x = n+3 is the smallest x with a reduction.
+Curve = P-224
+X = d7afcc97eefcf32becf100cf967588c68f9c149fa18344ac08e245b4
+Y = 3b853f6c6d955587d9ac080c8f10bf355f9992a0103a27aa30dac7e8
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00000000000000000000000000000000000000000000000000000003
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+
+# r = 4, x = n+3 is incorrect.
+Curve = P-224
+X = d7afcc97eefcf32becf100cf967588c68f9c149fa18344ac08e245b4
+Y = 3b853f6c6d955587d9ac080c8f10bf355f9992a0103a27aa30dac7e8
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00000000000000000000000000000000000000000000000000000004
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+Invalid =
+
+# r = p-3-n, x = p-3 is the largest valid x.
+Curve = P-224
+X = cdacee2255448c72d1558eb866b14831acef41ed348bd938cce655be
+Y = d0b409693b64f3597468ae5535338052436158a6771c6318b68025de
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0000000000000000000000000000e95c1f470fc1ec22d6baa3a3d5c1
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+
+# r = p-n+3, x = 3 is incorrect. r is too large to compare r+n with x.
+Curve = P-224
+X = ef9169ef146a19c9a7220c6f25f597e7345e25fa1267712b9a20e30d
+Y = 454b19373a67ad81ca37ba8de9a96e881896df7160ba740f4c7373b9
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0000000000000000000000000000e95c1f470fc1ec22d6baa3a3d5c7
+S = ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a
+Invalid =
+
+# r = 5, x = 5 is valid.
+Curve = P-256
+X = 264d796a0dab9b376d34eea6fe297dde1c7b73e53944bc96c8f1e8a6850bb6c9
+Y = cf5308020eed460c649ddae61d4ef8bb79958113f106befaf4f18876d12a5e64
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0000000000000000000000000000000000000000000000000000000000000005
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+
+# r = 5 + n, x = 5 is invalid. r must already be reduced.
+Curve = P-256
+X = 264d796a0dab9b376d34eea6fe297dde1c7b73e53944bc96c8f1e8a6850bb6c9
+Y = cf5308020eed460c649ddae61d4ef8bb79958113f106befaf4f18876d12a5e64
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632556
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+Invalid =
+
+# r = n-2, x = n-2 is the largest x without a reduction.
+Curve = P-256
+X = 50a50c01132bf79e42b31fb278f7317b29515e9e1c973a41266b69048826fb8e
+Y = aac53e7df37b5eb25ce4ddb705fc7135c6b1e00a7f56e30744f62f258afa5537
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+
+# r = n-3, x = n-2 is incorrect.
+Curve = P-256
+X = 50a50c01132bf79e42b31fb278f7317b29515e9e1c973a41266b69048826fb8e
+Y = aac53e7df37b5eb25ce4ddb705fc7135c6b1e00a7f56e30744f62f258afa5537
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+Invalid =
+
+# r = 3, x = n+3 is the smallest x with a reduction.
+Curve = P-256
+X = ce24c99032d52ac6ead23c0ae3ec68ef41e51a281fd457808c83136d7dcce90e
+Y = 8f7a154b551e9f39c59279357aa491b2a62bdebc2bb78613883fc72936c057e0
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0000000000000000000000000000000000000000000000000000000000000003
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+
+# r = 4, x = n+3 is incorrect.
+Curve = P-256
+X = ce24c99032d52ac6ead23c0ae3ec68ef41e51a281fd457808c83136d7dcce90e
+Y = 8f7a154b551e9f39c59279357aa491b2a62bdebc2bb78613883fc72936c057e0
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0000000000000000000000000000000000000000000000000000000000000004
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+Invalid =
+
+# r = p-3-n, x = p-3 is the largest valid x.
+Curve = P-256
+X = 768a0d300a595005a520130e50927d403395c8e1e40be997b48fc048410f7cdb
+Y = 16f217d8e1c02bd887e5de388a17783b182e61b5d534152dc2c4be8d75fdd706
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 000000000000000000000000000000004319055358e8617b0c46353d039cdaab
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+
+# r = p-n+5, x = 5 is incorrect. r is too large to compare r+n with x.
+Curve = P-256
+X = 0ec505bc19b14a43e05678cccf07a443d3e871a2e19b68a4da91859a0650f324
+Y = 77300e4f64e9982d94dff5d294428bb37cc9be66117cae9c389d2d495f68b987
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 000000000000000000000000000000004319055358e8617b0c46353d039cdab3
+S = ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254e
+Invalid =
+
+# r = 2, x = 2 is valid.
+Curve = P-384
+X = 016d2db67561bc126ad6c344d6eeb2713a9e2892c649af0f015c6b7617f160c8a3b3a88add669d7155025073c5ac5b4f
+Y = 43bf2ed0088af08645c80aa0a24a567a94ba2d794e9689d3ad4b185bc5d2dd008333e2dd2ebb5069a9b32251a3cac71e
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+
+# r = 2 + n, x = 2 is invalid. r must already be reduced.
+Curve = P-384
+X = 016d2db67561bc126ad6c344d6eeb2713a9e2892c649af0f015c6b7617f160c8a3b3a88add669d7155025073c5ac5b4f
+Y = 43bf2ed0088af08645c80aa0a24a567a94ba2d794e9689d3ad4b185bc5d2dd008333e2dd2ebb5069a9b32251a3cac71e
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52975
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+Invalid =
+
+# r = n-1, x = n-1 is the largest x without a reduction.
+Curve = P-384
+X = b5b375264c09acf145ca91d12ab10a096092a41ec43f4d718e129ea1c12b2dea62c7785efc52f46f009fb1dba133e811
+Y = bc0b2af172b4b3068d032a798080e76f4d56f72069519e3c19a43682a41794e52cb3ca139348d6bbc923e6a4f7945cb1
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+
+# r = n-2, x = n-1 is incorrect.
+Curve = P-384
+X = b5b375264c09acf145ca91d12ab10a096092a41ec43f4d718e129ea1c12b2dea62c7785efc52f46f009fb1dba133e811
+Y = bc0b2af172b4b3068d032a798080e76f4d56f72069519e3c19a43682a41794e52cb3ca139348d6bbc923e6a4f7945cb1
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52971
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+Invalid =
+
+# r = 2, x = n+2 is the smallest x with a reduction.
+Curve = P-384
+X = 01b54a697305092bac2939fb906d7471b411c4eba8654169166a5da3810e1fc96795df921f7abbf519be4a027435176c
+Y = a19012a3518773d508106d4153adee43c3c384fa62ce36a4addea08f593ec9c76b09a6b9c69d29bd7d47eb48e167dd2f
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+
+# r = 3, x = n+2 is incorrect.
+Curve = P-384
+X = 01b54a697305092bac2939fb906d7471b411c4eba8654169166a5da3810e1fc96795df921f7abbf519be4a027435176c
+Y = a19012a3518773d508106d4153adee43c3c384fa62ce36a4addea08f593ec9c76b09a6b9c69d29bd7d47eb48e167dd2f
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+Invalid =
+
+# r = p-1-n, x = p-1 is the largest valid x.
+Curve = P-384
+X = c4fd8e68006b83f7b7b20b731ae405813aa05f6e57374589b36ae1cecd1d49cae1418c22f398188bcf4ef02e89fe7394
+Y = dd1164b3707f59e05129fa228b8448031db159985f035d93470dc42b3ab4129f0760c46cf201d42e73a7e33ba7402ea6
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = 000000000000000000000000000000000000000000000000389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68b
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+
+# r = p-n+2, x = 2 is incorrect. r is too large to compare r+n with x.
+Curve = P-384
+X = 4e5e4f1a6e97059a6cf2f4e8129e5c7c64cb84f9994a41ff5bf30b29c1bf5ba6898627c91a23c73e05cd1a43c8f908c0
+Y = 06a0aed7f1e63a728f87dbd5360a67571a076ab0b4cde81b10d499959814ddb3a8c7854b0bbfa87cc272f90bca2a2254
+Digest = 1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f00418a70cdb7e
+R = 000000000000000000000000000000000000000000000000389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e
+S = ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52970
+Invalid =
+
+# r = 1, x = 1 is valid.
+Curve = P-521
+X = 00f07e0b593332d09ec4fd0bae93f648a3da04dd224faae3f64cc490ec8fce3a6fe53d1b2c9e326be076cafb921b7e3f8b2288db491819522d65472870668c3808c9
+Y = 018e42509aca542a8de421589c38ba653e8cfd69322336217042a9dc0f67f6d7ae2cd4e385f480ffaf8981f715c7ca3765d9867dfd5a02947b0895f82eaf8b257e88
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+
+# r = 1 + n, x = 1 is invalid. r must already be reduced.
+Curve = P-521
+X = 00f07e0b593332d09ec4fd0bae93f648a3da04dd224faae3f64cc490ec8fce3a6fe53d1b2c9e326be076cafb921b7e3f8b2288db491819522d65472870668c3808c9
+Y = 018e42509aca542a8de421589c38ba653e8cfd69322336217042a9dc0f67f6d7ae2cd4e385f480ffaf8981f715c7ca3765d9867dfd5a02947b0895f82eaf8b257e88
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138640a
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+Invalid =
+
+# r = n-2, x = n-2 is the largest x without a reduction.
+Curve = P-521
+X = 002a61afb982e49f030dd4e6ba0e495703abe0442b1283ee693fffc1b558f49f0a4cb4f138ea0604e667958495b86c61f358dce7e7f170da47372be3e4168408a260
+Y = 01baa19e8929fc8e7208e854e706a3d7f21479d1f6922a65ae3490fd5f52ae6580513b1fdd5bee927d002a9608abbb925b6727bdc110a3145fc8622d1fa8154c82d8
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386407
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+
+# r = n-3, x = n-2 is incorrect.
+Curve = P-521
+X = 002a61afb982e49f030dd4e6ba0e495703abe0442b1283ee693fffc1b558f49f0a4cb4f138ea0604e667958495b86c61f358dce7e7f170da47372be3e4168408a260
+Y = 01baa19e8929fc8e7208e854e706a3d7f21479d1f6922a65ae3490fd5f52ae6580513b1fdd5bee927d002a9608abbb925b6727bdc110a3145fc8622d1fa8154c82d8
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+Invalid =
+
+# r = 1, x = n+1 is the smallest x with a reduction.
+Curve = P-521
+X = 0049bbb2d3267a6eab2c59fac5b138b9e9c383db6637fcfe5d9f430e4c4c2ba0332340975448bd86c92a55c1a8288adf7f774096022419aa8c497499dafee7b93257
+Y = 00bb52fd444ec497ce228135f2498d40fb84eb6f674df1245d3aaac3c75b55ff5fff8e90b6f0189a3132cb9fd8d6e74fda5866fe2b9fc7484c628fde97e0b00f2b67
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+
+# r = 2, x = n+1 is incorrect.
+Curve = P-521
+X = 0049bbb2d3267a6eab2c59fac5b138b9e9c383db6637fcfe5d9f430e4c4c2ba0332340975448bd86c92a55c1a8288adf7f774096022419aa8c497499dafee7b93257
+Y = 00bb52fd444ec497ce228135f2498d40fb84eb6f674df1245d3aaac3c75b55ff5fff8e90b6f0189a3132cb9fd8d6e74fda5866fe2b9fc7484c628fde97e0b00f2b67
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+Invalid =
+
+# r = p-1-n, x = p-1 is the largest valid x.
+Curve = P-521
+X = 00f651d53d45bf6fd55a5f184e580d11259bc65200387dbc1bf7fb867d2d12a207d2962204ccf38e9d37d23ed95bd01ec576c457127766ecb8ad00342a476ea82078
+Y = 0196caedf64fbaa9a12c16836e0564e36f733957375706edb5f32911991a994c2d6a1ea5db2ee764835a9d6aff379e195f722b48e8d2b60fc50de2a5160c77c3f06c
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 00000000000000000000000000000000000000000000000000000000000000000005ae79787c40d069948033feb708f65a2fc44a36477663b851449048e16ec79bf5
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+
+# r = p-n+1, x = 1 is incorrect. r is too large to compare r+n with x.
+Curve = P-521
+X = 009eeb7f956230c3744ca5b683f413009363107aad18a027fa7af6ac07a699911e94143d3ef00c0062d4187c2ea74dc9322c05431a6b7fed51ee71b047ce3a0e967c
+Y = 007d2c089a6720f7c7886ce8aa6aeb9b821adde0eb025ef63c62d37c32b2d6823c857ce7743b8181c35c8f34e6aeb4487dd693e01d69dfe883c07c25ebe89bdc4d56
+Digest = 8710339dcb6814d0d9d2290ef422285c9322b7163951f9a0ca8f883d3305286f44139aa374848e4174f5aada663027e4548637b6d19894aec4fb6c46a139fbf9
+R = 00000000000000000000000000000000000000000000000000000000000000000005ae79787c40d069948033feb708f65a2fc44a36477663b851449048e16ec79bf7
+S = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386406
+Invalid =
+
+# Although we do not support secp160r1, all our built-in curves have p > n,
+# while n > p is reachable from custom curve logic. Moreover, p and n have
+# different word widths on 32-bit machines. We include some test vectors to
+# cover these cases.
+#
+# When n > p, the reduction mod n never occurs, but an optimized implementation,
+# working mod p, may incorrectly accept, e.g., r = p+4 instead of r = 4.
+
+# r = 4, x = 4 is valid.
+Curve = secp160r1
+X = 39891bd61138e775cd012518ff00f59ae01c4733
+Y = 25026b77b1c44affb1592dcf711b4290e9404c9f
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 000000000000000000000000000000000000000004
+S = 0100000000000000000001f4c8f927aed3ca752254
+
+# r = 4 + n, x = 4 is invalid. r must already be reduced.
+Curve = secp160r1
+X = 39891bd61138e775cd012518ff00f59ae01c4733
+Y = 25026b77b1c44affb1592dcf711b4290e9404c9f
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 0100000000000000000001f4c8f927aed3ca75225b
+S = 0100000000000000000001f4c8f927aed3ca752254
+Invalid =
+
+# r = p-3, x = p-3 are the largest valid values of x and r.
+Curve = secp160r1
+X = d88d902a0d8d942333c7b846a933d4794fcb5807
+Y = d24c4f405689b86cd5c61fe104e6365d254d5222
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00ffffffffffffffffffffffffffffffff7ffffffc
+S = 0100000000000000000001f4c8f927aed3ca752254
+
+# r = p-4, x = p-3 is incorrect.
+Curve = secp160r1
+X = d88d902a0d8d942333c7b846a933d4794fcb5807
+Y = d24c4f405689b86cd5c61fe104e6365d254d5222
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00ffffffffffffffffffffffffffffffff7ffffffb
+S = 0100000000000000000001f4c8f927aed3ca752254
+Invalid =
+
+# r = p+4, x = 4 is incorrect. They should be compared modulo the order, not p,
+# so r >= p is never valid.
+Curve = secp160r1
+X = d8add22064027856c162243ab09ea96642975297
+Y = 8822a506712385ab3ebe5c61737c3bbb722b06b9
+Digest = 09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b
+R = 00ffffffffffffffffffffffffffffffff80000003
+S = 0100000000000000000001f4c8f927aed3ca752254
+Invalid =