Skip to content

Commit

Permalink
Finished with marshalling of all supported curves #318
Browse files Browse the repository at this point in the history
  • Loading branch information
vo-nil committed Sep 12, 2024
1 parent c5b1b99 commit 2ac117d
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@
#define CRYPTO3_MARSHALLING_PROCESSING_BLS12_CURVE_ELEMENT_HPP

#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <limits>
#include <iterator>

#include <nil/marshalling/endianness.hpp>
#include <nil/marshalling/status_type.hpp>
Expand All @@ -50,6 +46,75 @@ namespace nil {
namespace marshalling {
namespace processing {


/* Specialization for bls12_377::g2_type */
template<typename Coordinates>
struct curve_element_marshalling_params<algebra::curves::bls12_377::
template g2_type<Coordinates, algebra::curves::forms::short_weierstrass> >
{
using group_type = algebra::curves::bls12_381::template
g2_type<Coordinates, algebra::curves::forms::short_weierstrass>;

static constexpr std::size_t length() {
return bit_length() / 8 + ((bit_length() % 8) != 0);
}

static constexpr std::size_t min_length() {
return length();
}

static constexpr std::size_t max_length() {
return length();
}

static constexpr std::size_t bit_length() {
constexpr std::size_t modulus_bits_round_up = (group_type::field_type::modulus_bits + 7) & ~7;
return modulus_bits_round_up * group_type::field_type::arity;
}

static constexpr std::size_t min_bit_length() {
return bit_length();
}

static constexpr std::size_t max_bit_length() {
return bit_length();
}
};

/* Specialization for bls12_381::g2_type */
template<typename Coordinates>
struct curve_element_marshalling_params<algebra::curves::bls12_381::
template g2_type<Coordinates, algebra::curves::forms::short_weierstrass> >
{
using group_type = algebra::curves::bls12_381::template
g2_type<Coordinates, algebra::curves::forms::short_weierstrass>;

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<typename Endianness, typename Coordinates>
struct curve_element_writer<
Endianness,
Expand Down Expand Up @@ -263,7 +328,7 @@ namespace nil {
integral_type x = read_data<sizeof_field_element, integral_type, endianness>(iter);

g1_field_value_type x_mod(x);
g1_field_value_type y2_mod = x_mod.pow(3u) + g1_field_value_type(4u);
g1_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b;
BOOST_ASSERT(y2_mod.is_square());
g1_field_value_type y_mod = y2_mod.sqrt();
bool Y_bit = detail::sign_gf_p<g1_field_type>(y_mod);
Expand Down Expand Up @@ -330,7 +395,7 @@ namespace nil {
integral_type x_0 = read_data<sizeof_field_element, integral_type, endianness>(read_iter);

g2_field_value_type x_mod(x_0, x_1);
g2_field_value_type y2_mod = x_mod.pow(3u) + g2_field_value_type(4u, 4u);
g2_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b;
BOOST_ASSERT(y2_mod.is_square());
g2_field_value_type y_mod = y2_mod.sqrt();
bool Y_bit = detail::sign_gf_p<g2_field_type>(y_mod);
Expand Down Expand Up @@ -392,7 +457,7 @@ namespace nil {
integral_type x = read_data<sizeof_field_element, integral_type, endianness>(iter);

g1_field_value_type x_mod(x);
g1_field_value_type y2_mod = x_mod.pow(3u) + g1_field_value_type(4u);
g1_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b;
BOOST_ASSERT(y2_mod.is_square());
g1_field_value_type y_mod = y2_mod.sqrt();
bool Y_bit = detail::sign_gf_p<g1_field_type>(y_mod);
Expand Down Expand Up @@ -459,7 +524,7 @@ namespace nil {
integral_type x_0 = read_data<sizeof_field_element, integral_type, endianness>(read_iter);

g2_field_value_type x_mod(x_0, x_1);
g2_field_value_type y2_mod = x_mod.pow(3u) + g2_field_value_type(4u, 4u);
g2_field_value_type y2_mod = x_mod.pow(3u) + group_type::params_type::b;
BOOST_ASSERT(y2_mod.is_square());
g2_field_value_type y_mod = y2_mod.sqrt();
bool Y_bit = detail::sign_gf_p<g2_field_type>(y_mod);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,4 @@ namespace nil {
} // namespace marshalling
} // namespace crypto3
} // namespace nil
#endif // CRYPTO3_MARSHALLING_PROCESSING_secp_k1<Version>_CURVE_ELEMENT_HPP
#endif // CRYPTO3_MARSHALLING_PROCESSING_SECP_K1_CURVE_ELEMENT_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
//---------------------------------------------------------------------------//
// Copyright (c) 2024 Vasiliy Olekhov <[email protected]>
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP
#define CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP

#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <iterator>

#include <nil/marshalling/endianness.hpp>
#include <nil/marshalling/status_type.hpp>

#include <nil/crypto3/algebra/type_traits.hpp>
#include <nil/crypto3/algebra/curves/detail/secp_r1/types.hpp>
#include <nil/crypto3/algebra/curves/detail/secp_r1/g1.hpp>
#include <nil/crypto3/algebra/curves/secp_r1.hpp>

#include <nil/crypto3/marshalling/multiprecision/processing/integral.hpp>

#include <nil/crypto3/marshalling/algebra/processing/curve_element.hpp>

namespace nil {
namespace crypto3 {
namespace marshalling {
namespace processing {

template<std::size_t Version>
struct curve_element_marshalling_params<
typename algebra::curves::detail::secp_r1_g1<
Version,
algebra::curves::forms::short_weierstrass,
algebra::curves::coordinates::projective>
> {
using group_type = typename algebra::curves::secp_r1<Version>::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<std::size_t Version>
struct curve_element_writer<
nil::marshalling::endian::big_endian,
typename algebra::curves::detail::secp_r1_g1<
Version,
algebra::curves::forms::short_weierstrass,
algebra::curves::coordinates::projective> > {
using group_type = typename algebra::curves::secp_r1<Version>::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<group_type>;

template<typename TIter>
static typename std::enable_if<
std::is_same<std::uint8_t, typename std::iterator_traits<TIter>::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<typename algebra::curves::coordinates::affine, form>::value_type
point_affine = point.to_affine();

*iter++ = (point_affine.Y.data & 1) == 0u ? 0x02 : 0x03;
write_data<params_type::bit_length(), endianness>(
static_cast<typename group_value_type::field_type::integral_type>(point_affine.X.data),
iter);

return nil::marshalling::status_type::success;
}
};

template<typename Coordinates, std::size_t Version>
struct curve_element_reader<
nil::marshalling::endian::big_endian,
typename algebra::curves::detail::secp_r1_g1<Version, algebra::curves::forms::short_weierstrass, Coordinates >> {

using group_type = typename algebra::curves::secp_r1<Version>::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<group_type>;
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<typename TIter>
static typename std::enable_if<
std::is_same<std::uint8_t, typename std::iterator_traits<TIter>::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<sizeof_field_element, integral_type, endianness>(iter);

g1_field_value_type x_mod(x);
g1_field_value_type y2_mod = x_mod * x_mod * x_mod + curve_params::a * x_mod + curve_params::b;
if (!y2_mod.is_square()) {
return nil::marshalling::status_type::invalid_msg_data;
}

g1_field_value_type y_mod = y2_mod.sqrt();

const chunk_type expected_prefix = (y_mod.data & 1) == 0u ? 0x02 : 0x03;

if (expected_prefix == prefix) {
point = group_value_type(x_mod, y_mod);
} else {
point = group_value_type(x_mod, -y_mod);
}

return nil::marshalling::status_type::success;
}
};

} // namespace processing
} // namespace marshalling
} // namespace crypto3
} // namespace nil
#endif // CRYPTO3_MARSHALLING_PROCESSING_SECP_R1_CURVE_ELEMENT_HPP
33 changes: 9 additions & 24 deletions libs/marshalling/algebra/test/curve_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
#include <nil/crypto3/marshalling/algebra/processing/vesta.hpp>

#include <nil/crypto3/marshalling/algebra/processing/secp_k1.hpp>
//#include <nil/crypto3/marshalling/algebra/processing/secp_r1.hpp>
#include <nil/crypto3/marshalling/algebra/processing/secp_r1.hpp>

template<typename T, typename endianness>
void test_group_element(T val) {
Expand All @@ -104,28 +104,10 @@ void test_group_element(T val) {
std::vector<unit_type> cv = nil::marshalling::pack<endianness>(val, status);
BOOST_CHECK(status == nil::marshalling::status_type::success);

std::cout << "Value: " << std::hex << val.to_affine() << std::endl;

/* */
std::cout << "Serialized as " << cv.size() << " bytes:" << std::endl;
for(auto &x: cv) {
std::cout << std::hex << std::setw(2) << std::setfill('0');
std::cout << (int)x;
}
std::cout << std::endl;
/* */

T test_val = nil::marshalling::pack<endianness>(cv, status);
BOOST_CHECK(status == nil::marshalling::status_type::success);

BOOST_CHECK_EQUAL(val.to_affine(), test_val.to_affine());
if (val == test_val) {
std::cout << "";
} else {
std::cout << "Deserialized: " << std::endl << std::hex << test_val.to_affine() << std::endl;
std::cout << "";
}
std::cout << "========================" << std::endl;
}

template<typename group_type, typename endianness>
Expand Down Expand Up @@ -196,7 +178,7 @@ BOOST_AUTO_TEST_CASE(curve_element_bls12_381) {

BOOST_AUTO_TEST_CASE(curve_element_bls12_377) {
// it freezes
// test_pairing_curve<nil::crypto3::algebra::curves::bls12_377, big_endian>("bls12_377");
test_pairing_curve<nil::crypto3::algebra::curves::bls12_377, big_endian>("bls12_377");
}

BOOST_AUTO_TEST_CASE(curve_element_bn254) {
Expand All @@ -211,16 +193,19 @@ BOOST_AUTO_TEST_CASE(curve_element_vesta) {
test_curve<nil::crypto3::algebra::curves::vesta, big_endian>("vesta");
}

// TODO: implement marshalling for secp_k1/secp_r1 curves
BOOST_AUTO_TEST_CASE(curve_element_secp_k1) {
test_curve<nil::crypto3::algebra::curves::secp_k1<160>, big_endian>("secp_k1<160>");
test_curve<nil::crypto3::algebra::curves::secp_k1<192>, big_endian>("secp_k1<192>");
test_curve<nil::crypto3::algebra::curves::secp_k1<224>, big_endian>("secp_k1<224>");
test_curve<nil::crypto3::algebra::curves::secp_k1<256>, big_endian>("secp_k1<256>");
}

#if 0
BOOST_AUTO_TEST_CASE(curve_element_secp_r1) {
test_curve<nil::crypto3::algebra::curves::secp_r1<160>>("secp_r1<160>");
test_curve<nil::crypto3::algebra::curves::secp_r1<160>, big_endian>("secp_r1<160>");
test_curve<nil::crypto3::algebra::curves::secp_r1<192>, big_endian>("secp_r1<192>");
test_curve<nil::crypto3::algebra::curves::secp_r1<224>, big_endian>("secp_r1<224>");
test_curve<nil::crypto3::algebra::curves::secp_r1<256>, big_endian>("secp_r1<256>");
}
#endif

BOOST_AUTO_TEST_CASE(curve_element_jubjub) {
test_curve<nil::crypto3::algebra::curves::jubjub, little_endian>("jubjub");
Expand Down

0 comments on commit 2ac117d

Please sign in to comment.