diff --git a/README.md b/README.md index 186c2aa9a..8704f4b19 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [[alloc] init] C++ Cryptography Suite +# [[alloc] init] C++ Cryptography Suite [![Twitter](https://img.shields.io/twitter/follow/alloc_init_)](https://twitter.com/alloc_init_) [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=flat-square&logo=telegram&logoColor=dark)](https://t.me/alloc_init) diff --git a/libs/algebra/include/nil/crypto3/algebra/curves/detail/scalar_mul.hpp b/libs/algebra/include/nil/crypto3/algebra/curves/detail/scalar_mul.hpp index 6d7cb3ed3..89d8c4148 100644 --- a/libs/algebra/include/nil/crypto3/algebra/curves/detail/scalar_mul.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/curves/detail/scalar_mul.hpp @@ -112,23 +112,20 @@ namespace nil { return res; } - template - std::enable_if_t::value, CurveElementType> constexpr - operator*(const CurveElementType &point, const std::size_t &multiplier) { + template + constexpr CurveElementType operator*(const CurveElementType &point, const std::size_t &multiplier) { typename CurveElementType::params_type::scalar_field_type::value_type scalar(multiplier); return point * scalar; } - template - std::enable_if_t::value, CurveElementType> constexpr - operator*(const std::size_t &multiplier, const CurveElementType &point) { + template + constexpr CurveElementType operator*(const std::size_t &multiplier, const CurveElementType &point) { typename CurveElementType::params_type::scalar_field_type::value_type scalar(multiplier); return point * scalar; } - template - std::enable_if_t::value, bool> - subgroup_check(CurveElementType point) { + template + bool subgroup_check(CurveElementType point) { auto scalar_modulus = CurveElementType::group_type::curve_type::scalar_field_type::modulus; scalar_mul_inplace(point, scalar_modulus); return point.is_zero(); diff --git a/libs/algebra/include/nil/crypto3/algebra/curves/detail/subgroup_check.hpp b/libs/algebra/include/nil/crypto3/algebra/curves/detail/subgroup_check.hpp index f0347d7ad..fec8f1c54 100644 --- a/libs/algebra/include/nil/crypto3/algebra/curves/detail/subgroup_check.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/curves/detail/subgroup_check.hpp @@ -33,10 +33,8 @@ namespace nil { namespace algebra { namespace curves { namespace detail { - // TODO: temporary implementation due to absence of GroupValueType type_trait - // Should be implemented as class method - template::value>::type> + template + requires CurveGroup bool subgroup_check(const GroupValueType &p) { return (p * GroupValueType::group_type::curve_type::q).is_zero(); } diff --git a/libs/algebra/include/nil/crypto3/algebra/random_element.hpp b/libs/algebra/include/nil/crypto3/algebra/random_element.hpp index 19cbd4eee..7cae3c348 100644 --- a/libs/algebra/include/nil/crypto3/algebra/random_element.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/random_element.hpp @@ -92,12 +92,12 @@ namespace nil { return typename field_type::value_type(data); } - template, typename UniformRandomBitGenerator = boost::random::random_device> - typename std::enable_if::value, typename CurveGroupType::value_type>:: - type constexpr random_element(UniformRandomBitGenerator &&rng = UniformRandomBitGenerator()) { + constexpr typename CurveGroupType::value_type + random_element(UniformRandomBitGenerator &&rng = UniformRandomBitGenerator()) { using curve_type = typename CurveGroupType::curve_type; using field_type = typename curve_type::scalar_field_type; diff --git a/libs/algebra/include/nil/crypto3/algebra/type_traits.hpp b/libs/algebra/include/nil/crypto3/algebra/type_traits.hpp index 5ace321c5..b0f380cb3 100644 --- a/libs/algebra/include/nil/crypto3/algebra/type_traits.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/type_traits.hpp @@ -31,96 +31,12 @@ #include #include -#include -#include -#include -#include #include namespace nil { namespace crypto3 { namespace algebra { - using namespace boost::mpl::placeholders; - - BOOST_TTI_HAS_TYPE(iterator) - BOOST_TTI_HAS_TYPE(const_iterator) - - BOOST_TTI_HAS_TYPE(params_type) - BOOST_TTI_HAS_TYPE(curve_type) - BOOST_TTI_HAS_TYPE(field_type) - BOOST_TTI_HAS_TYPE(value_type) - BOOST_TTI_HAS_TYPE(base_field_type) - BOOST_TTI_HAS_TYPE(scalar_field_type) - BOOST_TTI_HAS_TYPE(gt_type) - - // BOOST_TTI_HAS_TYPE(g1_type) does not work properly on g1_type since it is a template - template> - struct has_type_g1_type : std::false_type { }; - template - struct has_type_g1_type>> : std::true_type { }; - - // BOOST_TTI_HAS_TYPE(g2_type) does not work properly on g2_type since it is a template - template> - struct has_type_g2_type : std::false_type { }; - template - struct has_type_g2_type>> : std::true_type { }; - - BOOST_TTI_HAS_TYPE(group_type) - - BOOST_TTI_HAS_STATIC_MEMBER_DATA(base_field_modulus) - - BOOST_TTI_HAS_STATIC_MEMBER_DATA(scalar_field_modulus) - - BOOST_TTI_HAS_STATIC_MEMBER_DATA(p) - - BOOST_TTI_HAS_STATIC_MEMBER_DATA(q) - - BOOST_TTI_HAS_FUNCTION(to_affine) - - BOOST_TTI_HAS_FUNCTION(to_special) - - BOOST_TTI_HAS_FUNCTION(is_special) - BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION(zero) - - BOOST_TTI_HAS_STATIC_MEMBER_FUNCTION(one) - - BOOST_TTI_HAS_FUNCTION(is_zero) - - BOOST_TTI_HAS_FUNCTION(is_well_formed) - - BOOST_TTI_HAS_FUNCTION(double_inplace) - - BOOST_TTI_HAS_FUNCTION(mixed_add) - - template - struct is_curve { - static constexpr bool value = has_type_base_field_type::value && - has_type_scalar_field_type::value && has_type_g1_type::value; - }; - - /** @brief is typename T either g1 or g2 group */ - template - struct is_curve_group { - static constexpr bool value = has_type_params_type::value && - has_type_curve_type>::value && - has_type_field_type::value && has_type_value_type::value; - }; - - template - struct is_curve_element { - static const bool value = - has_type_field_type::value && has_type_group_type::value && - has_static_member_function_zero::value && has_static_member_function_one::value && - has_function_is_zero::value && has_function_is_well_formed::value && - has_function_double_inplace::value; - }; - - template - struct has_mixed_add { - static const bool value = has_function_mixed_add>::value; - }; - template concept FieldValue = requires(const T &a, const T &b, const boost::multiprecision::cpp_int &exponent) { typename T::field_type; @@ -168,22 +84,43 @@ namespace nil { }; template - struct is_complex : std::false_type { }; + concept Curve = requires { + typename T::base_field_type; + typename T::scalar_field_type; + typename T::template g1_type<>; + requires Field; + requires Field; + }; + template - struct is_complex> : std::true_type { }; + concept CurveWithG2 = Curve && requires { typename T::template g2_type<>; }; + template - constexpr bool is_complex_v = is_complex::value; + concept CurveWithTargetGroup = Curve && requires { typename T::gt_type; }; template - struct remove_complex { - using type = T; + concept CurveElement = requires(T &value, const T &const_value) { + typename T::field_type; + typename T::group_type; + { T::zero() } -> std::convertible_to; + { T::one() } -> std::convertible_to; + { const_value.is_zero() } -> std::convertible_to; + { const_value.is_well_formed() } -> std::convertible_to; + { value.double_inplace() } -> std::same_as; }; + template - struct remove_complex> { - using type = T; + concept CurveGroup = requires { + typename T::params_type; + typename T::curve_type; + typename T::field_type; + typename T::value_type; + requires Curve; + requires Field; + requires CurveElement; + requires std::same_as; }; - template - using remove_complex_t = typename remove_complex::type; + } // namespace algebra } // namespace crypto3 } // namespace nil diff --git a/libs/algebra/include/nil/crypto3/detail/assert.hpp b/libs/algebra/include/nil/crypto3/detail/assert.hpp deleted file mode 100644 index 2fa803dd7..000000000 --- a/libs/algebra/include/nil/crypto3/detail/assert.hpp +++ /dev/null @@ -1,55 +0,0 @@ -//---------------------------------------------------------------------------// -// Copyright (c) 2020-2021 Mikhail Komarov -// -// MIT License -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -//---------------------------------------------------------------------------// - -#ifndef CRYPTO3_DETAIL_ASSERT_HPP -#define CRYPTO3_DETAIL_ASSERT_HPP - -#include - -#define CRYPTO3_DETAIL_ASSERT_FLOATING_POINT(T) \ - static_assert(std::is_floating_point::type>::value, \ - "argument must be a (real or complex) floating point type"); - -#define CRYPTO3_DETAIL_ASSERT_INTEGRAL(T) \ - static_assert(std::is_integral::value, "argument must be a real integral type"); - -#define CRYPTO3_DETAIL_ASSERT_VALID_COMPLEX(T) \ - static_assert(!algebra::detail::is_complex::value || \ - std::is_floating_point::type>::value, \ - "invalid complex type argument (valid types are " \ - "complex, complex, and complex)"); - -#define CRYPTO3_DETAIL_ASSERT_ARITHMETIC(T) \ - CRYPTO3_DETAIL_ASSERT_VALID_COMPLEX(T) \ - static_assert(std::is_arithmetic::type>::value, \ - "argument must be a (real or complex) arithmetic type"); - -#define CRYPTO3_DETAIL_ASSERT_REAL(T) \ - static_assert(std::is_arithmetic::value, "argument must be a real arithmetic type"); - -#define CRYPTO3_DETAIL_ASSERT_COMPLEX(T) \ - CRYPTO3_DETAIL_ASSERT_VALID_COMPLEX(T) \ - static_assert(algebra::detail::is_complex::value, "argument must be a complex type"); - -#endif // CRYPTO3_DETAIL_ASSERT_H_ \ No newline at end of file diff --git a/libs/algebra/test/bench_test/curves.cpp b/libs/algebra/test/bench_test/curves.cpp index c8da5d8c1..175330272 100644 --- a/libs/algebra/test/bench_test/curves.cpp +++ b/libs/algebra/test/bench_test/curves.cpp @@ -98,7 +98,7 @@ void benchmark_curve_operations(std::string const& curve_name) { bench_name("G1 scalar multiplication"), [](typename g1_type::value_type& A, typename scalar_field::value_type const& B) { return A *= B; }); - if constexpr (has_type_g2_type::value) { + if constexpr (CurveWithG2) { using g2_type = typename curve_type::template g2_type<>; using g2_field = typename g2_type::field_type; @@ -131,7 +131,7 @@ void benchmark_curve_operations(std::string const& curve_name) { std::cout << "Curve " << curve_name << " does not have G2, skipping benchmarks" << std::endl; } - if constexpr (has_type_gt_type::value) { + if constexpr (CurveWithTargetGroup) { using gt_type = typename curve_type::gt_type; run_benchmark( diff --git a/libs/algebra/test/type_traits.cpp b/libs/algebra/test/type_traits.cpp index 035bece02..8619a9831 100644 --- a/libs/algebra/test/type_traits.cpp +++ b/libs/algebra/test/type_traits.cpp @@ -64,19 +64,12 @@ template void test_field_value_types() { static_assert(FieldElementWithCoordinates); - BOOST_ASSERT(has_type_field_type::value); - BOOST_ASSERT((has_function_is_zero::value)); - BOOST_ASSERT((has_static_member_function_zero::value)); - BOOST_ASSERT((has_static_member_function_one::value)); - - BOOST_ASSERT(FieldValue); + static_assert(FieldValue); } template void test_field_types() { - BOOST_ASSERT(has_type_value_type::value); - - BOOST_ASSERT(Field); + static_assert(Field); test_field_value_types(); } @@ -85,58 +78,42 @@ template void test_extended_field_types() { test_field_types(); - BOOST_ASSERT(ExtendedField); - - BOOST_ASSERT(ExtendedFieldValue); + static_assert(ExtendedField); + static_assert(ExtendedFieldValue); test_field_value_types(); } template void test_curve_group_types() { - BOOST_ASSERT(is_curve_group::value); - BOOST_ASSERT(has_type_curve_type::value); - - BOOST_ASSERT(has_type_value_type::value); + static_assert(CurveGroup); using value_type = typename curve_group_type::value_type; - BOOST_ASSERT(has_type_field_type::value); - BOOST_ASSERT(has_type_group_type::value); - - BOOST_ASSERT((has_static_member_function_zero::value)); - BOOST_ASSERT((has_static_member_function_one::value)); - BOOST_ASSERT((has_function_is_zero::value)); - BOOST_ASSERT((has_function_is_well_formed::value)); - BOOST_ASSERT((has_function_double_inplace::value)); - - BOOST_ASSERT(is_curve_element::value); + static_assert(CurveElement); } template void test_ordinary_curve_types() { - BOOST_ASSERT(has_type_base_field_type::value); test_field_types(); - BOOST_ASSERT(has_type_scalar_field_type::value); test_field_types(); - BOOST_ASSERT(has_type_g1_type::value); test_curve_group_types>(); - BOOST_ASSERT(is_curve::value); + static_assert(Curve); } template void test_pairing_friendly_curve_types() { test_ordinary_curve_types(); - BOOST_ASSERT(has_type_g2_type::value); + static_assert(CurveWithG2); test_curve_group_types>(); using g2_base_field = typename curve_type::template g2_type<>::params_type::field_type; test_extended_field_types(); - BOOST_ASSERT(has_type_gt_type::value); + static_assert(CurveWithTargetGroup); test_extended_field_types(); } diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/inference.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/inference.hpp index 1f255cddf..879f66b8e 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/inference.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/inference.hpp @@ -60,8 +60,8 @@ namespace nil { template class is_compatible; - template - class is_compatible::value>::type> { + template + class is_compatible { using default_endianness = option::big_endian; public: diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/type_traits.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/type_traits.hpp index aa8923cc6..d1c1da32e 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/type_traits.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/type_traits.hpp @@ -53,24 +53,6 @@ namespace nil { } // namespace crypto3 namespace marshalling { - /// @brief Compile time check function of whether a provided type is any - /// variant of nil::crypto3::marshalling::types::curve_element. - /// @tparam T Any type. - /// @return true in case provided type is any variant of @ref curve_element - /// @related nil::crypto3::marshalling::types::curve_element - template - struct is_curve_element { - - static const bool value = false; - }; - - template - struct is_curve_element< - nil::crypto3::marshalling::types::curve_element> { - - static const bool value = true; - }; - template inline constexpr bool marshalling_field_element = false; @@ -88,9 +70,9 @@ namespace nil { template struct is_container; - template - requires is_curve_element::value - struct is_container { + template + struct is_container, + void> { static const bool value = false; }; diff --git a/libs/marshalling/algebra/test/curve_element.cpp b/libs/marshalling/algebra/test/curve_element.cpp index 0cec5c3d7..8a8a2cbfe 100644 --- a/libs/marshalling/algebra/test/curve_element.cpp +++ b/libs/marshalling/algebra/test/curve_element.cpp @@ -71,7 +71,7 @@ void test_curve_element_big_endian(T val) { using curve_element_type = types::curve_element, typename T::group_type>; - static_assert(nil::marshalling::is_curve_element::value); + static_assert(nil::crypto3::algebra::CurveElement); static_assert(nil::marshalling::is_compatible::value); nil::marshalling::status_type status; diff --git a/libs/math/include/nil/crypto3/math/static_matrix/math.hpp b/libs/math/include/nil/crypto3/math/static_matrix/math.hpp index bac90f7c8..86ca50649 100644 --- a/libs/math/include/nil/crypto3/math/static_matrix/math.hpp +++ b/libs/math/include/nil/crypto3/math/static_matrix/math.hpp @@ -230,8 +230,6 @@ namespace nil::crypto3::math { /// @private template constexpr std::tuple, std::size_t, T> gauss_jordan_impl(static_matrix m) { - // CRYPTO3_DETAIL_ASSERT_FLOATING_POINT(T) - // CRYPTO3_DETAIL_ASSERT_REAL(T) auto negligible = [](const T &v) { return v == T::zero(); }; diff --git a/libs/math/include/nil/crypto3/math/static_matrix/static_matrix.hpp b/libs/math/include/nil/crypto3/math/static_matrix/static_matrix.hpp index e6f7c9f3e..13effa639 100644 --- a/libs/math/include/nil/crypto3/math/static_matrix/static_matrix.hpp +++ b/libs/math/include/nil/crypto3/math/static_matrix/static_matrix.hpp @@ -29,8 +29,6 @@ #include #include -#include - #include #include @@ -64,8 +62,6 @@ namespace nil::crypto3::math { static_assert(sizeof...(args) == N * M, "Number of arguments must match the static_matrix size"); } - // CRYPTO3_DETAIL_ASSERT_ARITHMETIC(T) - using value_type = T; using size_type = std::size_t; constexpr static const size_type column_size = N; ///< Number of rows diff --git a/libs/pubkey/include/nil/crypto3/detail/type_traits.hpp b/libs/pubkey/include/nil/crypto3/detail/type_traits.hpp index 1a5427f65..d541defba 100644 --- a/libs/pubkey/include/nil/crypto3/detail/type_traits.hpp +++ b/libs/pubkey/include/nil/crypto3/detail/type_traits.hpp @@ -296,44 +296,16 @@ namespace nil { GENERATE_HAS_MEMBER_TYPE(extension_policy) - GENERATE_HAS_MEMBER_TYPE(curve_type) - - GENERATE_HAS_MEMBER_TYPE(underlying_field_type) - GENERATE_HAS_MEMBER_TYPE(value_type) GENERATE_HAS_MEMBER_TYPE(integral_type) - GENERATE_HAS_MEMBER_TYPE(base_field_type) - - GENERATE_HAS_MEMBER_TYPE(number_type) - - GENERATE_HAS_MEMBER_TYPE(scalar_field_type) - - GENERATE_HAS_MEMBER_TYPE(g1_type) - - GENERATE_HAS_MEMBER_TYPE(g2_type) - - GENERATE_HAS_MEMBER_TYPE(gt_type) - GENERATE_HAS_MEMBER(value_bits) GENERATE_HAS_MEMBER(modulus_bits) - GENERATE_HAS_MEMBER(base_field_bits) - - GENERATE_HAS_MEMBER(base_field_modulus) - - GENERATE_HAS_MEMBER(scalar_field_bits) - - GENERATE_HAS_MEMBER(scalar_field_modulus) - GENERATE_HAS_MEMBER(arity) - GENERATE_HAS_MEMBER(p) - - GENERATE_HAS_MEMBER(q) - GENERATE_HAS_MEMBER_FUNCTION(to_affine_coordinates) GENERATE_HAS_MEMBER_FUNCTION(to_special) @@ -419,41 +391,6 @@ namespace nil { typedef T type; }; - template - struct is_curve { - static const bool value = - has_base_field_bits::value && has_base_field_type::value && has_number_type::value && - has_base_field_modulus::value && has_scalar_field_bits::value && - has_scalar_field_type::value && has_scalar_field_modulus::value && has_g1_type::value && - has_g2_type::value && has_gt_type::value && has_p::value && has_q::value; - typedef T type; - }; - - template // TODO: we should add some other params to curve group policy to identify it more - // clearly - struct is_curve_group { - static const bool value = has_value_type::value && has_underlying_field_type::value && - has_value_bits::value && has_curve_type::value; - typedef T type; - }; - - template - struct is_complex : std::false_type { }; - template - struct is_complex> : std::true_type { }; - template - constexpr bool is_complex_v = is_complex::value; - - template - struct remove_complex { - using type = T; - }; - template - struct remove_complex> { - using type = T; - }; - template - using remove_complex_t = typename remove_complex::type; } // namespace detail } // namespace crypto3 } // namespace nil diff --git a/libs/random/include/nil/crypto3/random/algebraic_engine.hpp b/libs/random/include/nil/crypto3/random/algebraic_engine.hpp index 113ae5b8c..90460d8b9 100644 --- a/libs/random/include/nil/crypto3/random/algebraic_engine.hpp +++ b/libs/random/include/nil/crypto3/random/algebraic_engine.hpp @@ -300,11 +300,8 @@ namespace nil { }; template - struct algebraic_engine< - AlgebraicType, - Engine, - typename std::enable_if::value && - boost::is_integral::value>::type> { + requires algebra::CurveGroup && boost::is_integral::value + struct algebraic_engine { protected: typedef AlgebraicType group_type; typedef typename group_type::value_type group_value_type; diff --git a/libs/random/include/nil/crypto3/random/algebraic_random_device.hpp b/libs/random/include/nil/crypto3/random/algebraic_random_device.hpp index 3a13a3292..629b0bb70 100644 --- a/libs/random/include/nil/crypto3/random/algebraic_random_device.hpp +++ b/libs/random/include/nil/crypto3/random/algebraic_random_device.hpp @@ -135,9 +135,8 @@ namespace nil { internal_generator_type gen; }; - template - struct algebraic_random_device< - AlgebraicType, typename std::enable_if::value>::type> { + template + struct algebraic_random_device { protected: typedef AlgebraicType group_type; typedef typename group_type::value_type group_value_type; diff --git a/libs/zk/include/nil/crypto3/zk/transcript/fiat_shamir.hpp b/libs/zk/include/nil/crypto3/zk/transcript/fiat_shamir.hpp index 52d308c93..cdb30f68e 100644 --- a/libs/zk/include/nil/crypto3/zk/transcript/fiat_shamir.hpp +++ b/libs/zk/include/nil/crypto3/zk/transcript/fiat_shamir.hpp @@ -149,9 +149,8 @@ namespace nil { } template - typename std::enable_if_t::value && - !algebra::FieldValue> - operator()(const InputRange &r) { + requires(!algebra::CurveElement && !algebra::FieldValue) + void operator()(const InputRange &r) { auto acc_convertible = hash(state); state = accumulators::extract::hash( hash(r, static_cast &>(acc_convertible))); @@ -165,8 +164,8 @@ namespace nil { } template - typename std::enable_if_t::value || algebra::FieldValue> - operator()(element const &data) { + requires(algebra::CurveElement || algebra::FieldValue) + void operator()(element const &data) { nil::marshalling::status_type status; std::vector byte_data = nil::marshalling::pack(data, status); @@ -282,14 +281,14 @@ namespace nil { } template - typename std::enable_if_t::value> - operator()(const InputRange &r) { + requires(!algebra::CurveElement) + void operator()(const InputRange &r) { absorb(static_cast(hash(r))); } template - typename std::enable_if_t::value> - operator()(element const &data) { + requires algebra::CurveElement + void operator()(element const &data) { auto affine = data.to_affine(); absorb(affine.X); absorb(affine.Y);