#include "Fp.hpp" extern const double bn_v; Fp::Fp() { fpe_setzero(element); no_change = false; } Fp::Fp(const fpe_t & input) { set(input); no_change = false; } Fp::Fp(int input) { set(input); no_change = false; } void Fp::set(const fpe_t & fpe) { fpe_set(element, fpe); no_change = false; } void Fp::set(int input) { mydouble[12] coefficient_matrix; for (int i = 0; i < 12; i++) { switch (i) { case 0: coefficient_matrix[i] = ((mydouble) input); break; default: coefficient_matrix[i] = 0.; } } fpe_set_doublearray(element, coefficient_matrix); if (input > ((int) bn_v) * 3) { fpe_short_coeffred(element) } no_change = false; } void Fp::set_random() { // c.f. https://www.cryptojedi.org/papers/dclxvi-20100714.pdf for these maxes const int MAX_A = ((int) bn_v) * 3; const int MAX_B = ((int) bn_v) / 2 + 1; std::random_device generator; std::uniform_int_distribution distribution_a(-MAX_A, MAX_A); std::uniform_int_distribution distribution_b(-MAX_B, MAX_B); mydouble[12] coefficient_matrix; for (int i = 0; i < 12; i++) { switch (i) { case 0: case 6: coefficient_matrix[i] = ((mydouble) distribution_a(generator)); break; default: coefficient_matrix[i] = ((mydouble) distribution_b(generator)); } } fpe_set_doublearray(element, coefficient_matrix); no_change = false; } Fp Fp::operator-() const { fpe_t temp; fpe_neg(temp, element); return Fp(temp); } Fp Fp::operator+(const Fp & b) const { fpe_t temp; fpe_add(temp, element, b.element); return Fp(temp); } Fp Fp::operator-(const Fp & b) const { fpe_t temp; fpe_sub(temp, element, b.element); return Fp(temp); } Fp Fp::operator*(const Fp & b) const { fpe_t temp; fpe_mul(temp, element, b.element); return Fp(temp); } Fp Fp::operator/(const Fp & b) const { fpe_t temp; fpe_invert(temp, b.element); fpe_mul(temp, element, temp); return Fp(temp); } bool Fp::operator==(const Fp & b) const { return fpe_iseq(element, b.element) == 1; } bool Fp::operator!=(const Fp & b) const { return fpe_iseq(element, b.element) == 0; } bool Fp::is_zero() const { return fpe_iszero(element) == 1; } scalar_t& Fp::to_scalar() const { if (no_change) return scalar; mpz_class poly_at_one = 1.; mpz_class increment_factor = bn_v * 6; for (int i = 0; i < 12; i++) { switch (i) { case 0: poly_at_one = todouble(element->v[0]); break; case 1: case 2: case 3: case 4: case 5: case 6: poly_at_one += increment_factor * todouble(element->v[i]); increment_factor *= bn_v; break; case 7: increment_factor *= 6.; poly_at_one += increment_factor * todouble(element->v[i]); increment_factor *= bn_v; break; default: poly_at_one += increment_factor * todouble(element->v[i]); increment_factor *= bn_v; break; } } mpz_class bn_u = 1; for (int i = 0; i < 3; i++) bn_u *= bn_v; mpz_class bn_p; bn_p = 36*bn_u*bn_u*bn_u*bn_u + 36*bn_u*bn_u*bn_u + 24*bn_u*bn_u + 6*bn_u + 1; mpz_class field_element = poly_at_one % bn_p; mpz_class mask = 0xffffffffffffffff; // 8 octets 64 bits scalar[0] = mpz2ull( field_element & mask); scalar[1] = mpz2ull((field_element >> 64) & mask); scalar[2] = mpz2ull((field_element >> 128) & mask); scalar[3] = mpz2ull((field_element >> 192) & mask); no_change = true; return scalar; } std::ostream& operator<<(std::ostream& os, const Fp& output) { if (!output.no_change) output.to_scalar(); os << output.scalar[3] << output.scalar[2] << output.scalar[1] << output.scalar[0]; return os; } unsigned long long Fp::mpz2ull(const mpz_class& n) const { stringstream str; unsigned long long retval; str << n; str >> retval; return retval; }