diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index add2c62ef5..8c1c76a237 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -10,12 +10,15 @@ namespace fc::crypto::blslib { const std::string bls_signature_prefix = "SIG_BLS_"; }; - // Immutable after construction. + // Immutable after construction (although operator= is provided). // Provides an efficient wrapper around bls12_381::g2. // Serialization form: // Non-Montgomery form and little-endian encoding for the field elements. // Affine form for the group element (the z component is 1 and not included in the serialization). // Binary serialization encodes x component first followed by y component. + // Cached g2 in Jacobian Montgomery is used for efficient BLS math. + // Keeping the serialized data allows for efficient serialization without the expensive conversion + // from Jacobian Montgomery to Affine Non-Montgomery. class bls_signature { public: bls_signature() = default; @@ -50,23 +53,19 @@ namespace fc::crypto::blslib { template friend T& operator>>(T& ds, bls_signature& sig) { ds.read(reinterpret_cast(sig._affine_non_montgomery_le.data()), sig._affine_non_montgomery_le.size()*sizeof(uint8_t)); - constexpr bool check = true; // check if invalid - constexpr bool raw = false; // non-montgomery - std::optional g2 = bls12_381::g2::fromAffineBytesLE(sig._affine_non_montgomery_le, check, raw); - FC_ASSERT(g2, "Invalid bls signature ${k}", ("k", sig._affine_non_montgomery_le)); - sig._jacobian_montgomery_le = *g2; + sig._jacobian_montgomery_le = to_jacobian_montgomery_le(sig._affine_non_montgomery_le); return ds; } private: + friend class bls_aggregate_signature; + static bls12_381::g2 to_jacobian_montgomery_le(const std::array& affine_non_montgomery_le); + std::array _affine_non_montgomery_le{}; bls12_381::g2 _jacobian_montgomery_le; // cached g2 }; - // Serialization form: - // Non-Montgomery form and little-endian encoding for the field elements. - // Affine form for the group element (the z component is 1 and not included in the serialization). - // Binary serialization encodes x component first followed by y component. + // See bls_signature comment above class bls_aggregate_signature { public: bls_aggregate_signature() = default; @@ -91,6 +90,7 @@ namespace fc::crypto::blslib { } // affine non-montgomery base64url with bls_signature_prefix + // Expensive as conversion from Jacobian Montgomery to Affine Non-Montgomery needed std::string to_string() const; const bls12_381::g2& jacobian_montgomery_le() const { return _jacobian_montgomery_le; } @@ -112,11 +112,7 @@ namespace fc::crypto::blslib { friend T& operator>>(T& ds, bls_aggregate_signature& sig) { std::array affine_non_montgomery_le; ds.read(reinterpret_cast(affine_non_montgomery_le.data()), affine_non_montgomery_le.size()*sizeof(uint8_t)); - constexpr bool check = true; // check if invalid - constexpr bool raw = false; // non-montgomery - std::optional g2 = bls12_381::g2::fromAffineBytesLE(affine_non_montgomery_le, check, raw); - FC_ASSERT(g2, "Invalid bls aggregate signature ${k}", ("k", affine_non_montgomery_le)); - sig._jacobian_montgomery_le = *g2; + sig._jacobian_montgomery_le = bls_signature::to_jacobian_montgomery_le(affine_non_montgomery_le); return ds; } diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index e3fe5623eb..873201873d 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -5,35 +5,37 @@ namespace fc::crypto::blslib { - bls_signature::bls_signature(std::span affine_non_montgomery_le) { - std::ranges::copy(affine_non_montgomery_le, _affine_non_montgomery_le.begin()); + bls12_381::g2 bls_signature::to_jacobian_montgomery_le(const std::array& affine_non_montgomery_le) { constexpr bool check = true; // verify constexpr bool raw = false; // to montgomery auto g2 = bls12_381::g2::fromAffineBytesLE(affine_non_montgomery_le, check, raw); FC_ASSERT(g2, "Invalid bls_signature"); - _jacobian_montgomery_le = *g2; + return *g2; } - static std::tuple> sig_parse_base64url(const std::string& base64urlstr) { + inline std::array from_span(std::span affine_non_montgomery_le) { + std::array r; + std::ranges::copy(affine_non_montgomery_le, r.begin()); + return r; + } + + bls_signature::bls_signature(std::span affine_non_montgomery_le) + : _affine_non_montgomery_le(from_span(affine_non_montgomery_le)) + , _jacobian_montgomery_le(to_jacobian_montgomery_le(_affine_non_montgomery_le)) { + } + + static std::array sig_parse_base64url(const std::string& base64urlstr) { try { - auto res = std::mismatch(config::bls_signature_prefix.begin(), config::bls_signature_prefix.end(), - base64urlstr.begin()); + auto res = std::mismatch(config::bls_signature_prefix.begin(), config::bls_signature_prefix.end(), base64urlstr.begin()); FC_ASSERT(res.first == config::bls_signature_prefix.end(), "BLS Signature has invalid format : ${str}", ("str", base64urlstr)); - auto data_str = base64urlstr.substr(config::bls_signature_prefix.size()); - - std::array bytes = fc::crypto::blslib::deserialize_base64url>(data_str); - - constexpr bool check = true; // check if base64urlstr is invalid - constexpr bool raw = false; // non-montgomery - std::optional g2 = bls12_381::g2::fromAffineBytesLE(bytes, check, raw); - FC_ASSERT(g2); - return {*g2, bytes}; - } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base64urlstr ) ) + return fc::crypto::blslib::deserialize_base64url>(data_str); + } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base64urlstr ) ) } - bls_signature::bls_signature(const std::string& base64urlstr) { - std::tie(_jacobian_montgomery_le, _affine_non_montgomery_le) = sig_parse_base64url(base64urlstr); + bls_signature::bls_signature(const std::string& base64urlstr) + : _affine_non_montgomery_le(sig_parse_base64url(base64urlstr)) + , _jacobian_montgomery_le(to_jacobian_montgomery_le(_affine_non_montgomery_le)) { } std::string bls_signature::to_string() const { @@ -41,8 +43,8 @@ namespace fc::crypto::blslib { return config::bls_signature_prefix + data_str; } - bls_aggregate_signature::bls_aggregate_signature(const std::string& base64urlstr) { - std::tie(_jacobian_montgomery_le, std::ignore) = sig_parse_base64url(base64urlstr); + bls_aggregate_signature::bls_aggregate_signature(const std::string& base64urlstr) + : _jacobian_montgomery_le(bls_signature::to_jacobian_montgomery_le(sig_parse_base64url(base64urlstr))) { } std::string bls_aggregate_signature::to_string() const { @@ -59,7 +61,6 @@ namespace fc { void to_variant(const crypto::blslib::bls_signature& var, variant& vo) { vo = var.to_string(); } - void from_variant(const variant& var, crypto::blslib::bls_signature& vo) { vo = crypto::blslib::bls_signature(var.as_string()); } @@ -67,7 +68,6 @@ namespace fc { void to_variant(const crypto::blslib::bls_aggregate_signature& var, variant& vo) { vo = var.to_string(); } - void from_variant(const variant& var, crypto::blslib::bls_aggregate_signature& vo) { vo = crypto::blslib::bls_aggregate_signature(var.as_string()); }