erigon-pulse/erigon-lib/pedersen_hash/elliptic_curve_constants.h
battlmonstr 231e468e19 Add 'erigon-lib/' from commit '93d9c9d9fe4bd8a49f7a98a6bce0f0da7094c7d3'
git-subtree-dir: erigon-lib
git-subtree-mainline: 3c8cbda809
git-subtree-split: 93d9c9d9fe
2023-09-20 14:50:25 +02:00

120 lines
4.3 KiB
C++

#ifndef STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_
#define STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_
#include <array>
#include <utility>
#include <vector>
#include "big_int.h"
#include "elliptic_curve.h"
#include "prime_field_element.h"
namespace starkware {
/*
Contains a set of constants that go along with an elliptic curve.
FieldElementT is the underlying field of the curve.
The equation of the elliptic curve is y^2 = x^3 + k_alpha * x + k_beta.
k_order is the size of the group.
k_points are points on the curve that were generated independently in a "nothing up my sleeve"
manner to ensure that no one knows their discrete log.
*/
template <typename FieldElementT>
struct EllipticCurveConstants {
public:
using ValueType = typename FieldElementT::ValueType;
const FieldElementT k_alpha;
const FieldElementT k_beta;
const ValueType k_order;
const std::vector<EcPoint<FieldElementT>> k_points;
constexpr EllipticCurveConstants(
const FieldElementT& k_alpha, const FieldElementT& k_beta, const ValueType& k_order,
std::vector<EcPoint<FieldElementT>> k_points) noexcept
: k_alpha(k_alpha), k_beta(k_beta), k_order(k_order), k_points(std::move(k_points)) {}
constexpr EllipticCurveConstants(
const ValueType& k_alpha, const ValueType& k_beta, const ValueType& k_order,
std::initializer_list<std::pair<ValueType, ValueType>> k_points) noexcept
: EllipticCurveConstants(
FieldElementT::FromBigInt(k_alpha), FieldElementT::FromBigInt(k_beta), k_order,
ECPointsVectorFromPairs(std::move(k_points))) {}
private:
static std::vector<EcPoint<FieldElementT>> ECPointsVectorFromPairs(
std::initializer_list<std::pair<ValueType, ValueType>> k_points) {
std::vector<EcPoint<FieldElementT>> res;
res.reserve(k_points.size());
for (const auto& p : k_points) {
res.emplace_back(FieldElementT::FromBigInt(p.first), FieldElementT::FromBigInt(p.second));
}
return res;
}
};
/*
This elliptic curve over the prime field PrimeFieldElement was chosen in a "nothing up my sleeve"
manner to show that we don't know any special properties of this curve (other than being of prime
order).
alpha was chosen to be 1 because any elliptic curve has an isomorphic curve with a small alpha,
but we didn't want a zero alpha because then the discriminant is small.
beta was generated in the following way:
1) Take beta to be the integer whose digits are the first 76 decimal digits of pi (76 is the
number of digits required to represent a field element).
2) While [y^2 = x^3 + alpha * x + beta] is not a curve of prime order, increase beta by 1.
The points were generated by the following steps:
1) Take the decimal digits of pi and split them into chunks of 76 digits (the number of decimal
digits of the modulus).
2) Each chunk of 76 digits is the seed for generating a point, except for the first chunk
which was used for generating the curve.
3) For each such seed x:
3.1) while (x^3 + alpha * x + beta) is not a square in the prime field:
increase x by 1.
3.2) (x, square_root(x^3 + alpha * x + beta)) is a point on the elliptic curve (for square_root
the smaller root).
4) The first two points are taken as-is, as they will be used as the shift point and the
ECDSA generator point.
5) Each subsequent point P is expanded to 248 or 4 points alternatingly, by taking the set
{2^i P : 0 <= i < 248} or {2^i P : 0 <= i < 3}. 248 is chosen to be the largest multiple of 8
lower than 251.
This is a sage code that implements these steps:
R = RealField(400000)
long_pi_string = '3' + str(R(pi))[2:]
p = 2^251 + 17 * 2^192 + 1
beta = GF(p)(long_pi_string[:76]) + 379
ec = EllipticCurve(GF(p), [1, beta])
points = []
for i in range(1, 13):
x = GF(p)(int(long_pi_string[i * 76 : (i+1) * 76]))
while not is_square(x^3 + x + beta):
x += 1
P = ec((x, sqrt(x^3 + x + beta)))
if i <= 2:
points.append(P.xy())
continue
for j in range(248 if i%2==1 else 4):
points.append(P.xy())
P *= 2
print "".join("{0x%x_Z,0x%x_Z},\n" % p for p in points)
*/
const EllipticCurveConstants<PrimeFieldElement>& GetEcConstants();
} // namespace starkware
#endif // STARKWARE_CRYPTO_ELLIPTIC_CURVE_CONSTANTS_H_