|
| 1 | +//---------------------------------------------------------------------------// |
| 2 | +// Copyright (c) 2024 Vasiliy Olekhov <[email protected]> |
| 3 | +// |
| 4 | +// MIT License |
| 5 | +// |
| 6 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | +// of this software and associated documentation files (the "Software"), to deal |
| 8 | +// in the Software without restriction, including without limitation the rights |
| 9 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | +// copies of the Software, and to permit persons to whom the Software is |
| 11 | +// furnished to do so, subject to the following conditions: |
| 12 | +// |
| 13 | +// The above copyright notice and this permission notice shall be included in all |
| 14 | +// copies or substantial portions of the Software. |
| 15 | +// |
| 16 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | +// SOFTWARE. |
| 23 | +//---------------------------------------------------------------------------// |
| 24 | + |
| 25 | +#ifndef CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP |
| 26 | +#define CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP |
| 27 | + |
| 28 | +#include <cstddef> |
| 29 | +#include <cstdint> |
| 30 | +#include <type_traits> |
| 31 | +#include <iterator> |
| 32 | + |
| 33 | +#include <nil/marshalling/endianness.hpp> |
| 34 | +#include <nil/marshalling/status_type.hpp> |
| 35 | + |
| 36 | +#include <nil/crypto3/algebra/type_traits.hpp> |
| 37 | +#include <nil/crypto3/algebra/curves/detail/secp_r1/types.hpp> |
| 38 | +#include <nil/crypto3/algebra/curves/detail/secp_r1/g1.hpp> |
| 39 | +#include <nil/crypto3/algebra/curves/secp_r1.hpp> |
| 40 | + |
| 41 | +#include <nil/crypto3/marshalling/multiprecision/processing/integral.hpp> |
| 42 | + |
| 43 | +#include <nil/crypto3/marshalling/algebra/processing/curve_element.hpp> |
| 44 | + |
| 45 | +namespace nil { |
| 46 | + namespace crypto3 { |
| 47 | + namespace marshalling { |
| 48 | + namespace processing { |
| 49 | + |
| 50 | + template<std::size_t Version> |
| 51 | + struct curve_element_marshalling_params< |
| 52 | + typename algebra::curves::detail::secp_r1_g1< |
| 53 | + Version, |
| 54 | + algebra::curves::forms::short_weierstrass, |
| 55 | + algebra::curves::coordinates::projective> |
| 56 | + > { |
| 57 | + using group_type = typename algebra::curves::secp_r1<Version>::template g1_type<>; |
| 58 | + |
| 59 | + static constexpr std::size_t length() { |
| 60 | + return 1 + bit_length() / 8 + ((bit_length() % 8) != 0); |
| 61 | + } |
| 62 | + |
| 63 | + static constexpr std::size_t min_length() { |
| 64 | + return length(); |
| 65 | + } |
| 66 | + |
| 67 | + static constexpr std::size_t max_length() { |
| 68 | + return length(); |
| 69 | + } |
| 70 | + |
| 71 | + static constexpr std::size_t bit_length() { |
| 72 | + return group_type::field_type::value_bits; |
| 73 | + } |
| 74 | + |
| 75 | + static constexpr std::size_t min_bit_length() { |
| 76 | + return bit_length(); |
| 77 | + } |
| 78 | + |
| 79 | + static constexpr std::size_t max_bit_length() { |
| 80 | + return bit_length(); |
| 81 | + } |
| 82 | + }; |
| 83 | + |
| 84 | + /* |
| 85 | + * Encoding of elliptic curve point according to https://www.secg.org/sec1-v2.pdf |
| 86 | + * Curve must be in short weierstrass form, Y^2 = X^3 + A*X + B |
| 87 | + * Only X coordinate is encoded, prefixed with either 02 or 03 depending on whether Y is even or odd |
| 88 | + * The encoding is big-endian |
| 89 | + * Infinity is encoded as 00 |
| 90 | + * */ |
| 91 | + template<std::size_t Version> |
| 92 | + struct curve_element_writer< |
| 93 | + nil::marshalling::endian::big_endian, |
| 94 | + typename algebra::curves::detail::secp_r1_g1< |
| 95 | + Version, |
| 96 | + algebra::curves::forms::short_weierstrass, |
| 97 | + algebra::curves::coordinates::projective> > { |
| 98 | + using group_type = typename algebra::curves::secp_r1<Version>::template g1_type<>; |
| 99 | + using group_value_type = typename group_type::value_type; |
| 100 | + using coordinates = typename group_value_type::coordinates; |
| 101 | + using form = typename group_value_type::form; |
| 102 | + using endianness = nil::marshalling::endian::big_endian; |
| 103 | + using params_type = curve_element_marshalling_params<group_type>; |
| 104 | + |
| 105 | + template<typename TIter> |
| 106 | + static typename std::enable_if< |
| 107 | + std::is_same<std::uint8_t, typename std::iterator_traits<TIter>::value_type>::value, |
| 108 | + nil::marshalling::status_type>::type |
| 109 | + process(const group_value_type &point, TIter &iter) |
| 110 | + { |
| 111 | + if (point.is_zero()) { |
| 112 | + *iter++ = 0x00; |
| 113 | + return nil::marshalling::status_type::success; |
| 114 | + } |
| 115 | + typename group_type::curve_type::template g1_type<typename algebra::curves::coordinates::affine, form>::value_type |
| 116 | + point_affine = point.to_affine(); |
| 117 | + |
| 118 | + *iter++ = (point_affine.Y.data & 1) == 0u ? 0x02 : 0x03; |
| 119 | + write_data<params_type::bit_length(), endianness>( |
| 120 | + static_cast<typename group_value_type::field_type::integral_type>(point_affine.X.data), |
| 121 | + iter); |
| 122 | + |
| 123 | + return nil::marshalling::status_type::success; |
| 124 | + } |
| 125 | + }; |
| 126 | + |
| 127 | + template<typename Coordinates, std::size_t Version> |
| 128 | + struct curve_element_reader< |
| 129 | + nil::marshalling::endian::big_endian, |
| 130 | + typename algebra::curves::detail::secp_r1_g1<Version, algebra::curves::forms::short_weierstrass, Coordinates >> { |
| 131 | + |
| 132 | + using group_type = typename algebra::curves::secp_r1<Version>::template g1_type<>; |
| 133 | + using group_value_type = typename group_type::value_type; |
| 134 | + using coordinates = typename group_value_type::coordinates; |
| 135 | + using form = typename group_value_type::form; |
| 136 | + using endianness = nil::marshalling::endian::big_endian; |
| 137 | + using params_type = curve_element_marshalling_params<group_type>; |
| 138 | + using curve_params = typename group_type::params_type; |
| 139 | + using integral_type = typename group_value_type::field_type::integral_type; |
| 140 | + using g1_field_type = typename group_value_type::field_type; |
| 141 | + using g1_field_value_type = typename g1_field_type::value_type; |
| 142 | + |
| 143 | + template<typename TIter> |
| 144 | + static typename std::enable_if< |
| 145 | + std::is_same<std::uint8_t, typename std::iterator_traits<TIter>::value_type>::value, |
| 146 | + nil::marshalling::status_type>::type |
| 147 | + process(group_value_type &point, TIter &iter) |
| 148 | + { |
| 149 | + using chunk_type = typename TIter::value_type; |
| 150 | + |
| 151 | + const chunk_type prefix = *iter++; |
| 152 | + |
| 153 | + if (0x00 == prefix) { |
| 154 | + point = group_value_type::zero(); |
| 155 | + return nil::marshalling::status_type::success; |
| 156 | + } |
| 157 | + |
| 158 | + if (prefix != 0x02 && prefix != 0x03) { |
| 159 | + return nil::marshalling::status_type::invalid_msg_data; |
| 160 | + } |
| 161 | + |
| 162 | + constexpr static const std::size_t sizeof_field_element = |
| 163 | + params_type::bit_length() / (group_value_type::field_type::arity); |
| 164 | + integral_type x = read_data<sizeof_field_element, integral_type, endianness>(iter); |
| 165 | + |
| 166 | + g1_field_value_type x_mod(x); |
| 167 | + g1_field_value_type y2_mod = x_mod * x_mod * x_mod + curve_params::a * x_mod + curve_params::b; |
| 168 | + if (!y2_mod.is_square()) { |
| 169 | + return nil::marshalling::status_type::invalid_msg_data; |
| 170 | + } |
| 171 | + |
| 172 | + g1_field_value_type y_mod = y2_mod.sqrt(); |
| 173 | + |
| 174 | + const chunk_type expected_prefix = (y_mod.data & 1) == 0u ? 0x02 : 0x03; |
| 175 | + |
| 176 | + if (expected_prefix == prefix) { |
| 177 | + point = group_value_type(x_mod, y_mod); |
| 178 | + } else { |
| 179 | + point = group_value_type(x_mod, -y_mod); |
| 180 | + } |
| 181 | + |
| 182 | + return nil::marshalling::status_type::success; |
| 183 | + } |
| 184 | + }; |
| 185 | + |
| 186 | + } // namespace processing |
| 187 | + } // namespace marshalling |
| 188 | + } // namespace crypto3 |
| 189 | +} // namespace nil |
| 190 | +#endif // CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP |
0 commit comments