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

     1  #ifndef STARKWARE_ALGEBRA_PRIME_FIELD_ELEMENT_H_
     2  #define STARKWARE_ALGEBRA_PRIME_FIELD_ELEMENT_H_
     3  
     4  #include <array>
     5  #include <cstddef>
     6  #include <cstdint>
     7  #include <limits>
     8  #include <string>
     9  #include <tuple>
    10  #include <utility>
    11  #include <vector>
    12  
    13  #include "big_int.h"
    14  #include "error_handling.h"
    15  #include "prng.h"
    16  
    17  namespace starkware {
    18  
    19  /*
    20    Represents an element of GF(p) for p = 2^251 + 17 * 2^192 + 1.
    21    The value is stored in Montgomery representation.
    22  */
    23  class PrimeFieldElement {
    24   public:
    25    using ValueType = BigInt<4>;
    26    static constexpr ValueType kModulus =
    27        0x800000000000011000000000000000000000000000000000000000000000001_Z;
    28    static constexpr ValueType kMontgomeryR =
    29        0x7fffffffffffdf0ffffffffffffffffffffffffffffffffffffffffffffffe1_Z;
    30    static constexpr ValueType kMontgomeryRSquared =
    31        0x7ffd4ab5e008810ffffffffff6f800000000001330ffffffffffd737e000401_Z;
    32    static constexpr ValueType kMontgomeryRCubed =
    33        0x38e5f79873c0a6df47d84f8363000187545706677ffcc06cc7177d1406df18e_Z;
    34    static constexpr uint64_t kMontgomeryMPrime = ~uint64_t(0);
    35    static constexpr ValueType kHalfMultiplicativeGroupSize =
    36        0x400000000000008800000000000000000000000000000000000000000000000_Z;
    37  
    38    PrimeFieldElement() = delete;
    39  
    40    static PrimeFieldElement FromUint(uint64_t val) {
    41      return PrimeFieldElement(
    42          // Note that because MontgomeryMul divides by r we need to multiply by r^2 here.
    43          MontgomeryMul(ValueType(val), kMontgomeryRSquared));
    44    }
    45  
    46    static constexpr PrimeFieldElement FromBigInt(const ValueType& val) {
    47      return PrimeFieldElement(
    48          // Note that because MontgomeryMul divides by r we need to multiply by r^2 here.
    49          MontgomeryMul(val, kMontgomeryRSquared));
    50    }
    51  
    52    static PrimeFieldElement RandomElement(Prng* prng);
    53  
    54    static constexpr PrimeFieldElement Zero() { return PrimeFieldElement(ValueType({})); }
    55  
    56    static constexpr PrimeFieldElement One() { return PrimeFieldElement(kMontgomeryR); }
    57  
    58    PrimeFieldElement operator*(const PrimeFieldElement& rhs) const {
    59      return PrimeFieldElement(MontgomeryMul(value_, rhs.value_));
    60    }
    61  
    62    PrimeFieldElement operator+(const PrimeFieldElement& rhs) const {
    63      return PrimeFieldElement{ValueType::ReduceIfNeeded(value_ + rhs.value_, kModulus)};
    64    }
    65  
    66    PrimeFieldElement operator-(const PrimeFieldElement& rhs) const {
    67      return PrimeFieldElement{(value_ >= rhs.value_) ? (value_ - rhs.value_)
    68                                                      : (value_ + kModulus - rhs.value_)};
    69    }
    70  
    71    PrimeFieldElement operator-() const { return Zero() - *this; }
    72  
    73    PrimeFieldElement operator/(const PrimeFieldElement& rhs) const { return *this * rhs.Inverse(); }
    74  
    75    bool operator==(const PrimeFieldElement& rhs) const { return value_ == rhs.value_; }
    76    bool operator!=(const PrimeFieldElement& rhs) const { return !(*this == rhs); }
    77  
    78    PrimeFieldElement Inverse() const {
    79      ASSERT(*this != PrimeFieldElement::Zero(), "Zero does not have an inverse");
    80      return Pow((kModulus - 0x2_Z).ToBoolVector());
    81    }
    82  
    83    /*
    84      Returns the power of a field element, where exponent_bits[0] is the least significant bit of the
    85      exponent.
    86      Note that this function doesn't support negative exponents.
    87    */
    88    PrimeFieldElement Pow(const std::vector<bool>& exponent_bits) const;
    89  
    90    /*
    91      Returns the power of a field element for the given exponent.
    92    */
    93    PrimeFieldElement Pow(const uint64_t exponent) const;
    94  
    95    /*
    96      For a field element x, returns true if there exists a field element y such that x = y^2.
    97    */
    98    bool IsSquare() const;
    99  
   100    /*
   101      For a field element x, returns an element y such that y^2 = x. If no such y exists, the function
   102      throws an exception.
   103    */
   104    PrimeFieldElement Sqrt() const;
   105  
   106    /*
   107      Returns the standard representation.
   108  
   109      A value in the range [0, kBigPrimeConstants::kModulus) in non-Montogomery representation.
   110    */
   111    ValueType ToStandardForm() const { return MontgomeryMul(value_, ValueType::One()); }
   112  
   113    std::string ToString() const { return ToStandardForm().ToString(); }
   114  
   115   private:
   116    explicit constexpr PrimeFieldElement(ValueType val) : value_(val) {}
   117  
   118    static constexpr ValueType MontgomeryMul(const ValueType& x, const ValueType& y) {
   119      return ValueType::MontMul(x, y, kModulus, kMontgomeryMPrime);
   120    }
   121  
   122    ValueType value_;
   123  };
   124  
   125  inline std::ostream& operator<<(std::ostream& out, const PrimeFieldElement& element) {
   126    return out << element.ToString();
   127  }
   128  
   129  }  // namespace starkware
   130  
   131  #endif  // STARKWARE_ALGEBRA_PRIME_FIELD_ELEMENT_H_