From 2ac117de78e68be8b859218cee11d86389edeef9 Mon Sep 17 00:00:00 2001 From: Vasiliy Olekhov Date: Thu, 12 Sep 2024 18:02:37 +0300 Subject: [PATCH] Finished with marshalling of all supported curves #318 --- .../marshalling/algebra/processing/bls12.hpp | 81 +++++++- .../algebra/processing/secp_k1.hpp | 2 +- .../algebra/processing/secp_r1.hpp | 190 ++++++++++++++++++ .../algebra/test/curve_element.cpp | 33 +-- 4 files changed, 273 insertions(+), 33 deletions(-) create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_r1.hpp diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp index 7182a5512..5b821ee01 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp @@ -28,10 +28,6 @@ #define CRYPTO3_MARSHALLING_PROCESSING_BLS12_CURVE_ELEMENT_HPP #include -#include -#include -#include -#include #include #include @@ -50,6 +46,75 @@ namespace nil { namespace marshalling { namespace processing { + + /* Specialization for bls12_377::g2_type */ + template + struct curve_element_marshalling_params > + { + using group_type = algebra::curves::bls12_381::template + g2_type; + + static constexpr std::size_t length() { + return bit_length() / 8 + ((bit_length() % 8) != 0); + } + + static constexpr std::size_t min_length() { + return length(); + } + + static constexpr std::size_t max_length() { + return length(); + } + + static constexpr std::size_t bit_length() { + constexpr std::size_t modulus_bits_round_up = (group_type::field_type::modulus_bits + 7) & ~7; + return modulus_bits_round_up * group_type::field_type::arity; + } + + static constexpr std::size_t min_bit_length() { + return bit_length(); + } + + static constexpr std::size_t max_bit_length() { + return bit_length(); + } + }; + + /* Specialization for bls12_381::g2_type */ + template + struct curve_element_marshalling_params > + { + using group_type = algebra::curves::bls12_381::template + g2_type; + + static constexpr std::size_t length() { + return bit_length() / 8 + ((bit_length() % 8) != 0); + } + + static constexpr std::size_t min_length() { + return length(); + } + + static constexpr std::size_t max_length() { + return length(); + } + + static constexpr std::size_t bit_length() { + constexpr std::size_t modulus_bits_round_up = (group_type::field_type::modulus_bits + 7) & ~7; + return modulus_bits_round_up * group_type::field_type::arity; + } + + static constexpr std::size_t min_bit_length() { + return bit_length(); + } + + static constexpr std::size_t max_bit_length() { + return bit_length(); + } + }; + template struct curve_element_writer< Endianness, @@ -263,7 +328,7 @@ namespace nil { integral_type x = read_data(iter); g1_field_value_type x_mod(x); - g1_field_value_type y2_mod = x_mod.pow(3u) + g1_field_value_type(4u); + g1_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b; BOOST_ASSERT(y2_mod.is_square()); g1_field_value_type y_mod = y2_mod.sqrt(); bool Y_bit = detail::sign_gf_p(y_mod); @@ -330,7 +395,7 @@ namespace nil { integral_type x_0 = read_data(read_iter); g2_field_value_type x_mod(x_0, x_1); - g2_field_value_type y2_mod = x_mod.pow(3u) + g2_field_value_type(4u, 4u); + g2_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b; BOOST_ASSERT(y2_mod.is_square()); g2_field_value_type y_mod = y2_mod.sqrt(); bool Y_bit = detail::sign_gf_p(y_mod); @@ -392,7 +457,7 @@ namespace nil { integral_type x = read_data(iter); g1_field_value_type x_mod(x); - g1_field_value_type y2_mod = x_mod.pow(3u) + g1_field_value_type(4u); + g1_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b; BOOST_ASSERT(y2_mod.is_square()); g1_field_value_type y_mod = y2_mod.sqrt(); bool Y_bit = detail::sign_gf_p(y_mod); @@ -459,7 +524,7 @@ namespace nil { integral_type x_0 = read_data(read_iter); g2_field_value_type x_mod(x_0, x_1); - g2_field_value_type y2_mod = x_mod.pow(3u) + g2_field_value_type(4u, 4u); + g2_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b; BOOST_ASSERT(y2_mod.is_square()); g2_field_value_type y_mod = y2_mod.sqrt(); bool Y_bit = detail::sign_gf_p(y_mod); diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp index 30a75632f..0ab5ca6d4 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp @@ -187,4 +187,4 @@ namespace nil { } // namespace marshalling } // namespace crypto3 } // namespace nil -#endif // CRYPTO3_MARSHALLING_PROCESSING_secp_k1_CURVE_ELEMENT_HPP +#endif // CRYPTO3_MARSHALLING_PROCESSING_SECP_K1_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_r1.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_r1.hpp new file mode 100644 index 000000000..bccaa173a --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_r1.hpp @@ -0,0 +1,190 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2024 Vasiliy Olekhov +// +// 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_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + template + struct curve_element_marshalling_params< + typename algebra::curves::detail::secp_r1_g1< + Version, + algebra::curves::forms::short_weierstrass, + algebra::curves::coordinates::projective> + > { + using group_type = typename algebra::curves::secp_r1::template g1_type<>; + + static constexpr std::size_t length() { + return 1 + bit_length() / 8 + ((bit_length() % 8) != 0); + } + + static constexpr std::size_t min_length() { + return length(); + } + + static constexpr std::size_t max_length() { + return length(); + } + + static constexpr std::size_t bit_length() { + return group_type::field_type::value_bits; + } + + static constexpr std::size_t min_bit_length() { + return bit_length(); + } + + static constexpr std::size_t max_bit_length() { + return bit_length(); + } + }; + + /* + * Encoding of elliptic curve point according to https://www.secg.org/sec1-v2.pdf + * Curve must be in short weierstrass form, Y^2 = X^3 + A*X + B + * Only X coordinate is encoded, prefixed with either 02 or 03 depending on whether Y is even or odd + * The encoding is big-endian + * Infinity is encoded as 00 + * */ + template + struct curve_element_writer< + nil::marshalling::endian::big_endian, + typename algebra::curves::detail::secp_r1_g1< + Version, + algebra::curves::forms::short_weierstrass, + algebra::curves::coordinates::projective> > { + using group_type = typename algebra::curves::secp_r1::template g1_type<>; + using group_value_type = typename group_type::value_type; + using coordinates = typename group_value_type::coordinates; + using form = typename group_value_type::form; + using endianness = nil::marshalling::endian::big_endian; + using params_type = curve_element_marshalling_params; + + template + static typename std::enable_if< + std::is_same::value_type>::value, + nil::marshalling::status_type>::type + process(const group_value_type &point, TIter &iter) + { + if (point.is_zero()) { + *iter++ = 0x00; + return nil::marshalling::status_type::success; + } + typename group_type::curve_type::template g1_type::value_type + point_affine = point.to_affine(); + + *iter++ = (point_affine.Y.data & 1) == 0u ? 0x02 : 0x03; + write_data( + static_cast(point_affine.X.data), + iter); + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::detail::secp_r1_g1> { + + using group_type = typename algebra::curves::secp_r1::template g1_type<>; + using group_value_type = typename group_type::value_type; + using coordinates = typename group_value_type::coordinates; + using form = typename group_value_type::form; + using endianness = nil::marshalling::endian::big_endian; + using params_type = curve_element_marshalling_params; + using curve_params = typename group_type::params_type; + using integral_type = typename group_value_type::field_type::integral_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + + template + static typename std::enable_if< + std::is_same::value_type>::value, + nil::marshalling::status_type>::type + process(group_value_type &point, TIter &iter) + { + using chunk_type = typename TIter::value_type; + + const chunk_type prefix = *iter++; + + if (0x00 == prefix) { + point = group_value_type::zero(); + return nil::marshalling::status_type::success; + } + + if (prefix != 0x02 && prefix != 0x03) { + return nil::marshalling::status_type::invalid_msg_data; + } + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + integral_type x = read_data(iter); + + g1_field_value_type x_mod(x); + g1_field_value_type y2_mod = x_mod * x_mod * x_mod + curve_params::a * x_mod + curve_params::b; + if (!y2_mod.is_square()) { + return nil::marshalling::status_type::invalid_msg_data; + } + + g1_field_value_type y_mod = y2_mod.sqrt(); + + const chunk_type expected_prefix = (y_mod.data & 1) == 0u ? 0x02 : 0x03; + + if (expected_prefix == prefix) { + point = group_value_type(x_mod, y_mod); + } else { + point = group_value_type(x_mod, -y_mod); + } + + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/test/curve_element.cpp b/libs/marshalling/algebra/test/curve_element.cpp index 81972c08f..982b635d8 100644 --- a/libs/marshalling/algebra/test/curve_element.cpp +++ b/libs/marshalling/algebra/test/curve_element.cpp @@ -83,7 +83,7 @@ #include #include -//#include +#include template void test_group_element(T val) { @@ -104,28 +104,10 @@ void test_group_element(T val) { std::vector cv = nil::marshalling::pack(val, status); BOOST_CHECK(status == nil::marshalling::status_type::success); - std::cout << "Value: " << std::hex << val.to_affine() << std::endl; - - /* */ - std::cout << "Serialized as " << cv.size() << " bytes:" << std::endl; - for(auto &x: cv) { - std::cout << std::hex << std::setw(2) << std::setfill('0'); - std::cout << (int)x; - } - std::cout << std::endl; - /* */ - T test_val = nil::marshalling::pack(cv, status); BOOST_CHECK(status == nil::marshalling::status_type::success); BOOST_CHECK_EQUAL(val.to_affine(), test_val.to_affine()); - if (val == test_val) { - std::cout << ""; - } else { - std::cout << "Deserialized: " << std::endl << std::hex << test_val.to_affine() << std::endl; - std::cout << ""; - } - std::cout << "========================" << std::endl; } template @@ -196,7 +178,7 @@ BOOST_AUTO_TEST_CASE(curve_element_bls12_381) { BOOST_AUTO_TEST_CASE(curve_element_bls12_377) { // it freezes -// test_pairing_curve("bls12_377"); + test_pairing_curve("bls12_377"); } BOOST_AUTO_TEST_CASE(curve_element_bn254) { @@ -211,16 +193,19 @@ BOOST_AUTO_TEST_CASE(curve_element_vesta) { test_curve("vesta"); } -// TODO: implement marshalling for secp_k1/secp_r1 curves BOOST_AUTO_TEST_CASE(curve_element_secp_k1) { test_curve, big_endian>("secp_k1<160>"); + test_curve, big_endian>("secp_k1<192>"); + test_curve, big_endian>("secp_k1<224>"); + test_curve, big_endian>("secp_k1<256>"); } -#if 0 BOOST_AUTO_TEST_CASE(curve_element_secp_r1) { - test_curve>("secp_r1<160>"); + test_curve, big_endian>("secp_r1<160>"); + test_curve, big_endian>("secp_r1<192>"); + test_curve, big_endian>("secp_r1<224>"); + test_curve, big_endian>("secp_r1<256>"); } -#endif BOOST_AUTO_TEST_CASE(curve_element_jubjub) { test_curve("jubjub");