/* * gf2nlong.h * */ #ifndef MATH_GF2NLONG_H_ #define MATH_GF2NLONG_H_ #include #include #include using namespace std; #include "Tools/random.h" #include "Tools/intrinsics.h" #include "Math/field_types.h" #include "Math/bigint.h" #include "Math/gf2n.h" bool is_ge(__m128i a, __m128i b); class int128 { public: __m128i a; int128() : a(_mm_setzero_si128()) { } int128(const __m128i& a) : a(a) { } int128(const word& a) : a(_mm_cvtsi64_si128(a)) { } int128(const word& upper, const word& lower) : a(_mm_set_epi64x(upper, lower)) { } word get_lower() const { return (word)_mm_cvtsi128_si64(a); } word get_upper() const { return _mm_cvtsi128_si64(_mm_unpackhi_epi64(a, a)); } word get_half(bool upper) const { return upper ? get_upper() : get_lower(); } #ifdef __SSE41__ bool operator==(const int128& other) const { return _mm_test_all_zeros(a ^ other.a, a ^ other.a); } #else bool operator==(const int128& other) const { return get_lower() == other.get_lower() and get_upper() == other.get_upper(); } #endif bool operator!=(const int128& other) const { return !(*this == other); } bool operator>=(const int128& other) const { return is_ge(a, other.a); } int128 operator<<(const int& other) const; int128 operator>>(const int& other) const; int128 operator^(const int128& other) const { return a ^ other.a; } int128 operator|(const int128& other) const { return a | other.a; } int128 operator&(const int128& other) const { return a & other.a; } int128 operator~() const { return ~a; } int128& operator<<=(const int& other) { return *this = *this << other; } int128& operator>>=(const int& other) { return *this = *this >> other; } int128& operator^=(const int128& other) { a ^= other.a; return *this; } int128& operator|=(const int128& other) { a |= other.a; return *this; } int128& operator&=(const int128& other) { a &= other.a; return *this; } friend ostream& operator<<(ostream& s, const int128& a); friend istream& operator>>(istream& s, int128& a); bool get_bit(int i) const; void randomize(PRNG& G) { *this = G.get_doubleword(); } void to(int128& other) { other = *this; } void to(word& other) { other = get_lower(); } }; template class bit_plus { static const int N_BITS = 8 * sizeof(T); T lower; bool msb; public: bit_plus() : msb(false) { } bit_plus(T lower, bool msb) : lower(lower), msb(msb) { } template bit_plus(U a) : lower(a), msb(false) { } T get_lower() { return lower; } bool operator==(const bit_plus& other) { return (lower == other.lower) && (msb == other.msb); } bool operator!=(const bit_plus& other) { return !(*this == other); } bool operator>=(const bit_plus& other) { return msb == other.msb ? lower >= other.lower : msb > other.msb; } bit_plus operator<<(int other) { return bit_plus(lower << other, ((lower >> (N_BITS-other)) & 1) != 0); } bit_plus& operator>>=(int other) { lower >>= other; lower |= (T(msb) << (N_BITS-other)); msb = !other; return *this; } bit_plus operator^(const bit_plus& other) { return bit_plus(lower ^ other.lower, msb ^ other.msb); } bit_plus& operator^=(const bit_plus& other) { lower ^= other.lower; msb ^= other.msb; return *this; } bit_plus operator&(const word& other) { return bit_plus(lower & other, false); } friend ostream& operator<<(ostream& s, const bit_plus& a) { s << a.msb << a.lower; return s; } }; typedef bit_plus int129; template class Input; template class PrivateOutput; template class SPDZ; template class Share; template class Square; namespace GC { class NoValue; } /* This interface compatible with the gfp interface * which then allows us to template the Share * data type. */ /* Arithmetic in Gf_{2^n} with n<=128 */ class gf2n_long : public gf2n_ { typedef gf2n_ super; public: typedef gf2n_long value_type; typedef gf2n_long next; typedef ::Square Square; typedef gf2n_long Scalar; static int default_degree() { return 128; } static string type_string() { return "gf2n_long"; } word get_word() const { return this->a.get_lower(); } static gf2n_long cut(int128 x) { return x; } gf2n_long() { assign_zero(); } gf2n_long(const super& g) : super(g) {} gf2n_long(const int128& g) : super(g) {} gf2n_long(int g) : gf2n_long(int128(unsigned(g))) {} template gf2n_long(IntBase g) : super(g.get()) {} template gf2n_long(const gf2n_& a) : super(int128(a.get())) {} }; #if defined(__aarch64__) && defined(__clang__) inline __m128i my_slli(int128 x, int i) { if (i < 64) return int128(x.get_upper() << i, x.get_lower() << i).a; else return int128().a; } inline __m128i my_srli(int128 x, int i) { if (i < 64) return int128(x.get_upper() >> i, x.get_lower() >> i).a; else return int128().a; } #undef _mm_slli_epi64 #undef _mm_srli_epi64 #define _mm_slli_epi64 my_slli #define _mm_srli_epi64 my_srli #endif inline int128 int128::operator<<(const int& other) const { int128 res(_mm_slli_epi64(a, other)); __m128i mask; if (other < 64) mask = _mm_srli_epi64(a, 64 - other); else mask = _mm_slli_epi64(a, other - 64); res.a ^= _mm_slli_si128(mask, 8); return res; } inline int128 int128::operator>>(const int& other) const { int128 res(_mm_srli_epi64(a, other)); __m128i mask; if (other < 64) mask = _mm_slli_epi64(a, 64 - other); else mask = _mm_srli_epi64(a, other - 64); res.a ^= _mm_srli_si128(mask, 8); return res; } void mul(word x, word y, word& lo, word& hi); inline __m128i software_clmul(__m128i a, __m128i b, int choice) { word lo, hi; mul(int128(a).get_half(choice & 1), int128(b).get_half((choice & 0x10) >> 4), lo, hi); return int128(hi, lo).a; } template inline __m128i clmul(__m128i a, __m128i b) { #if defined(__PCLMUL__) || !defined(__x86_64__) if (cpu_has_pclmul()) { return _mm_clmulepi64_si128(a, b, choice); } else #endif return software_clmul(a, b, choice); } inline void mul128(__m128i a, __m128i b, __m128i *res1, __m128i *res2) { __m128i tmp3, tmp4, tmp5, tmp6; tmp3 = clmul<0x00>(a, b); tmp4 = clmul<0x10>(a, b); tmp5 = clmul<0x01>(a, b); tmp6 = clmul<0x11>(a, b); tmp4 = _mm_xor_si128(tmp4, tmp5); tmp5 = _mm_slli_si128(tmp4, 8); tmp4 = _mm_srli_si128(tmp4, 8); tmp3 = _mm_xor_si128(tmp3, tmp5); tmp6 = _mm_xor_si128(tmp6, tmp4); // initial mul now in tmp3, tmp6 *res1 = tmp3; *res2 = tmp6; } inline void mul(int128 a, int128 b, int128& lo, int128& hi) { mul128(a.a, b.a, &lo.a, &hi.a); } inline bool int128::get_bit(int i) const { if (i < 64) return (get_lower() >> i) & 1; else return (get_upper() >> (i - 64)) & 1; } #endif /* MATH_GF2NLONG_H_ */