github.com/ledgerwatch/erigon-lib@v1.0.0/pedersen_hash/elliptic_curve_constants.h (about)

     1  #ifndef STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_
     2  #define STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_
     3  
     4  #include <array>
     5  #include <utility>
     6  #include <vector>
     7  
     8  #include "big_int.h"
     9  #include "elliptic_curve.h"
    10  #include "prime_field_element.h"
    11  
    12  namespace starkware {
    13  
    14  /*
    15    Contains a set of constants that go along with an elliptic curve.
    16  
    17    FieldElementT is the underlying field of the curve.
    18    The equation of the elliptic curve is y^2 = x^3 + k_alpha * x + k_beta.
    19    k_order is the size of the group.
    20    k_points are points on the curve that were generated independently in a "nothing up my sleeve"
    21    manner to ensure that no one knows their discrete log.
    22  */
    23  template <typename FieldElementT>
    24  struct EllipticCurveConstants {
    25   public:
    26    using ValueType = typename FieldElementT::ValueType;
    27  
    28    const FieldElementT k_alpha;
    29    const FieldElementT k_beta;
    30    const ValueType k_order;
    31    const std::vector<EcPoint<FieldElementT>> k_points;
    32  
    33    constexpr EllipticCurveConstants(
    34        const FieldElementT& k_alpha, const FieldElementT& k_beta, const ValueType& k_order,
    35        std::vector<EcPoint<FieldElementT>> k_points) noexcept
    36        : k_alpha(k_alpha), k_beta(k_beta), k_order(k_order), k_points(std::move(k_points)) {}
    37  
    38    constexpr EllipticCurveConstants(
    39        const ValueType& k_alpha, const ValueType& k_beta, const ValueType& k_order,
    40        std::initializer_list<std::pair<ValueType, ValueType>> k_points) noexcept
    41        : EllipticCurveConstants(
    42              FieldElementT::FromBigInt(k_alpha), FieldElementT::FromBigInt(k_beta), k_order,
    43              ECPointsVectorFromPairs(std::move(k_points))) {}
    44  
    45   private:
    46    static std::vector<EcPoint<FieldElementT>> ECPointsVectorFromPairs(
    47        std::initializer_list<std::pair<ValueType, ValueType>> k_points) {
    48      std::vector<EcPoint<FieldElementT>> res;
    49      res.reserve(k_points.size());
    50  
    51      for (const auto& p : k_points) {
    52        res.emplace_back(FieldElementT::FromBigInt(p.first), FieldElementT::FromBigInt(p.second));
    53      }
    54      return res;
    55    }
    56  };
    57  
    58  /*
    59    This elliptic curve over the prime field PrimeFieldElement was chosen in a "nothing up my sleeve"
    60    manner to show that we don't know any special properties of this curve (other than being of prime
    61    order).
    62  
    63    alpha was chosen to be 1 because any elliptic curve has an isomorphic curve with a small alpha,
    64    but we didn't want a zero alpha because then the discriminant is small.
    65  
    66    beta was generated in the following way:
    67    1) Take beta to be the integer whose digits are the first 76 decimal digits of pi (76 is the
    68    number of digits required to represent a field element).
    69    2) While [y^2 = x^3 + alpha * x + beta] is not a curve of prime order, increase beta by 1.
    70  
    71    The points were generated by the following steps:
    72    1) Take the decimal digits of pi and split them into chunks of 76 digits (the number of decimal
    73    digits of the modulus).
    74  
    75    2) Each chunk of 76 digits is the seed for generating a point, except for the first chunk
    76    which was used for generating the curve.
    77  
    78    3) For each such seed x:
    79  
    80    3.1)   while (x^3 + alpha * x + beta) is not a square in the prime field:
    81               increase x by 1.
    82  
    83    3.2)   (x, square_root(x^3 + alpha * x + beta)) is a point on the elliptic curve (for square_root
    84           the smaller root).
    85  
    86  
    87    4) The first two points are taken as-is, as they will be used as the shift point and the
    88    ECDSA generator point.
    89  
    90    5) Each subsequent point P is expanded to 248 or 4 points alternatingly, by taking the set
    91    {2^i P : 0 <= i < 248} or {2^i P : 0 <= i < 3}. 248 is chosen to be the largest multiple of 8
    92    lower than 251.
    93  
    94    This is a sage code that implements these steps:
    95  
    96    R = RealField(400000)
    97    long_pi_string = '3' + str(R(pi))[2:]
    98    p = 2^251 + 17 * 2^192 + 1
    99    beta = GF(p)(long_pi_string[:76]) + 379
   100    ec = EllipticCurve(GF(p), [1, beta])
   101    points = []
   102    for i in range(1, 13):
   103        x = GF(p)(int(long_pi_string[i * 76 : (i+1) * 76]))
   104        while not is_square(x^3 + x + beta):
   105            x += 1
   106        P = ec((x, sqrt(x^3 + x + beta)))
   107        if i <= 2:
   108          points.append(P.xy())
   109          continue
   110        for j in range(248 if i%2==1 else 4):
   111            points.append(P.xy())
   112            P *= 2
   113    print "".join("{0x%x_Z,0x%x_Z},\n" % p for p in points)
   114  */
   115  const EllipticCurveConstants<PrimeFieldElement>& GetEcConstants();
   116  
   117  }  // namespace starkware
   118  
   119  #endif  // STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_