/* * Z2k.h * */ #ifndef MATH_Z2K_H_ #define MATH_Z2K_H_ #include #include using namespace std; #include "Tools/avx_memcpy.h" #include "bigint.h" #include "field_types.h" #include "mpn_fixed.h" #include "ValueInterface.h" template class Z2 : public ValueInterface { template friend class Z2; friend class bigint; static const int N_WORDS = ((K + 7) / 8 + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); static const int N_LIMB_BITS = 8 * sizeof(mp_limb_t); static const uint64_t UPPER_MASK = ((K % N_LIMB_BITS) == 0) ? -1 : -1 + (1LL << (K % N_LIMB_BITS)); mp_limb_t a[N_WORDS]; public: typedef void Inp; typedef void PO; class DummyZ2kProtocol { public: static void assign(Z2& _, const Z2& __, int& ___) { (void) _, (void) __, (void) ___; throw not_implemented(); } }; typedef DummyZ2kProtocol Protocol; static const int N_BITS = K; static const int N_BYTES = (K + 7) / 8; static int size() { return N_BYTES; } static int t() { return 0; } static char type_char() { return 'Z'; } static string type_string() { return "Z2^" + to_string(int(N_BITS)); } static DataFieldType field_type() { return DATA_INT; } static const bool invertible = false; template static Z2 Mul(const Z2& x, const Z2& y); typedef Z2 value_type; typedef Z2 next; Z2() { assign_zero(); } Z2(uint64_t x) : Z2() { a[0] = x; } Z2(__m128i x) : Z2() { avx_memcpy(a, &x, min(N_BYTES, 16)); } Z2(int x) : Z2(long(x)) { a[N_WORDS - 1] &= UPPER_MASK; } Z2(long x) : Z2(uint64_t(x)) { if (K > 64 and x < 0) memset(&a[1], -1, N_BYTES - 8); } Z2(const Integer& x); Z2(const bigint& x); Z2(const void* buffer) : Z2() { assign(buffer); } template Z2(const Z2& x) : Z2() { avx_memcpy(a, x.a, min(N_BYTES, x.N_BYTES)); normalize(); } void normalize() { a[N_WORDS - 1] &= UPPER_MASK; } void assign_zero() { avx_memzero(a, sizeof(a)); } void assign_one() { assign_zero(); a[0] = 1; } void assign(const void* buffer) { avx_memcpy(a, buffer, N_BYTES); normalize(); } void assign(int x) { *this = x; } mp_limb_t get_limb(int i) const { return a[i]; } bool get_bit(int i) const; const void* get_ptr() const { return a; } void negate() { throw not_implemented(); } Z2 operator+(const Z2& other) const; Z2 operator-(const Z2& other) const; template Z2 operator*(const Z2& other) const; Z2 operator*(bool other) const { return other ? *this : Z2(); } Z2 operator/(const Z2& other) const { (void) other; throw not_implemented(); } Z2& operator+=(const Z2& other); Z2& operator-=(const Z2& other); Z2 operator<<(int i) const; Z2 operator>>(int i) const; bool operator==(const Z2& other) const; bool operator!=(const Z2& other) const { return not (*this == other); } void add(const Z2& a, const Z2& b) { *this = a + b; } void add(const Z2& a) { *this += a; } void sub(const Z2& a, const Z2& b) { *this = a - b; } template void mul(const Z2& a, const Z2& b) { *this = Z2::Mul(a, b); } template void mul(const Integer& a, const Z2& b) { *this = Z2::Mul(Z2<64>(a), b); } template void add(octetStream& os) { add(os.consume(size())); } Z2& invert(); Z2 sqrRoot(); bool is_zero() { return *this == Z2(); } void randomize(PRNG& G); void almost_randomize(PRNG& G) { randomize(G); } void pack(octetStream& o) const; void unpack(octetStream& o); void input(istream& s, bool human=true); void output(ostream& s, bool human=true) const; template friend ostream& operator<<(ostream& o, const Z2& x); }; template inline Z2 Z2::operator+(const Z2& other) const { Z2 res; mpn_add_fixed_n(res.a, a, other.a); res.a[N_WORDS - 1] &= UPPER_MASK; return res; } template Z2 Z2::operator-(const Z2& other) const { Z2 res; mpn_sub_fixed_n(res.a, a, other.a); res.a[N_WORDS - 1] &= UPPER_MASK; return res; } template inline Z2& Z2::operator+=(const Z2& other) { mpn_add_fixed_n(a, other.a, a); a[N_WORDS - 1] &= UPPER_MASK; return *this; } template Z2& Z2::operator-=(const Z2& other) { *this = *this - other; return *this; } template template inline Z2 Z2::Mul(const Z2& x, const Z2& y) { Z2 res; mpn_mul_fixed_::N_WORDS, Z2::N_WORDS>(res.a, x.a, y.a); res.a[N_WORDS - 1] &= UPPER_MASK; return res; } template template inline Z2 Z2::operator*(const Z2& other) const { return Z2::Mul(*this, other); } template Z2 Z2::operator<<(int i) const { Z2 res; int n_limb_shift = i / N_LIMB_BITS; for (int j = n_limb_shift; j < N_WORDS; j++) res.a[j] = a[j - n_limb_shift]; int n_inside_shift = i % N_LIMB_BITS; if (n_inside_shift > 0) mpn_lshift(res.a, res.a, N_WORDS, n_inside_shift); res.a[N_WORDS - 1] &= UPPER_MASK; return res; } template Z2 Z2::operator>>(int i) const { Z2 res; int n_byte_shift = i / 8; memcpy(res.a, (char*)a + n_byte_shift, N_BYTES - n_byte_shift); int n_inside_shift = i % 8; if (n_inside_shift > 0) mpn_rshift(res.a, res.a, N_WORDS, n_inside_shift); return res; } template void Z2::randomize(PRNG& G) { G.get_octets((octet*)a); normalize(); } template void Z2::pack(octetStream& o) const { o.append((octet*)a, N_BYTES); } template void Z2::unpack(octetStream& o) { o.consume((octet*)a, N_BYTES); } #endif /* MATH_Z2K_H_ */