#ifndef CT_FIELD_HPP
#define CT_FIELD_HPP
#include <ctbignum/addition.hpp>
#include <ctbignum/invariant_div.hpp>
#include <ctbignum/io.hpp>
#include <ctbignum/mult.hpp>
#include <ctbignum/slicing.hpp>
#include <cstddef>
#include <type_traits>
namespace cbn
{
class skip_reduction
{
};
template <typename T, T... Modulus>
struct ZqElement
{
using value_type = T;
big_int<sizeof...(Modulus), T> data;
explicit operator auto() const { return data; } constexpr ZqElement() : data() {}
constexpr ZqElement(long x)
{
auto neg = subtract_ignore_carry(to_big_int(std::integer_sequence<T, Modulus...>{}), big_int<sizeof...(Modulus), T>{static_cast<T>(-x)});
auto pos = big_int<sizeof...(Modulus), T>{static_cast<T>(x)};
data = mod((x >= 0) ? pos : neg, std::integer_sequence<T, Modulus...>());
}
template <T... Limbs>
constexpr ZqElement(std::integer_sequence<T, Limbs...>)
: data(big_int<sizeof...(Limbs), T>{Limbs...} <
big_int<sizeof...(Modulus), T>{Modulus...}
? detail::to_length<sizeof...(Modulus)>(
big_int<sizeof...(Limbs), T>{Limbs...})
: mod(big_int<sizeof...(Limbs), T>{Limbs...},
std::integer_sequence<T, Modulus...>()))
{
}
template <std::size_t N>
constexpr ZqElement(big_int<N, T> init)
: data(init < big_int<sizeof...(Modulus), T>{Modulus...}
? detail::to_length<sizeof...(Modulus)>(init)
: mod(init, std::integer_sequence<T, Modulus...>()))
{
}
constexpr ZqElement(big_int<sizeof...(Modulus), T> init, skip_reduction)
: data(init) {}
};
template <typename T, T... Modulus>
auto Zq(std::integer_sequence<T, Modulus...>)
{
return ZqElement<T, Modulus...>{};
}
template <typename T, T... Modulus>
constexpr auto extract_modulus(ZqElement<T, Modulus...> a)
{
return std::integer_sequence<T, Modulus...>{};
}
template <typename T, T... M>
constexpr auto &operator+=(ZqElement<T, M...> &a, ZqElement<T, M...> b)
{
a = ZqElement<T, M...>{mod_add(a.data, b.data, big_int<sizeof...(M), T>{M...}), skip_reduction{}};
return a;
}
template <typename T, T... M>
constexpr auto operator+(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
a += b;
return a;
}
template <typename T, T... M>
constexpr auto &operator-=(ZqElement<T, M...> &a, ZqElement<T, M...> b)
{
a = ZqElement<T, M...>{mod_sub(a.data, b.data, big_int<sizeof...(M), T>{M...}), skip_reduction{}};
return a;
}
template <typename T, T... M>
constexpr auto operator-(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
a -= b;
return a;
}
template <typename T, T... M>
constexpr auto operator-(ZqElement<T, M...> a)
{
big_int<sizeof...(M), T> mod{M...};
return ZqElement<T, M...>{mod - a.data};
}
template <typename T, T... M>
constexpr auto &operator*=(ZqElement<T, M...> &a, ZqElement<T, M...> b)
{
a = ZqElement<T, M...>{mod(mul(a.data, b.data), std::integer_sequence<T, M...>()), skip_reduction{}};
return a;
}
template <typename T, T... M>
constexpr auto operator*(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
a *= b;
return a;
}
template <typename T, T... M>
constexpr auto &operator/=(ZqElement<T, M...> &a, ZqElement<T, M...> b)
{
a = ZqElement<T, M...>{
mod(mul(a.data, mod_inv(b.data, big_int<sizeof...(M), T>{M...})),
std::integer_sequence<T, M...>()),
skip_reduction{}};
return a;
}
template <typename T, T... M>
constexpr auto operator/(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
a /= b;
return a;
}
template <typename T, T... M>
std::ostream &operator<<(std::ostream &strm, const ZqElement<T, M...> &obj)
{
strm << obj.data;
return strm;
}
template <typename T, T... M>
constexpr bool operator==(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
return a.data == b.data;
}
template <typename T, T... M>
constexpr bool operator!=(ZqElement<T, M...> a, ZqElement<T, M...> b)
{
return !(a == b);
}
} #endif