Repository: randombit/botan
Pull request #2102 (2019-09-12 13:36:26)

Support loading an EC point with affine zero coordinates.
For example it is possible to construct a point with x coordinate of zero whenenver b has a square root modulo p.

Found during integration with https://github.com/catenacyber/elliptic-curve-differential-fuzzer


Patch:
diff --git a/src/lib/pubkey/ec_group/point_gfp.cpp b/src/lib/pubkey/ec_group/point_gfp.cpp
index 5574a360c..9a9667175 100644
--- a/src/lib/pubkey/ec_group/point_gfp.cpp
+++ b/src/lib/pubkey/ec_group/point_gfp.cpp
@@ -30,9 +30,9 @@ PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
    m_coord_y(y),
    m_coord_z(m_curve.get_1_rep())
    {
-   if(x <= 0 || x >= curve.get_p())
+   if(x < 0 || x >= curve.get_p())
       throw Invalid_Argument("Invalid PointGFp affine x");
-   if(y <= 0 || y >= curve.get_p())
+   if(y < 0 || y >= curve.get_p())
       throw Invalid_Argument("Invalid PointGFp affine y");
 
    secure_vector<word> monty_ws(m_curve.get_ws_size());
diff --git a/src/lib/pubkey/ec_group/point_gfp.h b/src/lib/pubkey/ec_group/point_gfp.h
index a233c5b94..bddb6707b 100644
--- a/src/lib/pubkey/ec_group/point_gfp.h
+++ b/src/lib/pubkey/ec_group/point_gfp.h
@@ -96,6 +96,7 @@ class BOTAN_PUBLIC_API(2,0) PointGFp final
 
       /**
       * Construct a point from its affine coordinates
+      * Prefer EC_Group::point(x,y) for this operation.
       * @param curve the base curve
       * @param x affine x coordinate
       * @param y affine y coordinate


Test patch:
diff --git a/src/tests/data/pubkey/ecc.vec b/src/tests/data/pubkey/ecc_base_point_mul.vec
similarity index 100%
rename from src/tests/data/pubkey/ecc.vec
rename to src/tests/data/pubkey/ecc_base_point_mul.vec
diff --git a/src/tests/data/pubkey/ecc_var_point_mul.vec b/src/tests/data/pubkey/ecc_var_point_mul.vec
new file mode 100644
index 000000000..31a4d757f
--- /dev/null
+++ b/src/tests/data/pubkey/ecc_var_point_mul.vec
@@ -0,0 +1,67 @@
+
+# x=0 tests generated by OpenSSL
+
+[secp160r1]
+X = 0x0
+Y = 0x6FF0D69A36F70625C65CA05EC3067DB8868399E
+k = 0xD23DFBE3261669627B6F84818BD5FB93
+kX = 0x84C267738CDA81A7B399FCFC7D2198DBBFC528AA
+kY = 0xA39AB69D16A1D9B1F5B2EDC77A53904BD2F694FD
+
+X = 0x0
+Y = 0xF900F2965C908F9DA39A35FA13CF9823F797C661
+k = 0x838B1CE199C05926BE905C82DC7BCBB9
+kX = 0x67DEB447DCC6DB622B75E9C5B642A57FA7BC133A
+kY = 0xDF1A116A5BAC921BDD45442E5E2C096EEFCEEFC6
+
+[secp160r2]
+X = 0x0
+Y = 0x19B5205266A7E65E9E3BBF9CF6659665D891710E
+k = 0xB19785992C666BCBF756DBCCE969F1FA
+kX = 0xB9FFBC1D385E102ABAAA1F7BBB072FBCFFFA3D92
+kY = 0x1D83105104C48F80EF30883865FA231198B2E667
+
+X = 0x0
+Y = 0xE64ADFAD995819A161C44063099A6999276E3B65
+k = 0xB249D974C10DFCDDDE68EBA4093207E3
+kX = 0xD5CD54E6B5A20D63F5EEDCF4A7D403C9CE6FD183
+kY = 0xE7058175309612A1764C96FBC0997F731D7328EF
+
+[secp256r1]
+X = 0x0
+Y = 0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4
+k = 0x8C9F8D338CCF9A69E06E8EC420628FB4
+kX = 0x52E0813F4C154FA39773CE64050F2080E9EDB63D2EDCB6119AEDFFC42AE03D34
+kY = 0x804D3E8A3BCEBA2FD1EE0429F100EAE459C90E443B96D5A98FCD97787656816D
+
+X = 0x0
+Y = 0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B
+k = 0x812F33B934572023C803A97A4144D1ED
+kX = 0x3521B6A34485ECCCD6E73A2D69D3EBB837E70BFBA583962577D004520C46573E
+kY = 0xFB2ABBE62BE5211FBE63D65C0A32D6258792C86DC26D264456DC9DAC43CB54A8
+
+[secp384r1]
+X = 0x0
+Y = 0xC306610FB0AE5A159CF45C06069F22A6C5EB3641C602D42DEA2C4B4F75550793406D80D2B91AD54F9048BD487AF1ADE1
+k = 0xC468FCBA3D5F6629101F0542B0B45FCD
+kX = 0xD1207533641E42D15887A84258CD0762A57A4D2575F82E6BF5172D8156DC2CCCDB8D06591EA3EBBE85E394B1312CDB89
+kY = 0x55BD64882101C3F42F470E98CAE3BA578BBDE77FEA3FE1D339A6A486FF9CF38B001E71BEFDC60C045C83E5B4E4466020
+
+X = 0x0
+Y = 0x3CF99EF04F51A5EA630BA3F9F960DD593A14C9BE39FD2BD215D3B4B08AAAF86BBF927F2C46E52AB06FB742B8850E521E
+k = 0xD3F1AADF5ED9052F246D5B9608D9E137
+kX = 0x4D012E2463D722B8279C46A65F55B895A391C908837C54148C0632D291BC606301742BC4A3573BB355D6EBB0CB647E90
+kY = 0x679572FB1930511F1F46FF3D1D2B496715CB4A82B2794AC5438AD013CCAC93BD54277BD59C770E2F6CB1E7FADE17E79
+
+[secp521r1]
+X = 0x0
+Y = 0x12DF13601594A883EF2D935E44BB90BF4D6619B74E52AF7552F97769011C0719EB439CFAB2A88D40FE59A2BED1F43557169A2D0A2CCD280C607B92BBF51FFE0B078
+k = 0xEAA09B20EF14895D1C0EDF57B309AA21
+kX = 0x6753947C091A35FFC8C49446DE48742B378CFCDC705148FC70CDC2E297095DAA26513EBCED6034ED5F26B479DD5060332D85CEC216AA23081A6420A4517156CF39
+kY = 0x1CE0D70BFF977CDE0B264D91D8B96BC82CB1F2251336443E01E30D5A4451AC3B246657504695D39C4525DBE2C74BD9761923A7983208B3F04B48BDA421587B5EF29
+
+X = 0x0
+Y = 0xD20EC9FEA6B577C10D26CA1BB446F40B299E648B1AD508AAD068896FEE3F8E614BC63054D5772BF01A65D412E0BCAA8E965D2F5D332D7F39F846D440AE001F4F87
+k = 0x8913F6C06A003873215F14EF1045C39F
+kX = 0x15C7248CF2474BEC46C23EAA6BA621D361E98797709EEA7E959724B9B101CE64A47C0B187A34C3EA0D8CFD9A85A533EE715762E2F61D23D05367CCC4DDCA598EEB7
+kY = 0x154DCF9A0359C22D4BF930B5E42DCB0707E912CF3DBEF5563E01E53CAE95BE45DD6EC3C08EF8CCA63A58D14C8E97970BF324D4EAD8722CEC84B229E9D4E97FBED90
diff --git a/src/tests/test_ecc_pointmul.cpp b/src/tests/test_ecc_pointmul.cpp
index 460c43ee5..0e4e18015 100644
--- a/src/tests/test_ecc_pointmul.cpp
+++ b/src/tests/test_ecc_pointmul.cpp
@@ -1,28 +1,29 @@
 /*
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2019 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
 
 #include "tests.h"
 
-#if defined(BOTAN_HAS_ECDSA)
-   #include <botan/ecdsa.h>
+#if defined(BOTAN_HAS_ECC_GROUP)
+   #include <botan/ec_group.h>
 #endif
 
 namespace Botan_Tests {
 
 namespace {
 
-#if defined(BOTAN_HAS_ECDSA)
-class ECC_Pointmult_Tests final : public Text_Based_Test
+#if defined(BOTAN_HAS_ECC_GROUP)
+
+class ECC_Basepoint_Mul_Tests final : public Text_Based_Test
    {
    public:
-      ECC_Pointmult_Tests() : Text_Based_Test("pubkey/ecc.vec", "m,X,Y") {}
+      ECC_Basepoint_Mul_Tests() : Text_Based_Test("pubkey/ecc_base_point_mul.vec", "m,X,Y") {}
 
       Test::Result run_one_test(const std::string& group_id, const VarMap& vars) override
          {
-         Test::Result result("ECC Scalarmult " + group_id);
+         Test::Result result("ECC base point multiply " + group_id);
 
          const Botan::BigInt m = vars.get_req_bn("m");
          const Botan::BigInt X = vars.get_req_bn("X");
@@ -49,7 +50,45 @@ class ECC_Pointmult_Tests final : public Text_Based_Test
          }
    };
 
-BOTAN_REGISTER_TEST("ecc_pointmul", ECC_Pointmult_Tests);
+BOTAN_REGISTER_TEST("ecc_basemul", ECC_Basepoint_Mul_Tests);
+
+class ECC_Varpoint_Mul_Tests final : public Text_Based_Test
+   {
+   public:
+      ECC_Varpoint_Mul_Tests() : Text_Based_Test("pubkey/ecc_var_point_mul.vec", "X,Y,k,kX,kY") {}
+
+      Test::Result run_one_test(const std::string& group_id, const VarMap& vars) override
+         {
+         Test::Result result("ECC var point multiply " + group_id);
+
+         const Botan::BigInt X = vars.get_req_bn("X");
+         const Botan::BigInt Y = vars.get_req_bn("Y");
+         const Botan::BigInt k = vars.get_req_bn("k");
+         const Botan::BigInt kX = vars.get_req_bn("kX");
+         const Botan::BigInt kY = vars.get_req_bn("kY");
+
+         Botan::EC_Group group(Botan::OID::from_string(group_id));
+
+         const Botan::PointGFp pt = group.point(X, Y);
+
+         result.confirm("Input point is on the curve", pt.on_the_curve());
+
+         const Botan::PointGFp p1 = pt * k;
+         result.test_eq("p1 affine X", p1.get_affine_x(), kX);
+         result.test_eq("p1 affine Y", p1.get_affine_y(), kY);
+
+         result.confirm("Output point is on the curve", p1.on_the_curve());
+
+         std::vector<Botan::BigInt> ws;
+         const Botan::PointGFp p2 = group.blinded_var_point_multiply(pt, k, Test::rng(), ws);
+         result.test_eq("p2 affine X", p2.get_affine_x(), kX);
+         result.test_eq("p2 affine Y", p2.get_affine_y(), kY);
+
+         return result;
+         }
+   };
+
+BOTAN_REGISTER_TEST("ecc_varmul", ECC_Varpoint_Mul_Tests);
 
 #endif