diff --git a/include/ack/ec.hpp b/include/ack/ec.hpp index 5248b5b..8561be6 100644 --- a/include/ack/ec.hpp +++ b/include/ack/ec.hpp @@ -828,10 +828,6 @@ namespace ack { [[nodiscard]] ec_point_fp_proj doubled() const { const auto& p = *this; - if ( p.is_identity() ) { - return p; - } - if ( p.is_identity() || p.y == 0 ) { return ec_point_fp_proj(); // identity } @@ -1482,11 +1478,11 @@ namespace ack { * @param verify if true, the point is verified to be valid point on the curve created by the curve generator point g. * @return curve point */ - template - [[nodiscard]] inline constexpr point_type make_point(IntT x, IntT y, bool verify = false) const + template + [[nodiscard]] inline constexpr PointU make_point(IntT x, IntT y, bool verify = false) const { return static_cast( *this ) - .make_point( std::move(x), std::move(y), verify ); + .template make_point( std::move(x), std::move(y), verify ); } /** @@ -1633,63 +1629,61 @@ namespace ack { } /** - * Creates a point from a given pair of integers x & y. + * Creates a point from provided affine coordinates x & y. * @warning Returned point stores pointer to curve prime. * The curve must outlive the point. * @note Expects x|y >= 0 and x|y < p * @note The returned point can be invalid, since the function allows * creating points that were not generated with the generator point. * + * @tparam PointU - point type to make. Default affine point_type. + * * @param x - point x coordinate * @param y - point y coordinate * @param verify - If true, the point is verified to be valid point on the curve created by the curve generator point g. * Default is false. Slow operation, can be be performed also with call to point.is_valid() function. * @return Curve point */ - [[nodiscard]] constexpr point_type make_point(IntT&& x, IntT&& y, bool verify = false) const + template + [[nodiscard]] constexpr PointU make_point(IntT&& x, IntT&& y, bool verify = false) const { check_integer( x, "Invalid point x coordinate" ); check_integer( y, "Invalid point y coordinate" ); - auto p = point_type { - *this, + auto point = make_point( make_field_element( std::move(x) ), - make_field_element( std::move(y) ) - }; - - if ( verify ) { - check( p.is_valid(), "Invalid point" ); - } - return p; + make_field_element( std::move(y) ), + verify + ); + return point; } /** - * Creates a point from a given pair of integers x & y. + * Creates a point from provided affine coordinates x & y. * @warning Returned point stores pointer to curve prime. * The curve must outlive the point. * @note Expects x|y >= 0 and x|y < p * @note The returned point can be invalid, since the function allows * creating points that were not generated with the generator point. * + * @tparam PointU - point type to make. Default affine point_type. + * * @param x - point x coordinate * @param y - point y coordinate * @param verify - If true, the point is verified to be valid point on the curve created by the curve generator point g. * Default is false. Slow operation, can be be performed also with call to point.is_valid() function. * @return Curve point */ - [[nodiscard]] constexpr point_type make_point(const IntT& x, const IntT& y, bool verify = false) const + template + [[nodiscard]] constexpr PointU make_point(const IntT& x, const IntT& y, bool verify = false) const { check_integer( x, "Invalid point x coordinate" ); check_integer( y, "Invalid point y coordinate" ); - auto p = point_type { - *this, + auto point = make_point( make_field_element( x, /*verify=*/ false ), - make_field_element( y, /*verify=*/ false ) - }; - - if ( verify ) { - check( p.is_valid(), "Invalid point" ); - } - return p; + make_field_element( y, /*verify=*/ false ), + verify + ); + return point; } /** @@ -1723,9 +1717,6 @@ namespace ack { auto afe = make_field_element( a, /*verify =*/ false ); auto bfe = make_field_element( b, /*verify =*/ false ); auto y2 = 4 * afe.sqr() * afe + 27 * bfe.sqr(); - if ( y2 == 0 ) { - return false; - } // check that discriminant is nonzero. If zero, the curve is singular. if ( ( -16 * y2 ) == 0) { @@ -1781,6 +1772,21 @@ namespace ack { } return field_element_type( x, p ); } + + template + [[nodiscard]] constexpr PointU make_point(field_element_type x, field_element_type y, bool verify = false) const + { + auto point = PointU{ point_type { + *this, + std::move( x ), + std::move( y ) + }}; + + if ( verify ) { + check( point.is_valid(), "Invalid point" ); + } + return point; + } }; /** diff --git a/tests/include/ack/tests/ec_test.hpp b/tests/include/ack/tests/ec_test.hpp index 4182275..545660e 100644 --- a/tests/include/ack/tests/ec_test.hpp +++ b/tests/include/ack/tests/ec_test.hpp @@ -142,6 +142,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1.is_valid() , false ) auto p1_proj = ec_point_fp_proj( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_proj ) REQUIRE_EQUAL( ( p1_proj.x == 0 ) && ( p1_proj.y == 1 ) && ( p1_proj.z == 0 ), true ) REQUIRE_EQUAL( p1_proj.is_identity(), true ) REQUIRE_EQUAL( p1_proj.is_on_curve(), true ) @@ -149,6 +151,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1_proj.to_affine() , p1 ) auto p1_jacobi = ec_point_fp_jacobi( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_jacobi ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_jacobi ) REQUIRE_EQUAL( ( p1_jacobi.x == 0 ) && ( p1_jacobi.y == 1 ) && ( p1_jacobi.z == 0 ), true ) REQUIRE_EQUAL( p1_jacobi.is_identity(), true ) REQUIRE_EQUAL( p1_jacobi.is_on_curve(), true ) @@ -176,6 +180,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1.is_valid() , false ) auto p1_proj = ec_point_fp_proj( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ) , p1_proj ) REQUIRE_EQUAL( ( p1_proj.x == 3 ) && ( p1_proj.y == 7 ) && ( p1_proj.z == 1 ), true ) REQUIRE_EQUAL( p1_proj.is_identity(), false ) REQUIRE_EQUAL( p1_proj.is_on_curve(), false ) @@ -183,6 +189,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1_proj.to_affine() , p1 ) auto p1_jacobi = ec_point_fp_jacobi( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_jacobi ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_jacobi ) REQUIRE_EQUAL( ( p1_jacobi.x == 3 ) && ( p1_jacobi.y == 7 ) && ( p1_jacobi.z == 1 ), true ) REQUIRE_EQUAL( p1_jacobi.is_identity(), false ) REQUIRE_EQUAL( p1_jacobi.is_on_curve(), false ) @@ -210,6 +218,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1.is_valid() , false ) // point not generated by base point auto p1_proj = ec_point_fp_proj( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) REQUIRE_EQUAL( ( p1_proj.x == 3 ) && ( p1_proj.y == 10 ) && ( p1_proj.z == 1 ), true ) REQUIRE_EQUAL( p1_proj.is_identity(), false ) REQUIRE_EQUAL( p1_proj.is_on_curve(), true ) @@ -217,6 +227,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1_proj.to_affine() , p1 ) auto p1_jacobi = ec_point_fp_jacobi( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_jacobi ) + REQUIRE_EQUAL( c23.make_point( x, y ), p1_jacobi ) REQUIRE_EQUAL( ( p1_jacobi.x == 3 ) && ( p1_jacobi.y == 10 ) && ( p1_jacobi.z == 1 ), true ) REQUIRE_EQUAL( p1_jacobi.is_identity(), false ) REQUIRE_EQUAL( p1_jacobi.is_on_curve(), true ) @@ -244,6 +256,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1.is_valid() , false ) auto p1_proj = ec_point_fp_proj( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_proj ) REQUIRE_EQUAL( ( p1_proj.x == 22 ) && ( p1_proj.y == 22 ) && ( p1_proj.z == 1 ), true ) REQUIRE_EQUAL( p1_proj.is_identity(), false ) REQUIRE_EQUAL( p1_proj.is_on_curve(), false ) @@ -251,6 +265,8 @@ namespace ack::tests { REQUIRE_EQUAL( p1_proj.to_affine() , p1 ) auto p1_jacobi = ec_point_fp_jacobi( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_jacobi ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_jacobi ) REQUIRE_EQUAL( ( p1_jacobi.x == 22 ) && ( p1_jacobi.y == 22 ) && ( p1_jacobi.z == 1 ), true ) REQUIRE_EQUAL( p1_jacobi.is_identity(), false ) REQUIRE_EQUAL( p1_jacobi.is_on_curve(), false ) @@ -278,12 +294,16 @@ namespace ack::tests { REQUIRE_EQUAL( p1.is_valid() , true ) auto p1_proj = ec_point_fp_proj( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y ), p1_proj ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ true ), p1_proj ) REQUIRE_EQUAL( ( p1_proj.x == 5 ) && ( p1_proj.y == 4 ) && ( p1_proj.z == 1 ), true ) REQUIRE_EQUAL( p1_proj.is_identity(), false ) REQUIRE_EQUAL( p1_proj.is_on_curve(), true ) REQUIRE_EQUAL( p1_proj.is_valid() , true ) auto p1_jacobi = ec_point_fp_jacobi( p1 ); + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ false ), p1_jacobi ) + REQUIRE_EQUAL( c23.make_point( x, y, /*verify=*/ true ), p1_jacobi ) REQUIRE_EQUAL( ( p1_jacobi.x == 5 ) && ( p1_jacobi.y == 4 ) && ( p1_jacobi.z == 1 ), true ) REQUIRE_EQUAL( p1_jacobi.is_identity(), false ) REQUIRE_EQUAL( p1_jacobi.is_on_curve(), true )