// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include "seal/util/common.h" #include #include "gtest/gtest.h" using namespace seal; using namespace seal::util; using namespace std; namespace sealtest { namespace util { TEST(Common, Constants) { ASSERT_EQ(4, bits_per_nibble); ASSERT_EQ(8, bits_per_byte); ASSERT_EQ(8, bytes_per_uint64); ASSERT_EQ(64, bits_per_uint64); ASSERT_EQ(2, nibbles_per_byte); ASSERT_EQ(16, nibbles_per_uint64); } TEST(Common, UnsignedComparisons) { int pos_i = 5; int neg_i = -5; unsigned pos_u = 6; signed pos_s = 6; unsigned char pos_uc = 1; signed char neg_sc = -1; signed char pos_sc = 1; unsigned char pos_uc_max = 0xFF; unsigned long long pos_ull = 1; unsigned long long pos_ull_max = 0xFFFFFFFFFFFFFFFF; long long neg_ull = -1; ASSERT_TRUE(unsigned_eq(pos_i, pos_i)); ASSERT_FALSE(unsigned_eq(pos_i, neg_i)); ASSERT_TRUE(unsigned_gt(pos_u, pos_i)); ASSERT_TRUE(unsigned_lt(pos_i, neg_i)); ASSERT_TRUE(unsigned_geq(pos_u, pos_s)); ASSERT_TRUE(unsigned_gt(neg_sc, pos_sc)); ASSERT_TRUE(unsigned_geq(neg_sc, pos_sc)); ASSERT_FALSE(unsigned_eq(neg_sc, pos_sc)); ASSERT_FALSE(unsigned_gt(pos_u, neg_sc)); ASSERT_TRUE(unsigned_eq(pos_uc, pos_sc)); ASSERT_TRUE(unsigned_geq(pos_uc, pos_sc)); ASSERT_TRUE(unsigned_leq(pos_uc, pos_sc)); ASSERT_TRUE(unsigned_lt(pos_uc_max, neg_sc)); ASSERT_TRUE(unsigned_eq(neg_sc, pos_ull_max)); ASSERT_TRUE(unsigned_eq(neg_ull, pos_ull_max)); ASSERT_FALSE(unsigned_lt(neg_ull, pos_ull_max)); ASSERT_TRUE(unsigned_lt(pos_ull, pos_ull_max)); } TEST(Common, SafeArithmetic) { int pos_i = 5; int neg_i = -5; unsigned pos_u = 6; unsigned char pos_uc_max = 0xFF; unsigned long long pos_ull_max = 0xFFFFFFFFFFFFFFFF; long long neg_ull = -1; SEAL_MAYBE_UNUSED unsigned long long res_ul; SEAL_MAYBE_UNUSED long long res_l; ASSERT_EQ(25, mul_safe(pos_i, pos_i)); ASSERT_EQ(25, mul_safe(neg_i, neg_i)); ASSERT_EQ(10, add_safe(pos_i, pos_i)); ASSERT_EQ(-10, add_safe(neg_i, neg_i)); ASSERT_EQ(0, add_safe(pos_i, neg_i)); ASSERT_EQ(0, add_safe(neg_i, pos_i)); ASSERT_EQ(10, sub_safe(pos_i, neg_i)); ASSERT_EQ(-10, sub_safe(neg_i, pos_i)); ASSERT_EQ(unsigned(0), sub_safe(pos_u, pos_u)); ASSERT_THROW(res_ul = sub_safe(unsigned(0), pos_u), logic_error); ASSERT_THROW(res_ul = sub_safe(unsigned(4), pos_u), logic_error); ASSERT_THROW(res_ul = add_safe(pos_uc_max, (unsigned char)1), logic_error); ASSERT_TRUE(pos_uc_max == add_safe(pos_uc_max, (unsigned char)0)); ASSERT_THROW(res_ul = mul_safe(pos_ull_max, pos_ull_max), logic_error); ASSERT_EQ(0ULL, mul_safe(0ULL, pos_ull_max)); ASSERT_TRUE((long long)1 == mul_safe(neg_ull, neg_ull)); ASSERT_THROW(res_ul = mul_safe(pos_uc_max, pos_uc_max), logic_error); ASSERT_EQ(15, add_safe(pos_i, -pos_i, pos_i, pos_i, pos_i)); ASSERT_EQ(6, add_safe(0, -pos_i, pos_i, 1, pos_i)); ASSERT_EQ(0, mul_safe(pos_i, pos_i, pos_i, 0, pos_i)); ASSERT_EQ(625, mul_safe(pos_i, pos_i, pos_i, pos_i)); ASSERT_THROW( res_l = mul_safe( pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i, pos_i), logic_error); } TEST(Common, FitsIn) { int neg_i = -5; signed pos_s = 6; unsigned char pos_uc = 1; unsigned char pos_uc_max = 0xFF; float f = 1.234f; double d = -1234; ASSERT_TRUE(fits_in(pos_s)); ASSERT_TRUE(fits_in(pos_uc)); ASSERT_FALSE(fits_in(neg_i)); ASSERT_FALSE(fits_in(pos_uc_max)); ASSERT_TRUE(fits_in(d)); ASSERT_TRUE(fits_in(f)); ASSERT_TRUE(fits_in(d)); ASSERT_TRUE(fits_in(f)); ASSERT_FALSE(fits_in(d)); } TEST(Common, DivideRoundUp) { ASSERT_EQ(0, divide_round_up(0, 4)); ASSERT_EQ(1, divide_round_up(1, 4)); ASSERT_EQ(1, divide_round_up(2, 4)); ASSERT_EQ(1, divide_round_up(3, 4)); ASSERT_EQ(1, divide_round_up(4, 4)); ASSERT_EQ(2, divide_round_up(5, 4)); ASSERT_EQ(2, divide_round_up(6, 4)); ASSERT_EQ(2, divide_round_up(7, 4)); ASSERT_EQ(2, divide_round_up(8, 4)); ASSERT_EQ(3, divide_round_up(9, 4)); ASSERT_EQ(3, divide_round_up(12, 4)); ASSERT_EQ(4, divide_round_up(13, 4)); } TEST(Common, HammingWeight) { ASSERT_EQ(0, hamming_weight(0)); ASSERT_EQ(8, hamming_weight(0xFF)); ASSERT_EQ(4, hamming_weight(0xF0)); ASSERT_EQ(4, hamming_weight(0x0F)); ASSERT_EQ(2, hamming_weight(0xC0)); ASSERT_EQ(2, hamming_weight(0x0C)); ASSERT_EQ(2, hamming_weight(0x03)); ASSERT_EQ(2, hamming_weight(0x30)); ASSERT_EQ(4, hamming_weight(0xAA)); ASSERT_EQ(4, hamming_weight(0x55)); ASSERT_EQ(5, hamming_weight(0xD6)); ASSERT_EQ(5, hamming_weight(0x6D)); ASSERT_EQ(7, hamming_weight(0xBF)); ASSERT_EQ(7, hamming_weight(0xFB)); } template void ReverseBits32Helper() { ASSERT_EQ(static_cast(0), reverse_bits(static_cast(0))); ASSERT_EQ(static_cast(0x80000000), reverse_bits(static_cast(1))); ASSERT_EQ(static_cast(0x40000000), reverse_bits(static_cast(2))); ASSERT_EQ(static_cast(0xC0000000), reverse_bits(static_cast(3))); ASSERT_EQ(static_cast(0x00010000), reverse_bits(static_cast(0x00008000))); ASSERT_EQ(static_cast(0xFFFF0000), reverse_bits(static_cast(0x0000FFFF))); ASSERT_EQ(static_cast(0x0000FFFF), reverse_bits(static_cast(0xFFFF0000))); ASSERT_EQ(static_cast(0x00008000), reverse_bits(static_cast(0x00010000))); ASSERT_EQ(static_cast(3), reverse_bits(static_cast(0xC0000000))); ASSERT_EQ(static_cast(2), reverse_bits(static_cast(0x40000000))); ASSERT_EQ(static_cast(1), reverse_bits(static_cast(0x80000000))); ASSERT_EQ(static_cast(0xFFFFFFFF), reverse_bits(static_cast(0xFFFFFFFF))); // Reversing a 0-bit item should return 0 ASSERT_EQ(static_cast(0), reverse_bits(static_cast(0xFFFFFFFF), 0)); // Reversing a 32-bit item returns is same as normal reverse ASSERT_EQ(static_cast(0), reverse_bits(static_cast(0), 32)); ASSERT_EQ(static_cast(0x80000000), reverse_bits(static_cast(1), 32)); ASSERT_EQ(static_cast(0x40000000), reverse_bits(static_cast(2), 32)); ASSERT_EQ(static_cast(0xC0000000), reverse_bits(static_cast(3), 32)); ASSERT_EQ(static_cast(0x00010000), reverse_bits(static_cast(0x00008000), 32)); ASSERT_EQ(static_cast(0xFFFF0000), reverse_bits(static_cast(0x0000FFFF), 32)); ASSERT_EQ(static_cast(0x0000FFFF), reverse_bits(static_cast(0xFFFF0000), 32)); ASSERT_EQ(static_cast(0x00008000), reverse_bits(static_cast(0x00010000), 32)); ASSERT_EQ(static_cast(3), reverse_bits(static_cast(0xC0000000), 32)); ASSERT_EQ(static_cast(2), reverse_bits(static_cast(0x40000000), 32)); ASSERT_EQ(static_cast(1), reverse_bits(static_cast(0x80000000), 32)); ASSERT_EQ(static_cast(0xFFFFFFFF), reverse_bits(static_cast(0xFFFFFFFF), 32)); // 16-bit reversal ASSERT_EQ(static_cast(0), reverse_bits(static_cast(0), 16)); ASSERT_EQ(static_cast(0x00008000), reverse_bits(static_cast(1), 16)); ASSERT_EQ(static_cast(0x00004000), reverse_bits(static_cast(2), 16)); ASSERT_EQ(static_cast(0x0000C000), reverse_bits(static_cast(3), 16)); ASSERT_EQ(static_cast(0x00000001), reverse_bits(static_cast(0x00008000), 16)); ASSERT_EQ(static_cast(0x0000FFFF), reverse_bits(static_cast(0x0000FFFF), 16)); ASSERT_EQ(static_cast(0x00000000), reverse_bits(static_cast(0xFFFF0000), 16)); ASSERT_EQ(static_cast(0x00000000), reverse_bits(static_cast(0x00010000), 16)); ASSERT_EQ(static_cast(3), reverse_bits(static_cast(0x0000C000), 16)); ASSERT_EQ(static_cast(2), reverse_bits(static_cast(0x00004000), 16)); ASSERT_EQ(static_cast(1), reverse_bits(static_cast(0x00008000), 16)); ASSERT_EQ(static_cast(0x0000FFFF), reverse_bits(static_cast(0xFFFFFFFF), 16)); } TEST(Common, ReverseBits32) { ReverseBits32Helper(); // Other types #ifdef SEAL_USE_IF_CONSTEXPR SEAL_IF_CONSTEXPR(sizeof(unsigned) == 4) ReverseBits32Helper(); SEAL_IF_CONSTEXPR(sizeof(unsigned long) == 4) ReverseBits32Helper(); SEAL_IF_CONSTEXPR(sizeof(unsigned long long) == 4) ReverseBits32Helper(); SEAL_IF_CONSTEXPR(sizeof(size_t) == 4) ReverseBits32Helper(); #endif } template void ReverseBits64Helper() { ASSERT_EQ(0ULL, reverse_bits(0ULL)); ASSERT_EQ(1ULL << 63, reverse_bits(1ULL)); ASSERT_EQ(1ULL << 32, reverse_bits(1ULL << 31)); ASSERT_EQ(0xFFFFULL << 32, reverse_bits(0xFFFFULL << 16)); ASSERT_EQ(0x0000FFFFFFFF0000ULL, reverse_bits(0x0000FFFFFFFF0000ULL)); ASSERT_EQ(0x0000FFFF0000FFFFULL, reverse_bits(0xFFFF0000FFFF0000ULL)); ASSERT_EQ(0ULL, reverse_bits(0ULL, 0)); ASSERT_EQ(0ULL, reverse_bits(0ULL, 1)); ASSERT_EQ(0ULL, reverse_bits(0ULL, 32)); ASSERT_EQ(0ULL, reverse_bits(0ULL, 64)); ASSERT_EQ(0ULL, reverse_bits(1ULL, 0)); ASSERT_EQ(1ULL, reverse_bits(1ULL, 1)); ASSERT_EQ(1ULL << 31, reverse_bits(1ULL, 32)); ASSERT_EQ(1ULL << 63, reverse_bits(1ULL, 64)); ASSERT_EQ(0ULL, reverse_bits(1ULL << 31, 0)); ASSERT_EQ(0ULL, reverse_bits(1ULL << 31, 1)); ASSERT_EQ(1ULL, reverse_bits(1ULL << 31, 32)); ASSERT_EQ(1ULL << 32, reverse_bits(1ULL << 31, 64)); ASSERT_EQ(0ULL, reverse_bits(0xFFFFULL << 16, 0)); ASSERT_EQ(0ULL, reverse_bits(0xFFFFULL << 16, 1)); ASSERT_EQ(0xFFFFULL, reverse_bits(0xFFFFULL << 16, 32)); ASSERT_EQ(0xFFFFULL << 32, reverse_bits(0xFFFFULL << 16, 64)); ASSERT_EQ(0ULL, reverse_bits(0x0000FFFFFFFF0000ULL, 0)); ASSERT_EQ(0ULL, reverse_bits(0x0000FFFFFFFF0000ULL, 1)); ASSERT_EQ(0xFFFFULL, reverse_bits(0x0000FFFFFFFF0000ULL, 32)); ASSERT_EQ(0x0000FFFFFFFF0000ULL, reverse_bits(0x0000FFFFFFFF0000ULL, 64)); ASSERT_EQ(0ULL, reverse_bits(0xFFFF0000FFFF0000ULL, 0)); ASSERT_EQ(0ULL, reverse_bits(0xFFFF0000FFFF0000ULL, 1)); ASSERT_EQ(0xFFFFULL, reverse_bits(0xFFFF0000FFFF0000ULL, 32)); ASSERT_EQ(0x0000FFFF0000FFFFULL, reverse_bits(0xFFFF0000FFFF0000ULL, 64)); } TEST(Common, ReverseBits64) { ReverseBits64Helper(); // Other types #ifdef SEAL_USE_IF_CONSTEXPR SEAL_IF_CONSTEXPR(sizeof(unsigned) == 8) ReverseBits64Helper(); SEAL_IF_CONSTEXPR(sizeof(unsigned long) == 8) ReverseBits64Helper(); SEAL_IF_CONSTEXPR(sizeof(unsigned long long) == 8) ReverseBits64Helper(); SEAL_IF_CONSTEXPR(sizeof(size_t) == 8) ReverseBits64Helper(); #endif } TEST(Common, GetSignificantBitCount) { ASSERT_EQ(0, get_significant_bit_count(0)); ASSERT_EQ(1, get_significant_bit_count(1)); ASSERT_EQ(2, get_significant_bit_count(2)); ASSERT_EQ(2, get_significant_bit_count(3)); ASSERT_EQ(3, get_significant_bit_count(4)); ASSERT_EQ(3, get_significant_bit_count(5)); ASSERT_EQ(3, get_significant_bit_count(6)); ASSERT_EQ(3, get_significant_bit_count(7)); ASSERT_EQ(4, get_significant_bit_count(8)); ASSERT_EQ(63, get_significant_bit_count(0x7000000000000000)); ASSERT_EQ(63, get_significant_bit_count(0x7FFFFFFFFFFFFFFF)); ASSERT_EQ(64, get_significant_bit_count(0x8000000000000000)); ASSERT_EQ(64, get_significant_bit_count(0xFFFFFFFFFFFFFFFF)); } TEST(Common, GetMSBIndexGeneric) { unsigned long result; get_msb_index_generic(&result, 1); ASSERT_EQ(static_cast(0), result); get_msb_index_generic(&result, 2); ASSERT_EQ(static_cast(1), result); get_msb_index_generic(&result, 3); ASSERT_EQ(static_cast(1), result); get_msb_index_generic(&result, 4); ASSERT_EQ(static_cast(2), result); get_msb_index_generic(&result, 16); ASSERT_EQ(static_cast(4), result); get_msb_index_generic(&result, 0xFFFFFFFF); ASSERT_EQ(static_cast(31), result); get_msb_index_generic(&result, 0x100000000); ASSERT_EQ(static_cast(32), result); get_msb_index_generic(&result, 0xFFFFFFFFFFFFFFFF); ASSERT_EQ(static_cast(63), result); } } // namespace util } // namespace sealtest