libsnark: convert long long and unsigned long to C++11 fixed-width types
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
namespace libsnark {
|
||||
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
long long alt_bn128_G1::add_cnt = 0;
|
||||
long long alt_bn128_G1::dbl_cnt = 0;
|
||||
int64_t alt_bn128_G1::add_cnt = 0;
|
||||
int64_t alt_bn128_G1::dbl_cnt = 0;
|
||||
#endif
|
||||
|
||||
std::vector<size_t> alt_bn128_G1::wnaf_window_table;
|
||||
|
||||
@@ -20,8 +20,8 @@ std::istream& operator>>(std::istream &, alt_bn128_G1&);
|
||||
class alt_bn128_G1 {
|
||||
public:
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
static long long add_cnt;
|
||||
static long long dbl_cnt;
|
||||
static int64_t add_cnt;
|
||||
static int64_t dbl_cnt;
|
||||
#endif
|
||||
static std::vector<size_t> wnaf_window_table;
|
||||
static std::vector<size_t> fixed_base_exp_window_table;
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
namespace libsnark {
|
||||
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
long long alt_bn128_G2::add_cnt = 0;
|
||||
long long alt_bn128_G2::dbl_cnt = 0;
|
||||
int64_t alt_bn128_G2::add_cnt = 0;
|
||||
int64_t alt_bn128_G2::dbl_cnt = 0;
|
||||
#endif
|
||||
|
||||
std::vector<size_t> alt_bn128_G2::wnaf_window_table;
|
||||
|
||||
@@ -20,8 +20,8 @@ std::istream& operator>>(std::istream &, alt_bn128_G2&);
|
||||
class alt_bn128_G2 {
|
||||
public:
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
static long long add_cnt;
|
||||
static long long dbl_cnt;
|
||||
static int64_t add_cnt;
|
||||
static int64_t dbl_cnt;
|
||||
#endif
|
||||
static std::vector<size_t> wnaf_window_table;
|
||||
static std::vector<size_t> fixed_base_exp_window_table;
|
||||
|
||||
@@ -74,11 +74,11 @@ void _basic_serial_radix2_FFT(std::vector<FieldT> &a, const FieldT &omega)
|
||||
template<typename FieldT>
|
||||
void _basic_parallel_radix2_FFT_inner(std::vector<FieldT> &a, const FieldT &omega, const size_t log_cpus)
|
||||
{
|
||||
const size_t num_cpus = 1ul<<log_cpus;
|
||||
const size_t num_cpus = UINT64_C(1)<<log_cpus;
|
||||
|
||||
const size_t m = a.size();
|
||||
const size_t log_m = log2(m);
|
||||
assert(m == 1ul<<log_m);
|
||||
assert(m == UINT64_C(1)<<log_m);
|
||||
|
||||
if (log_m < log_cpus)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ void _basic_parallel_radix2_FFT_inner(std::vector<FieldT> &a, const FieldT &omeg
|
||||
std::vector<std::vector<FieldT> > tmp(num_cpus);
|
||||
for (size_t j = 0; j < num_cpus; ++j)
|
||||
{
|
||||
tmp[j].resize(1ul<<(log_m-log_cpus), FieldT::zero());
|
||||
tmp[j].resize(UINT64_C(1)<<(log_m-log_cpus), FieldT::zero());
|
||||
}
|
||||
|
||||
#ifdef MULTICORE
|
||||
@@ -102,7 +102,7 @@ void _basic_parallel_radix2_FFT_inner(std::vector<FieldT> &a, const FieldT &omeg
|
||||
const FieldT omega_step = omega^(j<<(log_m - log_cpus));
|
||||
|
||||
FieldT elt = FieldT::one();
|
||||
for (size_t i = 0; i < 1ul<<(log_m - log_cpus); ++i)
|
||||
for (size_t i = 0; i < UINT64_C(1)<<(log_m - log_cpus); ++i)
|
||||
{
|
||||
for (size_t s = 0; s < num_cpus; ++s)
|
||||
{
|
||||
@@ -135,7 +135,7 @@ void _basic_parallel_radix2_FFT_inner(std::vector<FieldT> &a, const FieldT &omeg
|
||||
#endif
|
||||
for (size_t i = 0; i < num_cpus; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < 1ul<<(log_m - log_cpus); ++j)
|
||||
for (size_t j = 0; j < UINT64_C(1)<<(log_m - log_cpus); ++j)
|
||||
{
|
||||
// now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m)
|
||||
a[(j<<log_cpus) + i] = tmp[i][j];
|
||||
|
||||
@@ -54,9 +54,9 @@ std::shared_ptr<evaluation_domain<FieldT> > get_evaluation_domain(const size_t m
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t big = 1ul<<(log2(min_size)-1);
|
||||
const size_t big = UINT64_C(1)<<(log2(min_size)-1);
|
||||
const size_t small = min_size - big;
|
||||
const size_t rounded_small = (1ul<<log2(small));
|
||||
const size_t rounded_small = (UINT64_C(1)<<log2(small));
|
||||
if (big == rounded_small)
|
||||
{
|
||||
if (log2(big + rounded_small) < FieldT::s+1)
|
||||
|
||||
@@ -22,7 +22,7 @@ template<typename FieldT, mp_size_t m>
|
||||
FieldT power(const FieldT &base, const bigint<m> &exponent);
|
||||
|
||||
template<typename FieldT>
|
||||
FieldT power(const FieldT &base, const unsigned long exponent);
|
||||
FieldT power(const FieldT &base, const uint64_t exponent);
|
||||
|
||||
} // libsnark
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ FieldT power(const FieldT &base, const bigint<m> &exponent)
|
||||
}
|
||||
|
||||
template<typename FieldT>
|
||||
FieldT power(const FieldT &base, const unsigned long exponent)
|
||||
FieldT power(const FieldT &base, const uint64_t exponent)
|
||||
{
|
||||
return power<FieldT>(base, bigint<1>(exponent));
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
mp_limb_t data[n] = {0};
|
||||
|
||||
bigint() = default;
|
||||
bigint(const unsigned long x); /// Initialize from a small integer
|
||||
bigint(const uint64_t x); /// Initalize from a small integer
|
||||
bigint(const char* s); /// Initialize from a string containing an integer in decimal notation
|
||||
bigint(const mpz_t r); /// Initialize from MPZ element
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
size_t max_bits() const { return n * GMP_NUMB_BITS; }
|
||||
size_t num_bits() const;
|
||||
|
||||
unsigned long as_ulong() const; /* return the last limb of the integer */
|
||||
uint64_t as_uint64() const; /* return the last limb of the integer */
|
||||
void to_mpz(mpz_t r) const;
|
||||
bool test_bit(const std::size_t bitno) const;
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
namespace libsnark {
|
||||
|
||||
template<mp_size_t n>
|
||||
bigint<n>::bigint(const unsigned long x) /// Initialize from a small integer
|
||||
bigint<n>::bigint(const uint64_t x) /// Initialize from a small integer
|
||||
{
|
||||
static_assert(ULONG_MAX <= GMP_NUMB_MAX, "unsigned long does not fit in a GMP limb");
|
||||
static_assert(UINT64_MAX <= GMP_NUMB_MAX, "uint64_t does not fit in a GMP limb");
|
||||
this->data[0] = x;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ size_t bigint<n>::num_bits() const
|
||||
}
|
||||
|
||||
template<mp_size_t n>
|
||||
unsigned long bigint<n>::as_ulong() const
|
||||
uint64_t bigint<n>::as_uint64() const
|
||||
{
|
||||
return this->data[0];
|
||||
}
|
||||
|
||||
@@ -44,11 +44,11 @@ public:
|
||||
static const mp_size_t num_limbs = n;
|
||||
static const constexpr bigint<n>& mod = modulus;
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
static long long add_cnt;
|
||||
static long long sub_cnt;
|
||||
static long long mul_cnt;
|
||||
static long long sqr_cnt;
|
||||
static long long inv_cnt;
|
||||
static int64_t add_cnt;
|
||||
static int64_t sub_cnt;
|
||||
static int64_t mul_cnt;
|
||||
static int64_t sqr_cnt;
|
||||
static int64_t inv_cnt;
|
||||
#endif
|
||||
static size_t num_bits;
|
||||
static bigint<n> euler; // (modulus-1)/2
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
Fp_model(const bigint<n> &b);
|
||||
Fp_model(const long x, const bool is_unsigned=false);
|
||||
|
||||
void set_ulong(const unsigned long x);
|
||||
void set_uint64(const uint64_t x);
|
||||
|
||||
void mul_reduce(const bigint<n> &other);
|
||||
|
||||
@@ -80,9 +80,9 @@ public:
|
||||
would return bigint(2) */
|
||||
bigint<n> as_bigint() const;
|
||||
/* Return the last limb of the standard representation of the
|
||||
field element. E.g. on 64-bit architectures Fp(123).as_ulong()
|
||||
and Fp(2^64+123).as_ulong() would both return 123. */
|
||||
unsigned long as_ulong() const;
|
||||
field element. E.g. on 64-bit architectures Fp(123).as_uint64()
|
||||
and Fp(2^64+123).as_uint64() would both return 123. */
|
||||
uint64_t as_uint64() const;
|
||||
|
||||
bool operator==(const Fp_model& other) const;
|
||||
bool operator!=(const Fp_model& other) const;
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
Fp_model& operator+=(const Fp_model& other);
|
||||
Fp_model& operator-=(const Fp_model& other);
|
||||
Fp_model& operator*=(const Fp_model& other);
|
||||
Fp_model& operator^=(const unsigned long pow);
|
||||
Fp_model& operator^=(const uint64_t pow);
|
||||
|
||||
template<mp_size_t m>
|
||||
Fp_model& operator^=(const bigint<m> &pow);
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
Fp_model inverse() const;
|
||||
Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
|
||||
|
||||
Fp_model operator^(const unsigned long pow) const;
|
||||
Fp_model operator^(const uint64_t pow) const;
|
||||
template<mp_size_t m>
|
||||
Fp_model operator^(const bigint<m> &pow) const;
|
||||
|
||||
@@ -125,19 +125,19 @@ public:
|
||||
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
long long Fp_model<n, modulus>::add_cnt = 0;
|
||||
int64_t Fp_model<n, modulus>::add_cnt = 0;
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
long long Fp_model<n, modulus>::sub_cnt = 0;
|
||||
int64_t Fp_model<n, modulus>::sub_cnt = 0;
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
long long Fp_model<n, modulus>::mul_cnt = 0;
|
||||
int64_t Fp_model<n, modulus>::mul_cnt = 0;
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
long long Fp_model<n, modulus>::sqr_cnt = 0;
|
||||
int64_t Fp_model<n, modulus>::sqr_cnt = 0;
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
long long Fp_model<n, modulus>::inv_cnt = 0;
|
||||
int64_t Fp_model<n, modulus>::inv_cnt = 0;
|
||||
#endif
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
|
||||
@@ -210,7 +210,7 @@ Fp_model<n,modulus>::Fp_model(const long x, const bool is_unsigned)
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
void Fp_model<n,modulus>::set_ulong(const unsigned long x)
|
||||
void Fp_model<n,modulus>::set_uint64(const uint64_t x)
|
||||
{
|
||||
this->mont_repr.clear();
|
||||
this->mont_repr.data[0] = x;
|
||||
@@ -237,9 +237,9 @@ bigint<n> Fp_model<n,modulus>::as_bigint() const
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
unsigned long Fp_model<n,modulus>::as_ulong() const
|
||||
uint64_t Fp_model<n,modulus>::as_uint64() const
|
||||
{
|
||||
return this->as_bigint().as_ulong();
|
||||
return this->as_bigint().as_uint64();
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
@@ -502,7 +502,7 @@ Fp_model<n,modulus>& Fp_model<n,modulus>::operator*=(const Fp_model<n,modulus>&
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
Fp_model<n,modulus>& Fp_model<n,modulus>::operator^=(const unsigned long pow)
|
||||
Fp_model<n,modulus>& Fp_model<n,modulus>::operator^=(const uint64_t pow)
|
||||
{
|
||||
(*this) = power<Fp_model<n, modulus> >(*this, pow);
|
||||
return (*this);
|
||||
@@ -538,7 +538,7 @@ Fp_model<n,modulus> Fp_model<n,modulus>::operator*(const Fp_model<n,modulus>& ot
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
Fp_model<n,modulus> Fp_model<n,modulus>::operator^(const unsigned long pow) const
|
||||
Fp_model<n,modulus> Fp_model<n,modulus>::operator^(const uint64_t pow) const
|
||||
{
|
||||
Fp_model<n, modulus> r(*this);
|
||||
return (r ^= pow);
|
||||
@@ -690,7 +690,7 @@ Fp_model<n, modulus> Fp_model<n,modulus>::random_element() /// returns random el
|
||||
const std::size_t part = bitno/GMP_NUMB_BITS;
|
||||
const std::size_t bit = bitno - (GMP_NUMB_BITS*part);
|
||||
|
||||
r.mont_repr.data[part] &= ~(1ul<<bit);
|
||||
r.mont_repr.data[part] &= ~(UINT64_C(1)<<bit);
|
||||
|
||||
bitno--;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
Fp12_2over3over2_model squared_karatsuba() const;
|
||||
Fp12_2over3over2_model squared_complex() const;
|
||||
Fp12_2over3over2_model inverse() const;
|
||||
Fp12_2over3over2_model Frobenius_map(unsigned long power) const;
|
||||
Fp12_2over3over2_model Frobenius_map(uint64_t power) const;
|
||||
Fp12_2over3over2_model unitary_inverse() const;
|
||||
Fp12_2over3over2_model cyclotomic_squared() const;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::inverse() c
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::Frobenius_map(unsigned long power) const
|
||||
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::Frobenius_map(uint64_t power) const
|
||||
{
|
||||
return Fp12_2over3over2_model<n,modulus>(c0.Frobenius_map(power),
|
||||
Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power));
|
||||
@@ -348,7 +348,7 @@ Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n,modulus>::cyclotomic
|
||||
res = res.cyclotomic_squared();
|
||||
}
|
||||
|
||||
if (exponent.data[i] & (1ul<<j))
|
||||
if (exponent.data[i] & (UINT64_C(1)<<j))
|
||||
{
|
||||
found_one = true;
|
||||
res = res * (*this);
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
Fp2_model operator-() const;
|
||||
Fp2_model squared() const; // default is squared_complex
|
||||
Fp2_model inverse() const;
|
||||
Fp2_model Frobenius_map(unsigned long power) const;
|
||||
Fp2_model Frobenius_map(uint64_t power) const;
|
||||
Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
|
||||
Fp2_model squared_karatsuba() const;
|
||||
Fp2_model squared_complex() const;
|
||||
|
||||
@@ -136,7 +136,7 @@ Fp2_model<n,modulus> Fp2_model<n,modulus>::inverse() const
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
Fp2_model<n,modulus> Fp2_model<n,modulus>::Frobenius_map(unsigned long power) const
|
||||
Fp2_model<n,modulus> Fp2_model<n,modulus>::Frobenius_map(uint64_t power) const
|
||||
{
|
||||
return Fp2_model<n,modulus>(c0,
|
||||
Frobenius_coeffs_c1[power % 2] * c1);
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
Fp6_3over2_model operator-() const;
|
||||
Fp6_3over2_model squared() const;
|
||||
Fp6_3over2_model inverse() const;
|
||||
Fp6_3over2_model Frobenius_map(unsigned long power) const;
|
||||
Fp6_3over2_model Frobenius_map(uint64_t power) const;
|
||||
|
||||
static my_Fp2 mul_by_non_residue(const my_Fp2 &elt);
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::inverse() const
|
||||
}
|
||||
|
||||
template<mp_size_t n, const bigint<n>& modulus>
|
||||
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::Frobenius_map(unsigned long power) const
|
||||
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::Frobenius_map(uint64_t power) const
|
||||
{
|
||||
return Fp6_3over2_model<n,modulus>(c0.Frobenius_map(power),
|
||||
Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power),
|
||||
|
||||
@@ -13,7 +13,6 @@ using namespace libsnark;
|
||||
|
||||
TEST(algebra, bigint)
|
||||
{
|
||||
static_assert(ULONG_MAX == 0xFFFFFFFFFFFFFFFFul, "unsigned long not 64-bit");
|
||||
static_assert(GMP_NUMB_BITS == 64, "GMP limb not 64-bit");
|
||||
|
||||
const char *b1_decimal = "76749407";
|
||||
@@ -26,11 +25,11 @@ TEST(algebra, bigint)
|
||||
bigint<1> b1 = bigint<1>(b1_decimal);
|
||||
bigint<2> b2 = bigint<2>(b2_decimal);
|
||||
|
||||
EXPECT_EQ(b0.as_ulong(), 0ul);
|
||||
EXPECT_EQ(b0.as_uint64(), 0ul);
|
||||
EXPECT_TRUE(b0.is_zero());
|
||||
EXPECT_EQ(b1.as_ulong(), 76749407ul);
|
||||
EXPECT_EQ(b1.as_uint64(), 76749407ul);
|
||||
EXPECT_FALSE(b1.is_zero());
|
||||
EXPECT_EQ(b2.as_ulong(), 15747124762497195938ul);
|
||||
EXPECT_EQ(b2.as_uint64(), 15747124762497195938ul);
|
||||
EXPECT_FALSE(b2.is_zero());
|
||||
EXPECT_NE(b0, b1);
|
||||
EXPECT_FALSE(b0 == b1);
|
||||
@@ -61,7 +60,7 @@ TEST(algebra, bigint)
|
||||
bigint<2> remainder;
|
||||
bigint<3>::div_qr(quotient, remainder, b3, b2);
|
||||
EXPECT_LT(quotient.num_bits(), GMP_NUMB_BITS);
|
||||
EXPECT_EQ(quotient.as_ulong(), b1.as_ulong());
|
||||
EXPECT_EQ(quotient.as_uint64(), b1.as_uint64());
|
||||
bigint<1> b1inc = bigint<1>("76749408");
|
||||
bigint<1> b1a = quotient.shorten(b1inc, "test");
|
||||
EXPECT_EQ(b1a, b1);
|
||||
@@ -79,9 +78,9 @@ TEST(algebra, bigint)
|
||||
|
||||
bigint<3>::div_qr(quotient, remainder, b3, b2);
|
||||
EXPECT_LT(quotient.num_bits(), GMP_NUMB_BITS);
|
||||
EXPECT_EQ(quotient.as_ulong(), b1.as_ulong());
|
||||
EXPECT_EQ(quotient.as_uint64(), b1.as_uint64());
|
||||
EXPECT_LT(remainder.num_bits(), GMP_NUMB_BITS);
|
||||
EXPECT_EQ(remainder.as_ulong(), 42);
|
||||
EXPECT_EQ(remainder.as_uint64(), 42);
|
||||
|
||||
b3a.clear();
|
||||
EXPECT_TRUE(b3a.is_zero());
|
||||
|
||||
@@ -214,7 +214,7 @@ T multi_exp_inner(typename std::vector<T>::const_iterator vec_start,
|
||||
const size_t bbits = b.r.num_bits();
|
||||
const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits);
|
||||
|
||||
if (bbits < 1ul<<limit)
|
||||
if (bbits < UINT64_C(1)<<limit)
|
||||
{
|
||||
/*
|
||||
In this case, exponentiating to the power of a is cheaper than
|
||||
@@ -420,9 +420,9 @@ window_table<T> get_window_table(const size_t scalar_size,
|
||||
const size_t window,
|
||||
const T &g)
|
||||
{
|
||||
const size_t in_window = 1ul<<window;
|
||||
const size_t in_window = UINT64_C(1)<<window;
|
||||
const size_t outerc = (scalar_size+window-1)/window;
|
||||
const size_t last_in_window = 1ul<<(scalar_size - (outerc-1)*window);
|
||||
const size_t last_in_window = UINT64_C(1)<<(scalar_size - (outerc-1)*window);
|
||||
#ifdef DEBUG
|
||||
if (!inhibit_profiling_info)
|
||||
{
|
||||
|
||||
@@ -60,10 +60,10 @@ template<typename T, mp_size_t n>
|
||||
T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n> &scalar)
|
||||
{
|
||||
std::vector<long> naf = find_wnaf(window_size, scalar);
|
||||
std::vector<T> table(1ul<<(window_size-1));
|
||||
std::vector<T> table(UINT64_C(1)<<(window_size-1));
|
||||
T tmp = base;
|
||||
T dbl = base.dbl();
|
||||
for (size_t i = 0; i < 1ul<<(window_size-1); ++i)
|
||||
for (size_t i = 0; i < UINT64_C(1)<<(window_size-1); ++i)
|
||||
{
|
||||
table[i] = tmp;
|
||||
tmp = tmp + dbl;
|
||||
|
||||
Reference in New Issue
Block a user