From cfbe84fc986cf8d4e3855a3da968187a85237b9e Mon Sep 17 00:00:00 2001 From: Vasiliy Olekhov Date: Tue, 3 Sep 2024 12:28:33 +0300 Subject: [PATCH] work in progress on implementing the marshalling #318 --- .../nil/crypto3/algebra/curves/curve25519.hpp | 2 +- .../algebra/curves/detail/babyjubjub/g1.hpp | 1 - .../algebra/curves/detail/curve25519/g1.hpp | 1 - .../algebra/processing/alt_bn128.hpp | 284 ++++ .../algebra/processing/babyjubjub.hpp | 171 +++ .../marshalling/algebra/processing/bls12.hpp | 484 +++++++ .../algebra/processing/curve_element.hpp | 1159 +---------------- .../processing/detail/curve_element.hpp | 17 +- .../algebra/processing/ed25519.hpp | 161 +++ .../marshalling/algebra/processing/jubjub.hpp | 150 +++ .../marshalling/algebra/processing/mnt4.hpp | 312 +++++ .../marshalling/algebra/processing/mnt6.hpp | 323 +++++ .../marshalling/algebra/processing/pallas.hpp | 186 +++ .../algebra/processing/secp_k1.hpp | 186 +++ .../marshalling/algebra/processing/vesta.hpp | 186 +++ .../algebra/test/curve_element.cpp | 114 +- 16 files changed, 2524 insertions(+), 1213 deletions(-) create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/alt_bn128.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/babyjubjub.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/ed25519.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/jubjub.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt4.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt6.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/pallas.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp create mode 100644 libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/vesta.hpp diff --git a/libs/algebra/include/nil/crypto3/algebra/curves/curve25519.hpp b/libs/algebra/include/nil/crypto3/algebra/curves/curve25519.hpp index 38395ffd3..6fbae6d14 100644 --- a/libs/algebra/include/nil/crypto3/algebra/curves/curve25519.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/curves/curve25519.hpp @@ -46,7 +46,7 @@ namespace nil { typedef typename policy_type::scalar_field_type scalar_field_type; template + typename Form = forms::twisted_edwards> using g1_type = typename detail::curve25519_g1; }; } // namespace curves diff --git a/libs/algebra/include/nil/crypto3/algebra/curves/detail/babyjubjub/g1.hpp b/libs/algebra/include/nil/crypto3/algebra/curves/detail/babyjubjub/g1.hpp index 3a429a479..ff014051e 100644 --- a/libs/algebra/include/nil/crypto3/algebra/curves/detail/babyjubjub/g1.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/curves/detail/babyjubjub/g1.hpp @@ -31,7 +31,6 @@ #include #include -#include namespace nil { namespace crypto3 { diff --git a/libs/algebra/include/nil/crypto3/algebra/curves/detail/curve25519/g1.hpp b/libs/algebra/include/nil/crypto3/algebra/curves/detail/curve25519/g1.hpp index b445a2402..cbaed496c 100644 --- a/libs/algebra/include/nil/crypto3/algebra/curves/detail/curve25519/g1.hpp +++ b/libs/algebra/include/nil/crypto3/algebra/curves/detail/curve25519/g1.hpp @@ -31,7 +31,6 @@ #include #ifdef __ZKLLVM__ #else -// #include #include #endif diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/alt_bn128.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/alt_bn128.hpp new file mode 100644 index 000000000..ae71759f6 --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/alt_bn128.hpp @@ -0,0 +1,284 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_ALT_BN128_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_ALT_BN128_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_writer< + nil::marshalling::endian::big_endian, + typename algebra::curves::alt_bn128_254::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::alt_bn128_254:: + template g1_type; + using group_value_type = typename group_type::value_type; + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is always encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + + auto point_affine = point.to_affine(); + + write_data( + static_cast(point_affine.X.data), + iter); + + if (point_affine.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_writer< + nil::marshalling::endian::big_endian, + typename algebra::curves::alt_bn128_254::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::alt_bn128_254:: + template g2_type; + using group_value_type = typename group_type::value_type; + using g2_value_type = group_value_type; + using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is always encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + typename group_type::curve_type::template g2_type< + typename algebra::curves::coordinates::affine, + form>::value_type point_affine = point.to_affine(); + + TIter write_iter = iter; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[1].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[0].data), + write_iter); + + if(point.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::alt_bn128_254::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::alt_bn128_254:: + 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + using integral_type = typename g1_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + integral_type x = read_data(iter); + + if (I_bit) { + // point at infinity + point = g1_value_type(); + return nil::marshalling::status_type::success; + } + + g1_field_value_type x_mod(x); + g1_field_value_type y2_mod = x_mod.pow(3) + 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); + if (Y_bit == bool(S_bit)) { + g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::alt_bn128_254::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::alt_bn128_254:: + template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g2_value_type = group_value_type; + using g2_field_type = typename g2_value_type::field_type; + using g2_field_value_type = typename g2_field_type::value_type; + using integral_type = typename g2_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + TIter read_iter = iter; + integral_type x_1 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + integral_type x_0 = read_data(read_iter); + + if (I_bit) { + // point at infinity + point = group_value_type(); + return nil::marshalling::status_type::success; + } + + g2_field_value_type x_mod(x_0, x_1); + g2_field_value_type y2_mod = x_mod.pow(3) + 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); + if (Y_bit == bool(S_bit)) { + g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/babyjubjub.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/babyjubjub.hpp new file mode 100644 index 000000000..76e3ce76d --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/babyjubjub.hpp @@ -0,0 +1,171 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_BABYJUBJUB_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_BABYJUBJUB_CURVE_ELEMENT_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include + + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + // Encoding of babyjubjub curve as described in Nocturne: + // https://nocturne-xyz.gitbook.io/nocturne/protocol-details/encodings + // Only Y coordinate is encoded, plus 's' - the "sign" of X coordinate + // uint256(signBit) << 254 | y + // TODO: update reference or invent our own rules + + template + struct curve_element_writer< + nil::marshalling::endian::little_endian, + typename algebra::curves::babyjubjub::template g1_type> { + using group_type = + typename algebra::curves::babyjubjub::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::little_endian; + using params_type = curve_element_marshalling_params; + using encoded_integral_type = typename algebra::fields::field<256>::integral_type; + + 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) { + using base_field_type = typename group_type::field_type; + using base_integral_type = typename base_field_type::integral_type; + + constexpr std::size_t encoded_size = 32; + using encoded_value_type = std::array; + encoded_value_type encoded_value {0}; + + auto point_affine = point.to_affine(); + + /* Zero point is encoded as (0,1) */ + if (point.is_zero()) { + point_affine.Y = 1u; + point_affine.X = 0u; + } + + uint8_t s = detail::sign_gf_p(point_affine.X) ? (0x40) : 0; + + auto tmp_iter = std::begin(encoded_value); + write_data(static_cast(point_affine.Y.data), + tmp_iter); + assert(!(encoded_value[encoded_size - 1] & 0xC0)); + + encoded_value[encoded_size - 1] |= s; + + std::copy(std::cbegin(encoded_value), std::cend(encoded_value), iter); + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_reader< + nil::marshalling::endian::little_endian, + typename algebra::curves::babyjubjub::template g1_type> { + using group_type = + typename algebra::curves::babyjubjub::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::little_endian; + using params_type = curve_element_marshalling_params; + + using group_affine_value_type = + typename algebra::curves::babyjubjub::g1_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) + { + + // somehow add size check of container pointed by iter + // assert(TSize == std::distance(first, last)); + using base_field_type = typename group_type::field_type; + using base_integral_type = typename base_field_type::integral_type; + using group_affine_value_type = + typename algebra::curves::babyjubjub::g1_type::value_type; + constexpr std::size_t encoded_size = 32; + static_assert(encoded_size == + (params_type::bit_length() / 8 + (params_type::bit_length() % 8 ? 1 : 0)), + "wrong size"); + + base_integral_type y = + read_data(iter); + bool sign = *(iter + encoded_size - 1) & (1 << 6); + + auto decoded_point_affine = + detail::recover_x(y, sign); + + if (!decoded_point_affine) { + return decoded_point_affine.error(); + } + + // TODO: remove hard-coded call for type conversion, implement type conversion between + // coordinates + // through operator + point = decoded_point_affine.value(); + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_BABYJUBJUB_CURVE_ELEMENT_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 new file mode 100644 index 000000000..7182a5512 --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/bls12.hpp @@ -0,0 +1,484 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_BLS12_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_BLS12_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_writer< + Endianness, + typename algebra::curves::bls12_381::template g1_type> { + using group_type = typename algebra::curves::bls12_381:: + 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 = Endianness; + using params_type = curve_element_marshalling_params; + + template + static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const chunk_type I_bit = 0x40; + typename group_type::curve_type::template g1_type::value_type point_affine = + point.to_affine(); + chunk_type m_unit = detail::evaluate_m_unit(point, true); + if (!(I_bit & m_unit)) { + // We assume here, that write_data doesn't change the iter + write_data( + static_cast(point_affine.X.data), + iter); + } + (*iter) |= m_unit; + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_writer< + Endianness, + typename algebra::curves::bls12_381::template g2_type> { + using group_type = typename algebra::curves::bls12_381:: + template g2_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 = Endianness; + using params_type = curve_element_marshalling_params; + + template + static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + + constexpr static const chunk_type I_bit = 0x40; + typename group_type::curve_type::template g2_type::value_type point_affine = + point.to_affine(); + chunk_type m_unit = detail::evaluate_m_unit(point, true); + if (!(I_bit & m_unit)) { + TIter write_iter = iter; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[1].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[0].data), + write_iter); + } + (*iter) |= m_unit; + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_writer< + Endianness, + typename algebra::curves::bls12_377::template g1_type> { + using group_type = typename algebra::curves::bls12_377:: + 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 = Endianness; + using params_type = curve_element_marshalling_params; + + template + static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const chunk_type I_bit = 0x40; + typename group_type::curve_type::template g1_type::value_type point_affine = + point.to_affine(); + chunk_type m_unit = detail::evaluate_m_unit(point, true); + if (!(I_bit & m_unit)) { + // We assume here, that write_data doesn't change the iter + write_data( + static_cast(point_affine.X.data), + iter); + } + (*iter) |= m_unit; + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_writer< + Endianness, + typename algebra::curves::bls12_377::template g2_type> { + using group_type = typename algebra::curves::bls12_377:: + template g2_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 = Endianness; + using params_type = curve_element_marshalling_params; + + template + static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + + constexpr static const chunk_type I_bit = 0x40; + typename group_type::curve_type::template g2_type::value_type point_affine = + point.to_affine(); + chunk_type m_unit = detail::evaluate_m_unit(point, true); + if (!(I_bit & m_unit)) { + TIter write_iter = iter; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[1].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[0].data), + write_iter); + } + (*iter) |= m_unit; + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::bls12_381::template g1_type> { + using group_type = typename algebra::curves::bls12_381:: + 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + const chunk_type m_unit = *iter & 0xE0; + BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + using integral_type = typename g1_value_type::field_type::integral_type; + + constexpr static const chunk_type I_bit = 0x40; + constexpr static const chunk_type S_bit = 0x20; + + if (m_unit & I_bit) { + BOOST_VERIFY(iter + sizeof_field_element_chunks_count == + std::find(iter, iter + sizeof_field_element_chunks_count, true)); + point = g1_value_type(); // point at infinity + return nil::marshalling::status_type::success; + } + + 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); + BOOST_ASSERT(y2_mod.is_square()); + g1_field_value_type y_mod = y2_mod.sqrt(); + bool Y_bit = detail::sign_gf_p(y_mod); + if (Y_bit == bool(m_unit & S_bit)) { + g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::bls12_381::template g2_type> { + using group_type = typename algebra::curves::bls12_381:: + template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + const chunk_type m_unit = *iter & 0xE0; + BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g2_value_type = group_value_type; + using g2_field_type = typename g2_value_type::field_type; + using g2_field_value_type = typename g2_field_type::value_type; + using integral_type = typename g2_value_type::field_type::integral_type; + + constexpr static const chunk_type I_bit = 0x40; + constexpr static const chunk_type S_bit = 0x20; + + if (m_unit & I_bit) { + BOOST_ASSERT(iter + 2 * sizeof_field_element_chunks_count == + std::find(iter, iter + 2 * sizeof_field_element_chunks_count, true)); + point = g2_value_type(); // point at infinity + return nil::marshalling::status_type::success; + } + + TIter read_iter = iter; + + integral_type x_1 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + + 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); + BOOST_ASSERT(y2_mod.is_square()); + g2_field_value_type y_mod = y2_mod.sqrt(); + bool Y_bit = detail::sign_gf_p(y_mod); + if (Y_bit == bool(m_unit & S_bit)) { + g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::bls12_377::template g1_type> { + using group_type = typename algebra::curves::bls12_377:: + 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + const chunk_type m_unit = *iter & 0xE0; + BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + using integral_type = typename g1_value_type::field_type::integral_type; + + constexpr static const chunk_type I_bit = 0x40; + constexpr static const chunk_type S_bit = 0x20; + + if (m_unit & I_bit) { + BOOST_VERIFY(iter + sizeof_field_element_chunks_count == + std::find(iter, iter + sizeof_field_element_chunks_count, true)); + point = g1_value_type(); // point at infinity + return nil::marshalling::status_type::success; + } + + 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); + BOOST_ASSERT(y2_mod.is_square()); + g1_field_value_type y_mod = y2_mod.sqrt(); + bool Y_bit = detail::sign_gf_p(y_mod); + if (Y_bit == bool(m_unit & S_bit)) { + g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::bls12_377::template g2_type> { + using group_type = typename algebra::curves::bls12_377:: + template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + const chunk_type m_unit = *iter & 0xE0; + BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g2_value_type = group_value_type; + using g2_field_type = typename g2_value_type::field_type; + using g2_field_value_type = typename g2_field_type::value_type; + using integral_type = typename g2_value_type::field_type::integral_type; + + constexpr static const chunk_type I_bit = 0x40; + constexpr static const chunk_type S_bit = 0x20; + + if (m_unit & I_bit) { + BOOST_ASSERT(iter + 2 * sizeof_field_element_chunks_count == + std::find(iter, iter + 2 * sizeof_field_element_chunks_count, true)); + point = g2_value_type(); // point at infinity + return nil::marshalling::status_type::success; + } + + TIter read_iter = iter; + + integral_type x_1 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + + 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); + BOOST_ASSERT(y2_mod.is_square()); + g2_field_value_type y_mod = y2_mod.sqrt(); + bool Y_bit = detail::sign_gf_p(y_mod); + if (Y_bit == bool(m_unit & S_bit)) { + g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/curve_element.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/curve_element.hpp index a792f811f..12d3a0b04 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/curve_element.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/curve_element.hpp @@ -1,6 +1,7 @@ //---------------------------------------------------------------------------// // Copyright (c) 2017-2021 Mikhail Komarov // Copyright (c) 2020-2021 Nikita Kaskov +// Copyright (c) 2024 Vasiliy Olekhov // // MIT License // @@ -37,13 +38,6 @@ #include -#include -#include -#include -#include -#include -#include - #include #include @@ -83,73 +77,6 @@ namespace nil { } }; - /* Specialization for mnt4_298::g2_type */ - template - struct curve_element_marshalling_params > - { - using group_type = algebra::curves::mnt4_298::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 mnt6_298::g2_type */ - template - struct curve_element_marshalling_params > - { - using group_type = algebra::curves::mnt6_298::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(); - } - }; // TODO: do not specify marshalling algorithm by curve group, instead specify marshalling procedure only // by form, coordinates and specification policy @@ -161,1090 +88,6 @@ namespace nil { template struct curve_element_reader; - template - struct curve_element_writer< - Endianness, - typename algebra::curves::bls12_381::template g1_type> { - using group_type = typename algebra::curves::bls12_381:: - 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 = Endianness; - using params_type = curve_element_marshalling_params; - - template - static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const chunk_type I_bit = 0x40; - typename group_type::curve_type::template g1_type::value_type point_affine = - point.to_affine(); - chunk_type m_unit = detail::evaluate_m_unit(point, true); - if (!(I_bit & m_unit)) { - // We assume here, that write_data doesn't change the iter - write_data( - static_cast(point_affine.X.data), - iter); - } - (*iter) |= m_unit; - - return nil::marshalling::status_type::success; - } - }; - - - template - struct curve_element_writer< - Endianness, - typename algebra::curves::bls12_381::template g2_type> { - using group_type = typename algebra::curves::bls12_381:: - template g2_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 = Endianness; - using params_type = curve_element_marshalling_params; - - template - static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - - constexpr static const chunk_type I_bit = 0x40; - typename group_type::curve_type::template g2_type::value_type point_affine = - point.to_affine(); - chunk_type m_unit = detail::evaluate_m_unit(point, true); - if (!(I_bit & m_unit)) { - TIter write_iter = iter; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[1].data), - write_iter); - write_iter += sizeof_field_element_chunks_count; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[0].data), - write_iter); - } - (*iter) |= m_unit; - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::alt_bn128_254::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::alt_bn128_254:: - template g1_type; - using group_value_type = typename group_type::value_type; - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is always encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - - auto point_affine = point.to_affine(); - - write_data( - static_cast(point_affine.X.data), - iter); - - if (point_affine.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::alt_bn128_254::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::alt_bn128_254:: - template g2_type; - using group_value_type = typename group_type::value_type; - using g2_value_type = group_value_type; - using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is always encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - typename group_type::curve_type::template g2_type< - typename algebra::curves::coordinates::affine, - form>::value_type point_affine = point.to_affine(); - - TIter write_iter = iter; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[1].data), - write_iter); - write_iter += sizeof_field_element_chunks_count; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[0].data), - write_iter); - - if(point.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt4_298::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt4_298:: - template g1_type; - using group_value_type = typename group_type::value_type; - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - - auto point_affine = point.to_affine(); - - write_data( - static_cast(point_affine.X.data), - iter); - - if (point_affine.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt4_298::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt4_298:: - template g2_type; - using group_value_type = typename group_type::value_type; - using g2_value_type = group_value_type; - using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is always encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - auto point_affine = point.to_affine(); - - TIter write_iter = iter; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[1].data), - write_iter); - write_iter += sizeof_field_element_chunks_count; - // We assume here, that write_data doesn't change the iter - write_data( - static_cast( - point_affine.X.data[0].data), - write_iter); - if(point.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt6_298::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt6_298:: - template g1_type; - using group_value_type = typename group_type::value_type; - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - - auto point_affine = point.to_affine(); - - write_data( - static_cast(point_affine.X.data), - iter); - - if (point_affine.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt6_298::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt6_298:: - template g2_type; - using group_value_type = typename group_type::value_type; - using g2_value_type = group_value_type; - using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { - - /* Point is always encoded in compressed form, only X coordinate. - * Highest bit is Infinity flag - * Second highest bit is sign of Y coordinate */ - - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - - constexpr static const chunk_type I_bit = 0x80; - constexpr static const chunk_type S_bit = 0x40; - auto point_affine = point.to_affine(); - - TIter write_iter = iter; - write_data( - static_cast( - point_affine.X.data[2].data), - write_iter); - write_iter += sizeof_field_element_chunks_count; - - write_data( - static_cast( - point_affine.X.data[1].data), - write_iter); - write_iter += sizeof_field_element_chunks_count; - - write_data( - static_cast( - point_affine.X.data[0].data), - write_iter); - - if(point.is_zero()) { - *iter |= I_bit; - } - - if (detail::sign_gf_p(point_affine.Y)) { - *iter |= S_bit; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::little_endian, - typename algebra::curves::curve25519::template g1_type> { - using group_type = - typename algebra::curves::curve25519::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::little_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) { - using base_field_type = typename group_type::field_type; - using base_integral_type = typename base_field_type::integral_type; - using group_affine_value_type = - typename algebra::curves::curve25519::g1_type::value_type; - // TODO: somehow add size check of container pointed by iter - constexpr std::size_t encoded_size = 32; - static_assert(encoded_size == - (params_type::bit_length() / 8 + (params_type::bit_length() % 8 ? 1 : 0)), - "wrong size"); - using encoded_value_type = std::array; - - group_affine_value_type point_affine = point.to_affine(); - // TODO: remove crating of temporary array encoded_value - encoded_value_type encoded_value {0}; - // TODO: remove lvalue iterator - auto tmp_iter = std::begin(encoded_value); - write_data(static_cast(point_affine.Y.data), - tmp_iter); - // TODO: throw catchable error, for example return status - assert(!(encoded_value[encoded_size - 1] & 0x80)); - encoded_value[encoded_size - 1] |= - (static_cast(static_cast(point_affine.X.data) & 1) << 7); - - std::copy(std::cbegin(encoded_value), std::cend(encoded_value), iter); - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_writer< - nil::marshalling::endian::little_endian, - typename algebra::curves::jubjub::template g1_type> { - using group_type = - typename algebra::curves::jubjub::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::little_endian; - using params_type = curve_element_marshalling_params; - - /// https://zips.z.cash/protocol/protocol.pdf#concreteextractorjubjub - template - static nil::marshalling::status_type - process(const group_value_type &point, TIter &iter) { - write_data( - static_cast(point.to_affine().X.data), - iter); - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::bls12_381::template g1_type> { - using group_type = typename algebra::curves::bls12_381:: - 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - const chunk_type m_unit = *iter & 0xE0; - BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_type; - using g1_field_value_type = typename g1_field_type::value_type; - using integral_type = typename g1_value_type::field_type::integral_type; - - constexpr static const chunk_type I_bit = 0x40; - constexpr static const chunk_type S_bit = 0x20; - - if (m_unit & I_bit) { - BOOST_VERIFY(iter + sizeof_field_element_chunks_count == - std::find(iter, iter + sizeof_field_element_chunks_count, true)); - point = g1_value_type(); // point at infinity - return nil::marshalling::status_type::success; - } - - 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); - BOOST_ASSERT(y2_mod.is_square()); - g1_field_value_type y_mod = y2_mod.sqrt(); - bool Y_bit = detail::sign_gf_p(y_mod); - if (Y_bit == bool(m_unit & S_bit)) { - g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::bls12_381::template g2_type> { - using group_type = typename algebra::curves::bls12_381:: - template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - const chunk_type m_unit = *iter & 0xE0; - BOOST_ASSERT(m_unit != 0x20 && m_unit != 0x60 && m_unit != 0xE0); - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - using g2_value_type = group_value_type; - using g2_field_type = typename g2_value_type::field_type; - using g2_field_value_type = typename g2_field_type::value_type; - using integral_type = typename g2_value_type::field_type::integral_type; - - constexpr static const chunk_type I_bit = 0x40; - constexpr static const chunk_type S_bit = 0x20; - - if (m_unit & I_bit) { - BOOST_ASSERT(iter + 2 * sizeof_field_element_chunks_count == - std::find(iter, iter + 2 * sizeof_field_element_chunks_count, true)); - point = g2_value_type(); // point at infinity - return nil::marshalling::status_type::success; - } - - TIter read_iter = iter; - - integral_type x_1 = read_data(read_iter); - read_iter += sizeof_field_element_chunks_count; - - 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); - BOOST_ASSERT(y2_mod.is_square()); - g2_field_value_type y_mod = y2_mod.sqrt(); - bool Y_bit = detail::sign_gf_p(y_mod); - if (Y_bit == bool(m_unit & S_bit)) { - g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::alt_bn128_254::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::alt_bn128_254:: - 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_type; - using g1_field_value_type = typename g1_field_type::value_type; - using integral_type = typename g1_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - integral_type x = read_data(iter); - - if (I_bit) { - // point at infinity - point = g1_value_type(); - return nil::marshalling::status_type::success; - } - - g1_field_value_type x_mod(x); - g1_field_value_type y2_mod = x_mod.pow(3) + 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); - if (Y_bit == bool(S_bit)) { - g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::alt_bn128_254::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::alt_bn128_254:: - template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - using g2_value_type = group_value_type; - using g2_field_type = typename g2_value_type::field_type; - using g2_field_value_type = typename g2_field_type::value_type; - using integral_type = typename g2_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - TIter read_iter = iter; - integral_type x_1 = read_data(read_iter); - read_iter += sizeof_field_element_chunks_count; - integral_type x_0 = read_data(read_iter); - - if (I_bit) { - // point at infinity - point = group_value_type(); - return nil::marshalling::status_type::success; - } - - g2_field_value_type x_mod(x_0, x_1); - g2_field_value_type y2_mod = x_mod.pow(3) + 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); - if (Y_bit == bool(S_bit)) { - g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt4_298::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt4_298:: - 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_type; - using g1_field_value_type = typename g1_field_type::value_type; - using integral_type = typename g1_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - integral_type x = read_data(iter); - - if (I_bit) { - // point at infinity - point = g1_value_type(); - return nil::marshalling::status_type::success; - } - - g1_field_value_type x_mod(x); - g1_field_value_type y2_mod = x_mod.pow(3) - + group_type::params_type::a * x_mod - + 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); - if (Y_bit == bool(S_bit)) { - g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt4_298::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt4_298:: - template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - using g2_value_type = group_value_type; - using g2_field_type = typename g2_value_type::field_type; - using g2_field_value_type = typename g2_field_type::value_type; - using integral_type = typename g2_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - TIter read_iter = iter; - integral_type x_1 = read_data(read_iter); - read_iter += sizeof_field_element_chunks_count; - integral_type x_0 = read_data(read_iter); - - if (I_bit) { - // point at infinity - point = group_value_type(); - return nil::marshalling::status_type::success; - } - - g2_field_value_type x_mod(x_0, x_1); - g2_field_value_type y2_mod = x_mod.pow(3) - + group_type::params_type::a * x_mod - + 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); - if (Y_bit == bool(S_bit)) { - g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt6_298::template g1_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt6_298:: - 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - using g1_value_type = group_value_type; - using g1_field_type = typename group_value_type::field_type; - using g1_field_value_type = typename g1_field_type::value_type; - using integral_type = typename g1_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - integral_type x = read_data(iter); - - if (I_bit) { - // point at infinity - point = g1_value_type(); - return nil::marshalling::status_type::success; - } - - g1_field_value_type x_mod(x); - g1_field_value_type y2_mod = x_mod.pow(3) - + group_type::params_type::a * x_mod - + 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); - if (Y_bit == bool(S_bit)) { - g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::big_endian, - typename algebra::curves::mnt6_298::template g2_type< - Coordinates, - algebra::curves::forms::short_weierstrass>> { - using group_type = typename algebra::curves::mnt6_298:: - template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { - using chunk_type = typename TIter::value_type; - - constexpr static const std::size_t sizeof_field_element = - params_type::bit_length() / (group_value_type::field_type::arity); - constexpr static const std::size_t units_bits = 8; - constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; - constexpr static const std::size_t sizeof_field_element_chunks_count = - (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); - using g2_value_type = group_value_type; - using g2_field_type = typename g2_value_type::field_type; - using g2_field_value_type = typename g2_field_type::value_type; - using integral_type = typename g2_value_type::field_type::integral_type; - - chunk_type I_bit = *iter & 0x80; - chunk_type S_bit = *iter & 0x40; - - TIter read_iter = iter; - integral_type x_2 = read_data(read_iter); - read_iter += sizeof_field_element_chunks_count; - integral_type x_1 = read_data(read_iter); - read_iter += sizeof_field_element_chunks_count; - integral_type x_0 = read_data(read_iter); - - if (I_bit) { - // point at infinity - point = group_value_type(); - return nil::marshalling::status_type::success; - } - - g2_field_value_type x_mod(x_0, x_1, x_2); - g2_field_value_type y2_mod = x_mod.pow(3) - + group_type::params_type::a * x_mod - + 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); - if (Y_bit == bool(S_bit)) { - g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } else { - g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); - BOOST_ASSERT(result.is_well_formed()); - point = result; - } - - return nil::marshalling::status_type::success; - } - }; - - template - struct curve_element_reader< - nil::marshalling::endian::little_endian, - typename algebra::curves::curve25519::template g1_type> { - using group_type = - typename algebra::curves::curve25519::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::little_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(group_value_type &point, TIter &iter) { - // somehow add size check of container pointed by iter - // assert(TSize == std::distance(first, last)); - using base_field_type = typename group_type::field_type; - using base_integral_type = typename base_field_type::integral_type; - using group_affine_value_type = - typename algebra::curves::curve25519::g1_type::value_type; - constexpr std::size_t encoded_size = 32; - static_assert(encoded_size == - (params_type::bit_length() / 8 + (params_type::bit_length() % 8 ? 1 : 0)), - "wrong size"); - - base_integral_type y = - read_data(iter); - bool sign = *(iter + encoded_size - 1) & (1 << 7); - - auto decoded_point_affine = - detail::recover_x(y, sign); - - if (!decoded_point_affine) { - return decoded_point_affine.error(); - } - - // TODO: remove hard-coded call for type conversion, implement type conversion between - // coordinates - // through operator - point = decoded_point_affine.value().to_extended_with_a_minus_1(); - return nil::marshalling::status_type::success; - } - }; - - template<> - struct curve_element_reader< - nil::marshalling::endian::little_endian, - typename algebra::curves::jubjub::template g1_type> { - using group_type = - typename algebra::curves::jubjub::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::little_endian; - using params_type = curve_element_marshalling_params; - - /// abst_J(LEOS2BSP_{256}(iter)) - /// See https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub - 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 field_type = typename group_value_type::field_type; - using integral_type = typename field_type::integral_type; - - const std::size_t chunk_number = - params_type::bit_length() / 8 + (params_type::bit_length() % 8 != 0); - assert(chunk_number == 32); - - integral_type int_v = read_data(iter); - if (int_v >= group_value_type::field_type::modulus) { - return nil::marshalling::status_type::invalid_msg_data; - } - field_type::value_type field_v(int_v); - field_type::value_type vv = field_v.squared(); - field_type::value_type denominator = (field_type::value_type(group_type::params_type::a) - - field_type::value_type(group_type::params_type::d) * vv); - if (denominator.is_zero()) { - return nil::marshalling::status_type::invalid_msg_data; - } - field_type::value_type fraction = (field_type::value_type::one() - vv) * denominator.inversed(); - - field_type::value_type u; - if (fraction.is_one()) { - u = field_type::modulus - 1; - } else if (fraction.is_zero()) { - u = field_type::value_type::zero(); - } else { - if ( !fraction.is_square() ) { - return nil::marshalling::status_type::invalid_msg_data; - } - u = fraction.sqrt(); - } - - if ((*(iter + chunk_number - 1) >> 7) == (static_cast(u.data) & 1)) { - point = group_value_type(u, field_v); - } else { - point = group_value_type(-u, field_v); - } - - return nil::marshalling::status_type::success; - } - }; } // namespace processing } // namespace marshalling } // namespace crypto3 diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/detail/curve_element.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/detail/curve_element.hpp index bbed22937..ccb4f390d 100644 --- a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/detail/curve_element.hpp +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/detail/curve_element.hpp @@ -1,6 +1,7 @@ //---------------------------------------------------------------------------// // Copyright (c) 2017-2021 Mikhail Komarov // Copyright (c) 2020-2021 Nikita Kaskov +// Copyright (c) 2024 Vasiliy Olekhov // // MIT License // @@ -88,6 +89,16 @@ namespace nil { return result; } + /** @brief Recover X coordinate from Y coordinate and given sign + * This is specific to Ed25519 Twisted Edwards curve, but could be used for + * any other curve in twisted edwards form. + * + * The curve equation in twisted edwards form is A*x^2+y^2=1+D*x^2*y^2 + * Given Y, we compute + * X^2 = ( 1 - Y^2 ) / ( A - D*Y^2 ) + * If X^2 is not a square, then there is no such point and input should be rejected + * Otherwise X or -X are chosen by the sign parameter + */ template static inline typename std::enable_if< @@ -106,12 +117,12 @@ namespace nil { } base_field_value_type y(y_int); base_field_value_type y2 = y * y; - base_field_value_type y2dp1 = y2 * group_type::params_type::d + base_integral_type(1); + base_field_value_type y2dp1 = group_type::params_type::a - y2 * group_type::params_type::d; if (y2dp1.is_zero()) { return nil::marshalling::status_type::invalid_msg_data; } base_field_value_type x2 = - (y2 - base_integral_type(1)) * y2dp1.inversed(); + (base_integral_type(1) - y2) * y2dp1.inversed(); if (x2.is_zero()) { return group_affine_value_type(base_field_value_type::zero(), y); } @@ -120,7 +131,7 @@ namespace nil { } base_field_value_type x = x2.sqrt(); auto x_int = static_cast(x.data); - if (static_cast(x_int & 1) != sign) { + if (sign_gf_p(x_int) != sign) { x_int = base_field_type::modulus - x_int; } return group_affine_value_type(x_int, y); diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/ed25519.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/ed25519.hpp new file mode 100644 index 000000000..8828545bb --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/ed25519.hpp @@ -0,0 +1,161 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_ED25519_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_ED25519_CURVE_ELEMENT_HPP + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + template + struct curve_element_writer< + nil::marshalling::endian::little_endian, + typename algebra::curves::ed25519::template g1_type> { + using group_type = + typename algebra::curves::ed25519::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::little_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) { + using base_field_type = typename group_type::field_type; + using base_integral_type = typename base_field_type::integral_type; + + constexpr std::size_t encoded_size = 32; + using encoded_value_type = std::array; + encoded_value_type encoded_value {0}; + + auto point_affine = point.to_affine(); + + /* Zero point is encoded as (0,1) */ + if (point.is_zero()) { + point_affine.Y = 1u; + point_affine.X = 0u; + } + + auto tmp_iter = std::begin(encoded_value); + write_data(static_cast(point_affine.Y.data), + tmp_iter); + assert(!(encoded_value[encoded_size - 1] & 0x80)); + bool sign = detail::sign_gf_p(point_affine.X.data); + encoded_value[encoded_size - 1] |= + (static_cast(sign ? 1 : 0) << 7); + + std::copy(std::cbegin(encoded_value), std::cend(encoded_value), iter); + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_reader< + nil::marshalling::endian::little_endian, + typename algebra::curves::ed25519::template g1_type> { + using group_type = + typename algebra::curves::ed25519::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::little_endian; + using params_type = curve_element_marshalling_params; + + using group_affine_value_type = + typename algebra::curves::ed25519::g1_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) + { + + // somehow add size check of container pointed by iter + // assert(TSize == std::distance(first, last)); + using base_field_type = typename group_type::field_type; + using base_integral_type = typename base_field_type::integral_type; + using group_affine_value_type = + typename algebra::curves::ed25519::g1_type::value_type; + constexpr std::size_t encoded_size = 32; + static_assert(encoded_size == + (params_type::bit_length() / 8 + (params_type::bit_length() % 8 ? 1 : 0)), + "wrong size"); + + base_integral_type y = + read_data(iter); + bool sign = *(iter + encoded_size - 1) & (1 << 7); + + auto decoded_point_affine = + detail::recover_x(y, sign); + + if (!decoded_point_affine) { + return decoded_point_affine.error(); + } + + // TODO: remove hard-coded call for type conversion, implement type conversion between + // coordinates + // through operator + point = decoded_point_affine.value().to_extended_with_a_minus_1(); + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_ED25519_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/jubjub.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/jubjub.hpp new file mode 100644 index 000000000..c972a3d16 --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/jubjub.hpp @@ -0,0 +1,150 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_JUBJUB_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_JUBJUB_CURVE_ELEMENT_HPP + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + template + struct curve_element_writer< + nil::marshalling::endian::little_endian, + typename algebra::curves::jubjub::template g1_type> { + using group_type = + typename algebra::curves::jubjub::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::little_endian; + using params_type = curve_element_marshalling_params; + + /// https://zips.z.cash/protocol/protocol.pdf#concreteextractorjubjub + template + static nil::marshalling::status_type process(const group_value_type &point, TIter &iter) + { + write_data( + static_cast(point.to_affine().X.data), + iter); + return nil::marshalling::status_type::success; + } + }; + + template<> + struct curve_element_reader< + nil::marshalling::endian::little_endian, + typename algebra::curves::jubjub::template g1_type> { + using group_type = + typename algebra::curves::jubjub::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::little_endian; + using params_type = curve_element_marshalling_params; + + /// abst_J(LEOS2BSP_{256}(iter)) + /// See https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub + 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 field_type = typename group_value_type::field_type; + using scalar_type = typename algebra::curves::jubjub::scalar_field_type; + using integral_type = typename field_type::integral_type; + + integral_type int_u = read_data(iter); + if (int_u >= group_value_type::field_type::modulus) { + return nil::marshalling::status_type::invalid_msg_data; + } + + if (int_u.is_zero()) { + point = group_value_type(); + return nil::marshalling::status_type::success; + } + + field_type::value_type field_u(int_u); + field_type::value_type uu = field_u.squared(); + field_type::value_type denominator = + (field_type::value_type::one() - field_type::value_type(group_type::params_type::d) * uu); + if (denominator.is_zero()) { + return nil::marshalling::status_type::invalid_msg_data; + } + + field_type::value_type fraction = + (field_type::value_type::one() - field_type::value_type(group_type::params_type::a) * uu) + * denominator.inversed(); + + if (!fraction.is_square()) { + return nil::marshalling::status_type::invalid_msg_data; + } + + field_type::value_type v = fraction.sqrt(); + + // ... at most one of (u, v) and (u, −v) is in J(𝑟) + point = group_value_type(field_u, v); + if ( (point * (scalar_type::modulus - 1) + point).is_zero() ) { + return nil::marshalling::status_type::success; + } + + point = group_value_type(field_u, -v); + if ( (point * (scalar_type::modulus - 1) + point).is_zero() ) { + return nil::marshalling::status_type::success; + } + + // If neither has order r, then point is of mixed order and should be rejected + point = group_value_type(); + return nil::marshalling::status_type::invalid_msg_data; + } + }; + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt4.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt4.hpp new file mode 100644 index 000000000..79e71ebbd --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt4.hpp @@ -0,0 +1,312 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_MNT4_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_MNT4_CURVE_ELEMENT_HPP + + +#include +#include + +#include + +#include + +#include + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + /* Specialization for mnt4_298::g2_type */ + template + struct curve_element_marshalling_params > + { + using group_type = algebra::curves::mnt4_298::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< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt4_298::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt4_298:: + template g1_type; + using group_value_type = typename group_type::value_type; + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + + auto point_affine = point.to_affine(); + + write_data( + static_cast(point_affine.X.data), + iter); + + if (point_affine.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_writer< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt4_298::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt4_298:: + template g2_type; + using group_value_type = typename group_type::value_type; + using g2_value_type = group_value_type; + using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is always encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + auto point_affine = point.to_affine(); + + TIter write_iter = iter; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[1].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + // We assume here, that write_data doesn't change the iter + write_data( + static_cast( + point_affine.X.data[0].data), + write_iter); + if(point.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt4_298::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt4_298:: + 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + using integral_type = typename g1_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + integral_type x = read_data(iter); + + if (I_bit) { + // point at infinity + point = g1_value_type(); + return nil::marshalling::status_type::success; + } + + g1_field_value_type x_mod(x); + g1_field_value_type y2_mod = x_mod.pow(3) + + group_type::params_type::a * x_mod + + 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); + if (Y_bit == bool(S_bit)) { + g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt4_298::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt4_298:: + template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g2_value_type = group_value_type; + using g2_field_type = typename g2_value_type::field_type; + using g2_field_value_type = typename g2_field_type::value_type; + using integral_type = typename g2_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + TIter read_iter = iter; + integral_type x_1 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + integral_type x_0 = read_data(read_iter); + + if (I_bit) { + // point at infinity + point = group_value_type(); + return nil::marshalling::status_type::success; + } + + g2_field_value_type x_mod(x_0, x_1); + g2_field_value_type y2_mod = x_mod.pow(3) + + group_type::params_type::a * x_mod + + 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); + if (Y_bit == bool(S_bit)) { + g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_MNT4_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt6.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt6.hpp new file mode 100644 index 000000000..6f051e1ea --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/mnt6.hpp @@ -0,0 +1,323 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2017-2021 Mikhail Komarov +// Copyright (c) 2020-2021 Nikita Kaskov +// 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_MNT6_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_MNT6_CURVE_ELEMENT_HPP + +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + /* Specialization for mnt6_298::g2_type */ + template + struct curve_element_marshalling_params > + { + using group_type = algebra::curves::mnt6_298::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< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt6_298::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt6_298:: + template g1_type; + using group_value_type = typename group_type::value_type; + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + + auto point_affine = point.to_affine(); + + write_data( + static_cast(point_affine.X.data), + iter); + + if (point_affine.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_writer< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt6_298::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt6_298:: + template g2_type; + using group_value_type = typename group_type::value_type; + using g2_value_type = group_value_type; + using g2_field_type = typename group_value_type::field_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 nil::marshalling::status_type process(const group_value_type &point, TIter &iter) { + + /* Point is always encoded in compressed form, only X coordinate. + * Highest bit is Infinity flag + * Second highest bit is sign of Y coordinate */ + + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(typename TIter::value_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + + constexpr static const chunk_type I_bit = 0x80; + constexpr static const chunk_type S_bit = 0x40; + auto point_affine = point.to_affine(); + + TIter write_iter = iter; + write_data( + static_cast( + point_affine.X.data[2].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + + write_data( + static_cast( + point_affine.X.data[1].data), + write_iter); + write_iter += sizeof_field_element_chunks_count; + + write_data( + static_cast( + point_affine.X.data[0].data), + write_iter); + + if(point.is_zero()) { + *iter |= I_bit; + } + + if (detail::sign_gf_p(point_affine.Y)) { + *iter |= S_bit; + } + + return nil::marshalling::status_type::success; + } + }; + + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt6_298::template g1_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt6_298:: + 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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + using g1_value_type = group_value_type; + using g1_field_type = typename group_value_type::field_type; + using g1_field_value_type = typename g1_field_type::value_type; + using integral_type = typename g1_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + integral_type x = read_data(iter); + + if (I_bit) { + // point at infinity + point = g1_value_type(); + return nil::marshalling::status_type::success; + } + + g1_field_value_type x_mod(x); + g1_field_value_type y2_mod = x_mod.pow(3) + + group_type::params_type::a * x_mod + + 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); + if (Y_bit == bool(S_bit)) { + g1_value_type result(x_mod, y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g1_value_type result(x_mod, -y_mod, g1_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + template + struct curve_element_reader< + nil::marshalling::endian::big_endian, + typename algebra::curves::mnt6_298::template g2_type< + Coordinates, + algebra::curves::forms::short_weierstrass>> { + using group_type = typename algebra::curves::mnt6_298:: + template g2_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 nil::marshalling::status_type process(group_value_type &point, TIter &iter) { + using chunk_type = typename TIter::value_type; + + constexpr static const std::size_t sizeof_field_element = + params_type::bit_length() / (group_value_type::field_type::arity); + constexpr static const std::size_t units_bits = 8; + constexpr static const std::size_t chunk_bits = sizeof(chunk_type) * units_bits; + constexpr static const std::size_t sizeof_field_element_chunks_count = + (sizeof_field_element / chunk_bits) + ((sizeof_field_element % chunk_bits) ? 1 : 0); + using g2_value_type = group_value_type; + using g2_field_type = typename g2_value_type::field_type; + using g2_field_value_type = typename g2_field_type::value_type; + using integral_type = typename g2_value_type::field_type::integral_type; + + chunk_type I_bit = *iter & 0x80; + chunk_type S_bit = *iter & 0x40; + + TIter read_iter = iter; + integral_type x_2 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + integral_type x_1 = read_data(read_iter); + read_iter += sizeof_field_element_chunks_count; + integral_type x_0 = read_data(read_iter); + + if (I_bit) { + // point at infinity + point = group_value_type(); + return nil::marshalling::status_type::success; + } + + g2_field_value_type x_mod(x_0, x_1, x_2); + g2_field_value_type y2_mod = x_mod.pow(3) + + group_type::params_type::a * x_mod + + 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); + if (Y_bit == bool(S_bit)) { + g2_value_type result(x_mod, y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } else { + g2_value_type result(x_mod, -y_mod, g2_field_value_type::one()); + BOOST_ASSERT(result.is_well_formed()); + point = result; + } + + return nil::marshalling::status_type::success; + } + }; + + } // namespace processing + } // namespace marshalling + } // namespace crypto3 +} // namespace nil +#endif // CRYPTO3_MARSHALLING_PROCESSING_MNT6_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/pallas.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/pallas.hpp new file mode 100644 index 000000000..8352df0da --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/pallas.hpp @@ -0,0 +1,186 @@ +//---------------------------------------------------------------------------// +// 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_PALLAS_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_PALLAS_CURVE_ELEMENT_HPP + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + template + struct curve_element_marshalling_params< + algebra::curves::pallas::g1_type + > { + using group_type = algebra::curves::pallas::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::pallas::template g1_type> { + using group_type = typename algebra::curves::pallas:: + 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::pallas::template g1_type> { + using group_type = typename algebra::curves::pallas:: + 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_PALLAS_CURVE_ELEMENT_HPP 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 new file mode 100644 index 000000000..bc15027ed --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/secp_k1.hpp @@ -0,0 +1,186 @@ +//---------------------------------------------------------------------------// +// 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_K1_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_SECP_K1_CURVE_ELEMENT_HPP + +#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::secp_k1::template g1_type<> + + > { + using group_type = typename algebra::curves::secp_k1::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::secp_k1::template g1_type<> > { + using group_type = typename algebra::curves::secp_k1::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::secp_k1::template g1_type> { + using group_type = typename algebra::curves::secp_k1:: + 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_k1_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/vesta.hpp b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/vesta.hpp new file mode 100644 index 000000000..8b3afa47f --- /dev/null +++ b/libs/marshalling/algebra/include/nil/crypto3/marshalling/algebra/processing/vesta.hpp @@ -0,0 +1,186 @@ +//---------------------------------------------------------------------------// +// 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_VESTA_CURVE_ELEMENT_HPP +#define CRYPTO3_MARSHALLING_PROCESSING_VESTA_CURVE_ELEMENT_HPP + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +namespace nil { + namespace crypto3 { + namespace marshalling { + namespace processing { + + template + struct curve_element_marshalling_params< + algebra::curves::vesta::g1_type + > { + using group_type = algebra::curves::vesta::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::vesta::template g1_type> { + using group_type = typename algebra::curves::vesta:: + 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::vesta::template g1_type> { + using group_type = typename algebra::curves::vesta:: + 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_VESTA_CURVE_ELEMENT_HPP diff --git a/libs/marshalling/algebra/test/curve_element.cpp b/libs/marshalling/algebra/test/curve_element.cpp index f6d6a8977..81972c08f 100644 --- a/libs/marshalling/algebra/test/curve_element.cpp +++ b/libs/marshalling/algebra/test/curve_element.cpp @@ -63,25 +63,32 @@ #include #include #include -#include #include #include -template -void print_byteblob(TIter iter_begin, TIter iter_end) { - for (TIter it = iter_begin; it != iter_end; it++) { - std::cout << std::hex << std::setw(2) << std::setfill('0') << int(*it); - } - std::cout << std::endl; -} +#include +#include + +#include +#include + +#include +#include + +#include -template -void test_group_element_big_endian(T val) { +#include +#include + +#include +//#include + +template +void test_group_element(T val) { using namespace nil::crypto3::marshalling; - using Endianness = nil::marshalling::option::big_endian; using unit_type = unsigned char; @@ -94,21 +101,39 @@ void test_group_element_big_endian(T val) { static_assert(nil::marshalling::is_compatible::value); nil::marshalling::status_type status; - std::vector cv = nil::marshalling::pack(val, status); + std::vector cv = nil::marshalling::pack(val, status); BOOST_CHECK(status == nil::marshalling::status_type::success); - T test_val = nil::marshalling::pack(cv, status); + 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(val == test_val); + 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 -void test_group_element() { +template +void test_group_element_set() { /* test default element - zero for GT and infinity for G1/G2 */ typename group_type::value_type val = typename group_type::value_type(); - test_group_element_big_endian(val); + test_group_element(val); /* test 128 random points */ for (std::size_t i = 0; i < 128; ++i) { @@ -116,34 +141,34 @@ void test_group_element() { std::cout << std::dec << i << " tested" << std::endl; } val = nil::crypto3::algebra::random_element(); - test_group_element_big_endian(val); + test_group_element(val); } } -template +template void test_curve(std::string curve_name) { std::cout << "Testing curve: " << curve_name << std::endl; std::cout << "Marshaling of G1 group elements" << std::endl; - test_group_element>(); + test_group_element_set, endianness>(); std::cout << "Testing of " << curve_name << " finished" << std::endl; } -template +template void test_pairing_curve(std::string curve_name) { std::cout << "Testing curve: " << curve_name << std::endl; std::cout << "Marshaling of G1 group elements" << std::endl; - test_group_element>(); + test_group_element_set, endianness>(); std::cout << "Marshaling of G2 group elements" << std::endl; - test_group_element>(); + test_group_element_set, endianness>(); - /* TODO: do we really need to marshal GT elements? + /* TODO: do we really need to marshal GT elements? std::cout << "Marshaling of GT group elements" << std::endl; test_group_element(); */ @@ -154,68 +179,59 @@ void test_pairing_curve(std::string curve_name) BOOST_AUTO_TEST_SUITE(curve_element_test_suite) +using big_endian = nil::marshalling::option::big_endian; +using little_endian = nil::marshalling::option::little_endian; + BOOST_AUTO_TEST_CASE(curve_element_mnt4) { - test_pairing_curve("mnt4_298"); + test_pairing_curve("mnt4_298"); } BOOST_AUTO_TEST_CASE(curve_element_mnt6) { - test_pairing_curve("mnt6_298"); + test_pairing_curve("mnt6_298"); } BOOST_AUTO_TEST_CASE(curve_element_bls12_381) { - test_pairing_curve("bls12_381"); + test_pairing_curve("bls12_381"); } -// TODO: implement marshalling for bls12<377> -#if 0 BOOST_AUTO_TEST_CASE(curve_element_bls12_377) { - test_curve("bls12_377"); + // it freezes +// test_pairing_curve("bls12_377"); } -#endif BOOST_AUTO_TEST_CASE(curve_element_bn254) { - test_pairing_curve("alt_bn128_254"); + test_pairing_curve("alt_bn128_254"); } -// TODO: implement marshalling for pasta curves -#if 0 BOOST_AUTO_TEST_CASE(curve_element_pallas) { - test_curve("pallas"); + test_curve("pallas"); } BOOST_AUTO_TEST_CASE(curve_element_vesta) { - test_curve("vesta"); + test_curve("vesta"); } -#endif // TODO: implement marshalling for secp_k1/secp_r1 curves -#if 0 BOOST_AUTO_TEST_CASE(curve_element_secp_k1) { - test_curve>("secp_k1<160>"); + test_curve, big_endian>("secp_k1<160>"); } +#if 0 BOOST_AUTO_TEST_CASE(curve_element_secp_r1) { test_curve>("secp_r1<160>"); } #endif -/* TODO: add marshalling for jubjub/babyjubjub/ed25519/curve25519, it is broken for now */ -#if 0 BOOST_AUTO_TEST_CASE(curve_element_jubjub) { - test_curve("jubjub"); + test_curve("jubjub"); } BOOST_AUTO_TEST_CASE(curve_element_babyjubjub) { - test_curve("babyjubjub"); + test_curve("babyjubjub"); } BOOST_AUTO_TEST_CASE(curve_element_ed25519) { - test_curve("ed25519"); + test_curve("ed25519"); } -BOOST_AUTO_TEST_CASE(curve_element_curve25519) { - test_curve("curve25519"); -} -#endif - BOOST_AUTO_TEST_SUITE_END()