aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-04-03 16:17:01 -0400
committerJack Lloyd <[email protected]>2018-04-03 16:17:01 -0400
commit9be58ff38919065ce72c8959aae2b5b905a75be3 (patch)
treee27dc1bf697a09ca958812a8dc77d4f161e15c3e
parentbc3074dccb934ed709d9e70597e0fd1665d98cb1 (diff)
Run ECC unit tests across all groups where applicable
Many of these were generic tests and not really tied to secp160r1 in any meaningful way.
-rw-r--r--src/tests/unit_ecc.cpp427
-rw-r--r--src/tests/unit_ecdsa.cpp40
2 files changed, 154 insertions, 313 deletions
diff --git a/src/tests/unit_ecc.cpp b/src/tests/unit_ecc.cpp
index f3a163435..6ec9be3e8 100644
--- a/src/tests/unit_ecc.cpp
+++ b/src/tests/unit_ecc.cpp
@@ -1,7 +1,7 @@
/*
* (C) 2007 Falko Strenzke
* 2007 Manuel Hartl
-* 2009,2015 Jack Lloyd
+* 2009,2015,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -84,10 +84,9 @@ Botan::PointGFp create_random_point(Botan::RandomNumberGenerator& rng,
const Botan::EC_Group& group)
{
const Botan::BigInt& p = group.get_p();
+ const Botan::Modular_Reducer mod_p(p);
- Botan::Modular_Reducer mod_p(p);
-
- while(true)
+ for(;;)
{
const Botan::BigInt x = Botan::BigInt::random_integer(rng, 1, p);
const Botan::BigInt x3 = mod_p.multiply(x, mod_p.square(x));
@@ -98,8 +97,7 @@ Botan::PointGFp create_random_point(Botan::RandomNumberGenerator& rng,
if(sqrt_y > 1)
{
BOTAN_ASSERT_EQUAL(mod_p.square(sqrt_y), y, "Square root is correct");
- Botan::PointGFp point = group.point(x, sqrt_y);
- return point;
+ return group.point(x, sqrt_y);
}
}
}
@@ -113,8 +111,7 @@ class ECC_Randomized_Tests final : public Test
std::vector<Test::Result> ECC_Randomized_Tests::run()
{
std::vector<Test::Result> results;
- std::set<std::string> named_groups = Botan::EC_Group::known_named_groups();
- for(auto const& group_name : named_groups)
+ for(const std::string& group_name : Botan::EC_Group::known_named_groups())
{
Test::Result result("ECC randomized " + group_name);
@@ -122,13 +119,9 @@ std::vector<Test::Result> ECC_Randomized_Tests::run()
Botan::EC_Group group(group_name);
- const Botan::PointGFp& base_point = group.get_base_point();
+ const Botan::PointGFp& pt = create_random_point(Test::rng(), group);
const Botan::BigInt& group_order = group.get_order();
- const Botan::PointGFp inf = base_point * group_order;
- result.test_eq("infinite order correct", inf.is_zero(), true);
- result.test_eq("infinity on the curve", inf.on_the_curve(), true);
-
std::vector<Botan::BigInt> blind_ws;
try
@@ -140,13 +133,13 @@ std::vector<Test::Result> ECC_Randomized_Tests::run()
const Botan::BigInt b = Botan::BigInt::random_integer(Test::rng(), 2, group_order);
const Botan::BigInt c = a + b;
- const Botan::PointGFp P = base_point * a;
- const Botan::PointGFp Q = base_point * b;
- const Botan::PointGFp R = base_point * c;
+ const Botan::PointGFp P = pt * a;
+ const Botan::PointGFp Q = pt * b;
+ const Botan::PointGFp R = pt * c;
- Botan::PointGFp P1 = group.blinded_base_point_multiply(a, Test::rng(), blind_ws);
- Botan::PointGFp Q1 = group.blinded_base_point_multiply(b, Test::rng(), blind_ws);
- Botan::PointGFp R1 = group.blinded_base_point_multiply(c, Test::rng(), blind_ws);
+ Botan::PointGFp P1 = group.blinded_var_point_multiply(pt, a, Test::rng(), blind_ws);
+ Botan::PointGFp Q1 = group.blinded_var_point_multiply(pt, b, Test::rng(), blind_ws);
+ Botan::PointGFp R1 = group.blinded_var_point_multiply(pt, c, Test::rng(), blind_ws);
Botan::PointGFp A1 = P + Q;
Botan::PointGFp A2 = Q + P;
@@ -280,26 +273,145 @@ class NIST_Curve_Reduction_Tests final : public Test
BOTAN_REGISTER_TEST("nist_redc", NIST_Curve_Reduction_Tests);
-Test::Result test_groups()
+class EC_Group_Tests : public Test
{
- Test::Result result("ECC Unit");
- std::set<std::string> named_groups = Botan::EC_Group::known_named_groups();
- for(auto const& group_name : named_groups)
- {
- const Botan::EC_Group group(group_name);
- result.confirm("EC_Group is known", !group.get_curve_oid().empty());
- result.test_eq("EC_Group has correct bit size", group.get_p().bits(), group.get_p_bits());
- result.test_eq("EC_Group has byte size", group.get_p().bytes(), group.get_p_bytes());
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
- bool a_is_minus_3 = group.a_is_minus_3();
+ for(const std::string& group_name : Botan::EC_Group::known_named_groups())
+ {
+ Test::Result result("EC_Group " + group_name);
- if(a_is_minus_3)
- result.test_eq("Group A equals -3", group.get_a(), group.get_p() - 3);
- else
- result.test_ne("Group " + group_name + " A does not equal -3", group.get_a(), group.get_p() - 3);
- }
- return result;
- }
+ const Botan::EC_Group group(group_name);
+
+ result.confirm("EC_Group is known", !group.get_curve_oid().empty());
+ result.test_eq("EC_Group has correct bit size", group.get_p().bits(), group.get_p_bits());
+ result.test_eq("EC_Group has byte size", group.get_p().bytes(), group.get_p_bytes());
+
+ const auto pt_mult_by_order = group.get_base_point() * group.get_order();
+ result.confirm("Multiplying point by the order results in zero point", pt_mult_by_order.is_zero());
+
+ if(group.a_is_minus_3())
+ result.test_eq("Group A equals -3", group.get_a(), group.get_p() - 3);
+ else
+ result.test_ne("Group " + group_name + " A does not equal -3", group.get_a(), group.get_p() - 3);
+
+ // get a valid point
+ Botan::PointGFp p = group.get_base_point() * Test::rng().next_nonzero_byte();
+
+ // get a copy
+ Botan::PointGFp q = p;
+
+ p.randomize_repr(Test::rng());
+ q.randomize_repr(Test::rng());
+
+ result.test_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
+ result.test_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
+
+ q.force_affine();
+
+ result.test_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
+ result.test_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
+
+ test_ser_der(result, group);
+ test_basic_math(result, group);
+ test_point_swap(result, group);
+ test_zeropoint(result, group);
+
+ results.push_back(result);
+ }
+
+ return results;
+ }
+ private:
+
+ void test_ser_der(Test::Result& result, const Botan::EC_Group& group)
+ {
+ // generate point
+ const Botan::PointGFp pt = create_random_point(Test::rng(), group);
+ const Botan::PointGFp zero = group.zero_point();
+
+ for(auto scheme : { Botan::PointGFp::UNCOMPRESSED,
+ Botan::PointGFp::COMPRESSED,
+ Botan::PointGFp::HYBRID })
+ {
+ result.test_eq("encoded/decode rt works", group.OS2ECP(pt.encode(scheme)), pt);
+ result.test_eq("encoded/decode rt works", group.OS2ECP(zero.encode(scheme)), zero);
+ }
+ }
+
+ void test_basic_math(Test::Result& result, const Botan::EC_Group& group)
+ {
+ const Botan::PointGFp& G = group.get_base_point();
+
+ Botan::PointGFp p1 = G * 2;
+ p1 += G;
+
+ result.test_eq("point addition", p1, G * 3);
+
+ p1 -= G * 2;
+
+ result.test_eq("point subtraction", p1, G);
+ }
+
+ void test_point_swap(Test::Result& result, const Botan::EC_Group& group)
+ {
+ Botan::PointGFp a(create_random_point(Test::rng(), group));
+ Botan::PointGFp b(create_random_point(Test::rng(), group));
+ b *= Botan::BigInt(Test::rng(), 20);
+
+ Botan::PointGFp c(a);
+ Botan::PointGFp d(b);
+
+ d.swap(c);
+ result.test_eq("swap correct", a, d);
+ result.test_eq("swap correct", b, c);
+ }
+
+ void test_zeropoint(Test::Result& result, const Botan::EC_Group& group)
+ {
+ const Botan::PointGFp zero = group.zero_point();
+ const Botan::PointGFp p1 = group.get_base_point() * 2;
+
+ result.confirm("point is on the curve", p1.on_the_curve());
+ result.confirm("point is not zero", !p1.is_zero());
+
+ Botan::PointGFp p2 = p1;
+ p2 -= p1;
+
+ result.confirm("p - q with q = p results in zero", p2.is_zero());
+
+ const Botan::PointGFp minus_p1 = -p1;
+ result.confirm("point is on the curve", minus_p1.on_the_curve());
+ const Botan::PointGFp shouldBeZero = p1 + minus_p1;
+ result.confirm("point is on the curve", shouldBeZero.on_the_curve());
+ result.confirm("point is zero", shouldBeZero.is_zero());
+
+ result.test_eq("minus point x", minus_p1.get_affine_x(), p1.get_affine_x());
+ result.test_eq("minus point y", minus_p1.get_affine_y(), group.get_p() - p1.get_affine_y());
+
+ result.confirm("zero point is zero", zero.is_zero());
+ result.confirm("zero point is on the curve", zero.on_the_curve());
+ result.test_eq("addition of zero does nothing", p1, p1 + zero);
+ result.test_eq("addition of zero does nothing", p1, zero + p1);
+ result.test_eq("addition of zero does nothing", p1, p1 - zero);
+ result.confirm("zero times anything is the zero point", (zero * 39193).is_zero());
+
+ for(auto scheme : { Botan::PointGFp::UNCOMPRESSED,
+ Botan::PointGFp::COMPRESSED,
+ Botan::PointGFp::HYBRID })
+ {
+ const std::vector<uint8_t> v = zero.encode(scheme);
+ result.test_eq("encoded/decode rt works", group.OS2ECP(v), zero);
+ }
+ }
+
+
+ };
+
+BOTAN_REGISTER_TEST("ec_group", EC_Group_Tests);
Test::Result test_decoding_with_seed()
{
@@ -349,25 +461,6 @@ Version 0.3;
Section 2.1.2
--------
*/
-Test::Result test_point_transformation()
- {
- Test::Result result("ECC Unit");
-
- // get a valid point
- Botan::EC_Group dom_pars("secp160r1");
- Botan::PointGFp p = dom_pars.get_base_point() * Test::rng().next_nonzero_byte();
-
- // get a copy
- Botan::PointGFp q = p;
-
- p.randomize_repr(Test::rng());
- q.randomize_repr(Test::rng());
-
- result.test_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
- result.test_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
- return result;
- }
-
Test::Result test_point_mult()
{
Test::Result result("ECC Unit");
@@ -402,109 +495,6 @@ Test::Result test_point_negative()
return result;
}
-Test::Result test_zeropoint()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group secp160r1("secp160r1");
-
- Botan::PointGFp p1 = secp160r1.point(Botan::BigInt("16984103820118642236896513183038186009872590470"),
- Botan::BigInt("1373093393927139016463695321221277758035357890939"));
-
- result.confirm("point is on the curve", p1.on_the_curve());
-
- Botan::PointGFp p2 = p1;
- p1 -= p2;
-
- result.confirm("p - q with q = p results in zero", p1.is_zero());
- return result;
- }
-
-Test::Result test_zeropoint_enc_dec()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group secp160r1("secp160r1");
-
- Botan::PointGFp p = secp160r1.zero_point();
- result.confirm("zero point is zero", p.is_zero());
-
- std::vector<uint8_t> sv_p = p.encode(Botan::PointGFp::UNCOMPRESSED);
- result.test_eq("encoded/decode rt works", secp160r1.OS2ECP(sv_p), p);
-
- sv_p = p.encode(Botan::PointGFp::COMPRESSED);
- result.test_eq("encoded/decode compressed rt works", secp160r1.OS2ECP(sv_p), p);
-
- sv_p = p.encode(Botan::PointGFp::HYBRID);
- result.test_eq("encoded/decode hybrid rt works", secp160r1.OS2ECP(sv_p), p);
- return result;
- }
-
-Test::Result test_calc_with_zeropoint()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group secp160r1("secp160r1");
-
- Botan::PointGFp p = secp160r1.point(Botan::BigInt("16984103820118642236896513183038186009872590470"),
- Botan::BigInt("1373093393927139016463695321221277758035357890939"));
-
- result.confirm("point is on the curve", p.on_the_curve());
- result.confirm("point is not zero", !p.is_zero());
-
- Botan::PointGFp zero = secp160r1.zero_point();
- result.confirm("zero point is zero", zero.is_zero());
-
- Botan::PointGFp res = p + zero;
- result.test_eq("point + 0 equals the point", p, res);
-
- res = p - zero;
- result.test_eq("point - 0 equals the point", p, res);
-
- res = zero * 32432243;
- result.confirm("point * 0 is the zero point", res.is_zero());
- return result;
- }
-
-Test::Result test_add_point()
- {
- Test::Result result("ECC Unit");
-
- // precalculation
- Botan::EC_Group secp160r1("secp160r1");
- const Botan::PointGFp& p_G = secp160r1.get_base_point();
-
- Botan::PointGFp p0 = p_G;
- Botan::PointGFp p1 = p_G * 2;
-
- p1 += p0;
-
- Botan::PointGFp expected = secp160r1.point(Botan::BigInt("704859595002530890444080436569091156047721708633"),
- Botan::BigInt("1147993098458695153857594941635310323215433166682"));
-
- result.test_eq("point addition", p1, expected);
- return result;
- }
-
-Test::Result test_sub_point()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group secp160r1("secp160r1");
- const Botan::PointGFp& p_G = secp160r1.get_base_point();
-
- Botan::PointGFp p0 = p_G;
- Botan::PointGFp p1 = p_G * 2;
-
- p1 -= p0;
-
- Botan::PointGFp expected = secp160r1.point(Botan::BigInt("425826231723888350446541592701409065913635568770"),
- Botan::BigInt("203520114162904107873991457957346892027982641970"));
-
- result.test_eq("point subtraction", p1, expected);
- return result;
- }
-
Test::Result test_mult_point()
{
Test::Result result("ECC Unit");
@@ -646,115 +636,6 @@ Test::Result test_enc_dec_uncompressed_521()
return result;
}
-Test::Result test_gfp_store_restore()
- {
- Test::Result result("ECC Unit");
-
- // generate point
- Botan::EC_Group dom_pars("secp160r1");
- Botan::PointGFp p = dom_pars.get_base_point();
-
- std::vector<uint8_t> sv_mes = p.encode(Botan::PointGFp::COMPRESSED);
- Botan::PointGFp new_p = dom_pars.OS2ECP(sv_mes);
-
- result.test_eq("original and restored points are same", p, new_p);
- return result;
- }
-
-Test::Result test_more_zeropoint()
- {
- Test::Result result("ECC Unit");
-
- // by Falko
-
- Botan::EC_Group secp160r1("secp160r1");
-
- Botan::PointGFp p1 = secp160r1.point(Botan::BigInt("16984103820118642236896513183038186009872590470"),
- Botan::BigInt("1373093393927139016463695321221277758035357890939"));
-
- result.confirm("point is on the curve", p1.on_the_curve());
- Botan::PointGFp minus_p1 = -p1;
- result.confirm("point is on the curve", minus_p1.on_the_curve());
- Botan::PointGFp shouldBeZero = p1 + minus_p1;
- result.confirm("point is on the curve", shouldBeZero.on_the_curve());
- result.confirm("point is zero", shouldBeZero.is_zero());
-
- Botan::BigInt y1 = p1.get_affine_y();
- y1 = secp160r1.get_p() - y1;
-
- result.test_eq("minus point x", minus_p1.get_affine_x(), p1.get_affine_x());
- result.test_eq("minus point y", minus_p1.get_affine_y(), y1);
-
- Botan::PointGFp zero = secp160r1.zero_point();
- result.confirm("zero point is on the curve", zero.on_the_curve());
- result.test_eq("addition of zero does nothing", p1, p1 + zero);
-
- return result;
- }
-
-Test::Result test_mult_by_order()
- {
- Test::Result result("ECC Unit");
-
- // generate point
- Botan::EC_Group dom_pars("secp160r1");
- Botan::PointGFp p = dom_pars.get_base_point();
- Botan::PointGFp shouldBeZero = p * dom_pars.get_order();
-
- result.confirm("G * order = 0", shouldBeZero.is_zero());
- return result;
- }
-
-Test::Result test_point_swap()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group dom_pars("secp160r1");
-
- Botan::PointGFp a(create_random_point(Test::rng(), dom_pars));
- Botan::PointGFp b(create_random_point(Test::rng(), dom_pars));
- b *= Botan::BigInt(Test::rng(), 20);
-
- Botan::PointGFp c(a);
- Botan::PointGFp d(b);
-
- d.swap(c);
- result.test_eq("swap correct", a, d);
- result.test_eq("swap correct", b, c);
-
- return result;
- }
-
-/**
-* This test verifies that the side channel attack resistant multiplication function
-* yields the same result as the normal (insecure) multiplication via operator*=
-*/
-Test::Result test_mult_sec_mass()
- {
- Test::Result result("ECC Unit");
-
- Botan::EC_Group dom_pars("secp160r1");
- for(int i = 0; i < 50; i++)
- {
- try
- {
- Botan::PointGFp a(create_random_point(Test::rng(), dom_pars));
- Botan::BigInt scal(Botan::BigInt(Test::rng(), 40));
- Botan::PointGFp b = a * scal;
- Botan::PointGFp c(a);
-
- c *= scal;
- result.test_eq("same result", b, c);
- }
- catch(std::exception& e)
- {
- result.test_failure("mult_sec_mass", e.what());
- }
- }
-
- return result;
- }
-
Test::Result test_ecc_registration()
{
Test::Result result("ECC registration");
@@ -787,28 +668,16 @@ class ECC_Unit_Tests final : public Test
{
std::vector<Test::Result> results;
- results.push_back(test_groups());
results.push_back(test_coordinates());
results.push_back(test_decoding_with_seed());
- results.push_back(test_point_transformation());
results.push_back(test_point_mult());
results.push_back(test_point_negative());
- results.push_back(test_zeropoint());
- results.push_back(test_zeropoint_enc_dec());
- results.push_back(test_calc_with_zeropoint());
- results.push_back(test_add_point());
- results.push_back(test_sub_point());
results.push_back(test_mult_point());
results.push_back(test_basic_operations());
results.push_back(test_enc_dec_compressed_160());
results.push_back(test_enc_dec_compressed_256());
results.push_back(test_enc_dec_uncompressed_112());
results.push_back(test_enc_dec_uncompressed_521());
- results.push_back(test_gfp_store_restore());
- results.push_back(test_more_zeropoint());
- results.push_back(test_mult_by_order());
- results.push_back(test_point_swap());
- results.push_back(test_mult_sec_mass());
results.push_back(test_ecc_registration());
return results;
diff --git a/src/tests/unit_ecdsa.cpp b/src/tests/unit_ecdsa.cpp
index 016906e66..dc2a43af5 100644
--- a/src/tests/unit_ecdsa.cpp
+++ b/src/tests/unit_ecdsa.cpp
@@ -403,54 +403,26 @@ Test::Result test_ecc_key_with_rfc5915_parameters()
Test::Result test_curve_registry()
{
- const std::vector<std::string> oids =
- {
- "1.3.132.0.8",
- "1.2.840.10045.3.1.1",
- "1.2.840.10045.3.1.2",
- "1.2.840.10045.3.1.3",
- "1.2.840.10045.3.1.4",
- "1.2.840.10045.3.1.5",
- "1.2.840.10045.3.1.6",
- "1.2.840.10045.3.1.7",
- "1.3.132.0.9",
- "1.3.132.0.30",
- "1.3.132.0.31",
- "1.3.132.0.32",
- "1.3.132.0.33",
- "1.3.132.0.10",
- "1.3.132.0.34",
- "1.3.132.0.35",
- "1.3.36.3.3.2.8.1.1.1",
- "1.3.36.3.3.2.8.1.1.3",
- "1.3.36.3.3.2.8.1.1.5",
- "1.3.36.3.3.2.8.1.1.7",
- "1.3.36.3.3.2.8.1.1.9",
- "1.3.36.3.3.2.8.1.1.11",
- "1.3.36.3.3.2.8.1.1.13",
- };
-
Test::Result result("ECDSA Unit");
- for(auto const& oid_str : oids)
+ for(const std::string& group_name : Botan::EC_Group::known_named_groups())
{
try
{
- Botan::OID oid(oid_str);
- Botan::EC_Group dom_pars(oid);
- Botan::ECDSA_PrivateKey ecdsa(Test::rng(), dom_pars);
+ Botan::EC_Group group(group_name);
+ Botan::ECDSA_PrivateKey ecdsa(Test::rng(), group);
Botan::PK_Signer signer(ecdsa, Test::rng(), "EMSA1(SHA-256)");
Botan::PK_Verifier verifier(ecdsa, "EMSA1(SHA-256)");
- auto msg = Botan::hex_decode("12345678901234567890abcdef12");
- std::vector<uint8_t> sig = signer.sign_message(msg, Test::rng());
+ const std::vector<uint8_t> msg = Botan::hex_decode("12345678901234567890abcdef12");
+ const std::vector<uint8_t> sig = signer.sign_message(msg, Test::rng());
result.confirm("verified signature", verifier.verify_message(msg, sig));
}
catch(Botan::Invalid_Argument& e)
{
- result.test_failure("testing " + oid_str + ": " + e.what());
+ result.test_failure("testing " + group_name + ": " + e.what());
}
}