/** @file ***************************************************************************** Declaration of arithmetic in the finite field F[p], for prime p of fixed length. ***************************************************************************** * @author This file is part of libsnark, developed by SCIPR Lab * and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ #ifndef FP_HPP_ #define FP_HPP_ #include "algebra/fields/bigint.hpp" #include "algebra/exponentiation/exponentiation.hpp" namespace libsnark { template& modulus> class Fp_model; template& modulus> std::ostream& operator<<(std::ostream &, const Fp_model&); template& modulus> std::istream& operator>>(std::istream &, Fp_model &); /** * Arithmetic in the finite field F[p], for prime p of fixed length. * * This class implements Fp-arithmetic, for a large prime p, using a fixed number * of words. It is optimized for tight memory consumption, so the modulus p is * passed as a template parameter, to avoid per-element overheads. * * The implementation is mostly a wrapper around GMP's MPN (constant-size integers). * But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each), * we implement performance-critical routines, like addition and multiplication, * using hand-optimized assembly code. */ template& modulus> class Fp_model { public: bigint mont_repr; public: static const mp_size_t num_limbs = n; static const constexpr bigint& mod = modulus; #ifdef PROFILE_OP_COUNTS static long long add_cnt; static long long sub_cnt; static long long mul_cnt; static long long sqr_cnt; static long long inv_cnt; #endif static size_t num_bits; static bigint euler; // (modulus-1)/2 static size_t s; // modulus = 2^s * t + 1 static bigint t; // with t odd static bigint t_minus_1_over_2; // (t-1)/2 static Fp_model nqr; // a quadratic nonresidue static Fp_model nqr_to_t; // nqr^t static Fp_model multiplicative_generator; // generator of Fp^* static Fp_model root_of_unity; // generator^((modulus-1)/2^s) static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size) static bigint Rsquared; // R^2, where R = W^k, where k = ?? static bigint Rcubed; // R^3 static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero Fp_model() {}; Fp_model(const bigint &b); Fp_model(const long x, const bool is_unsigned=false); void set_ulong(const unsigned long x); void mul_reduce(const bigint &other); void clear(); /* Return the standard (not Montgomery) representation of the Field element's requivalence class. I.e. Fp(2).as_bigint() would return bigint(2) */ bigint as_bigint() const; /* Return the last limb of the standard representation of the field element. E.g. on 64-bit architectures Fp(123).as_ulong() and Fp(2^64+123).as_ulong() would both return 123. */ unsigned long as_ulong() const; bool operator==(const Fp_model& other) const; bool operator!=(const Fp_model& other) const; bool is_zero() const; void print() const; Fp_model& operator+=(const Fp_model& other); Fp_model& operator-=(const Fp_model& other); Fp_model& operator*=(const Fp_model& other); Fp_model& operator^=(const unsigned long pow); template Fp_model& operator^=(const bigint &pow); Fp_model operator+(const Fp_model& other) const; Fp_model operator-(const Fp_model& other) const; Fp_model operator*(const Fp_model& other) const; Fp_model operator-() const; Fp_model squared() const; Fp_model& invert(); Fp_model inverse() const; Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) Fp_model operator^(const unsigned long pow) const; template Fp_model operator^(const bigint &pow) const; static size_t size_in_bits() { return num_bits; } static size_t capacity() { return num_bits - 1; } static bigint field_char() { return modulus; } static Fp_model zero(); static Fp_model one(); static Fp_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp_model &p); friend std::istream& operator>> (std::istream &in, Fp_model &p); }; #ifdef PROFILE_OP_COUNTS template& modulus> long long Fp_model::add_cnt = 0; template& modulus> long long Fp_model::sub_cnt = 0; template& modulus> long long Fp_model::mul_cnt = 0; template& modulus> long long Fp_model::sqr_cnt = 0; template& modulus> long long Fp_model::inv_cnt = 0; #endif template& modulus> size_t Fp_model::num_bits; template& modulus> bigint Fp_model::euler; template& modulus> size_t Fp_model::s; template& modulus> bigint Fp_model::t; template& modulus> bigint Fp_model::t_minus_1_over_2; template& modulus> Fp_model Fp_model::nqr; template& modulus> Fp_model Fp_model::nqr_to_t; template& modulus> Fp_model Fp_model::multiplicative_generator; template& modulus> Fp_model Fp_model::root_of_unity; template& modulus> mp_limb_t Fp_model::inv; template& modulus> bigint Fp_model::Rsquared; template& modulus> bigint Fp_model::Rcubed; } // libsnark #include "algebra/fields/fp.tcc" #endif // FP_HPP_