/* * 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 { protected: 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 = uint64_t(-1LL) >> (N_LIMB_BITS - 1 - (K - 1) % N_LIMB_BITS); mp_limb_t a[N_WORDS]; public: typedef void Inp; typedef void PO; typedef void Square; 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 size_in_limbs() { return N_WORDS; } static int t() { return 0; } static char type_char() { return 'R'; } 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); static void reqbl(int n); static bool allows(Dtype dtype); 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; } const mp_limb_t* get() const { return a; } void convert_destroy(bigint& a) { *this = 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); } void mul(const Z2& a) { *this = Z2::Mul(*this, a); } template void add(octetStream& os) { add(os.consume(size())); } Z2& invert(); void invert(const Z2& a) { *this = a; invert(); } Z2 sqrRoot(); bool is_zero() const { return *this == Z2(); } bool is_one() const { return *this == 1; } bool is_bit() const { return is_zero() or is_one(); } void SHL(const Z2& a, const bigint& i) { *this = a << i.get_ui(); } void SHR(const Z2& a, const bigint& i) { *this = a >> i.get_ui(); } void AND(const Z2& a, const Z2& b); void OR(const Z2& a, const Z2& b); void XOR(const Z2& a, const Z2& b); void randomize(PRNG& G); void almost_randomize(PRNG& G) { randomize(G); } void force_to_bit() { throw runtime_error("impossible"); } 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 class SignedZ2 : public Z2 { public: SignedZ2() { } template SignedZ2(const SignedZ2& other) : Z2(other) { if (K < L and other.negative()) { this->a[Z2::N_WORDS - 1] |= ~Z2::UPPER_MASK; for (int i = Z2::N_WORDS; i < this->N_WORDS; i++) this->a[i] = -1; } } SignedZ2(const Integer& other) : SignedZ2(SignedZ2<64>(other)) { } template SignedZ2(const T& other) : Z2(other) { } bool negative() const { return this->a[this->N_WORDS - 1] & 1ll << ((K - 1) % (8 * sizeof(mp_limb_t))); } SignedZ2 operator-() const { return SignedZ2() - *this; } SignedZ2 operator-(const SignedZ2& other) const { return Z2::operator-(other); } void output(ostream& s, bool human = true) const; }; 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); } template void to_gfp(Z2& res, const bigint& a) { res = a; } template SignedZ2 abs(const SignedZ2& x) { if (x.negative()) return -x; else return x; } template void SignedZ2::output(ostream& s, bool human) const { if (human) { bigint::tmp = *this; s << bigint::tmp; } else Z2::output(s, false); } template ostream& operator<<(ostream& o, const SignedZ2& x) { x.output(o, true); return o; } template inline void to_signed_bigint(bigint& res, const SignedZ2& x, int n) { bigint tmp = x; to_signed_bigint(res, tmp, n); } #endif /* MATH_Z2K_H_ */