Uint 256 T

/**
 * @file
 *
 * @details Implementation of 256-bit unsigned integers.
 * @note The implementation can be flagged as not completed. This header is used
 * with enough operations to demonstrate the usage of ECDH (Elliptic Curve
 * Diffie-Hellman) Key exchange.
 * @author [Ashish Daulatabad](https://github.com/AshishYUO)
 */
#include <string>   /// for `std::string`
#include <utility>  /// for `std::pair` library

#include "uint128_t.hpp"  /// for uint128_t integer

#ifndef CIPHERS_UINT256_T_HPP_
#define CIPHERS_UINT256_T_HPP_

class uint256_t;

template <>
struct std::is_integral<uint256_t> : std::true_type {};

template <>
struct std::is_arithmetic<uint256_t> : std::true_type {};

template <>
struct std::is_unsigned<uint256_t> : std::true_type {};

/**
 * @class uint256_t
 * @brief class for 256-bit unsigned integer
 */
class uint256_t {
    uint128_t f{}, s{};  /// First and second half of 256 bit number

    /**
     * @brief Get integer from given string.
     * @details Create an integer from a given string
     * @param str integer string, can be hexadecimal (starting on 0x... or
     * number)
     * @returns void
     */
    void __get_integer_from_string(const std::string &str) {
        this->f = this->s = uint128_t(0);
        if (str.size() > 1 && str[1] == 'x') {
            for (auto i = 2; i < str.size(); ++i) {
                *this *= 16LL;
                if (str[i] >= '0' && str[i] <= '9') {
                    *this += (str[i] - '0');
                } else if (str[i] >= 'A' && str[i] <= 'F') {
                    *this += (str[i] - 'A' + 10);
                } else if (str[i] >= 'a' && str[i] <= 'f') {
                    *this += (str[i] - 'a' + 10);
                }
            }
        } else {
            for (auto &x : str) {
                *this *= 10LL;
                *this += (x - '0');
            }
        }
    }

 public:
    // Constructors
    uint256_t() = default;

    /**
     * @brief Parameterized constructor
     * @tparam T template for integer types
     * @param low Integer denoting lower 128-bits
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    explicit uint256_t(T low) : s(low), f(0) {}

    /**
     * @brief Parameterized constructor
     * @param str Integer string (hexadecimal starting with 0x.. or decimal)
     */
    explicit uint256_t(const std::string &str) {
        __get_integer_from_string(str);
    }

    /**
     * @brief Copy constructor
     * @param num 256-bit unsigned integer
     */
    uint256_t(const uint256_t &num) = default;

    /**
     * @brief Move constructor
     * @param num 256-bit unsigned integer
     */
    uint256_t(uint256_t &&num) noexcept
        : f(std::move(num.f)), s(std::move(num.s)) {}

    /**
     * @brief Parameterized constructor
     * @param high higher part 128-bit unsigned integer
     * @param low lower part 128-bit unsigned integer
     */
    uint256_t(uint128_t high, uint128_t low)
        : f(std::move(high)), s(std::move(low)) {}

    /**
     * @brief Parameterized constructor
     * @param high higher part 64-bit unsigned integer
     * @param low lower part 64-bit unsigned integer
     */
    uint256_t(const uint64_t high, const uint64_t low) : f(high), s(low) {}

    /**
     * @brief Destructor for uint256_t
     */
    ~uint256_t() = default;

    /**
     * @brief Leading zeroes in binary
     * @details Calculates leading zeros in 256-bit integer
     * @returns Integer denoting leading zeroes
     */
    inline uint32_t _lez() {
        if (f) {
            return f._lez();
        }
        return 128 + s._lez();
    }

    /**
     * @brief Trailing zeroes in binary
     * @details Calculates leading zeros in 256-bit integer
     * @returns Integer denoting Trailing zeroes
     */
    inline uint32_t _trz() {
        if (s) {
            return s._trz();
        }
        return 128 + f._trz();
    }

    /**
     * @brief casting operator to boolean value
     * @returns true if value of this is non-zero, else false
     */
    inline explicit operator bool() const { return f || s; }

    /**
     * @brief casting operator to any integer value
     * @tparam T any integer type
     * @returns integer value casted to mentioned type
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline explicit operator T() const {
        return static_cast<T>(s);
    }

    /**
     * @brief casting operator to uint128_t
     * @returns returns lower 128-bit integer part
     */
    inline explicit operator uint128_t() const { return s; }

    /**
     * @brief returns lower 128-bit integer part
     * @returns returns lower 128-bit integer part
     */
    inline uint128_t lower() const { return s; }

    /**
     * @brief returns upper 128-bit integer part
     * @returns returns upper 128-bit integer part
     */
    inline uint128_t upper() const { return f; }

    /**
     * @brief operator = for uint256_t
     * @param p an 256-bit integer to assign it's value
     * @returns this pointer with it's value equal to `p`
     */
    inline uint256_t &operator=(const uint256_t &p) = default;

    /**
     * @brief operator = for other types
     * @tparam T denoting any integer type
     * @param p an integer to assign it's value
     * @returns this pointer with it's value equal to `p`
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator=(const T &p) {
        this->s = p;
        return *this;
    }

    /**
     * @brief operator = for type string
     * @param p a string to assign it's value to equivalent integer
     * @returns this pointer with it's value equal to `p`
     */
    inline uint256_t &operator=(const std::string &p) {
        __get_integer_from_string(p);
        return *this;
    }

    /**
     * @brief Move assignment operator
     */
    inline uint256_t &operator=(uint256_t &&p) = default;

    /**
     * @brief operator + for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns addition of this and p, returning uint256_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator+(const T &p) {
        bool app = s + p < s;
        return uint256_t(f + app, s + p);
    }

    /**
     * @brief operator + for uint256_t and other integer types.
     * @param p 256-bit unsigned integer
     * @returns addition of this and p, returning uint256_t integer
     */
    inline uint256_t operator+(const uint256_t &p) {
        bool app = (s + p.s < s);
        return {f + app + p.f, s + p.s};
    }

    /**
     * @brief operator += for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns addition of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator+=(const T &p) {
        bool app = (p + s < s);
        this->f += app;
        this->s += p;
        return *this;
    }

    /**
     * @brief operator += for uint256_t
     * @param p 256-bit unsigned integer
     * @returns addition of this and p, returning this
     */
    inline uint256_t &operator+=(const uint256_t &p) {
        bool app = (s + p.s < s);
        f = f + app + p.f;
        s = s + p.s;
        return *this;
    }

    /**
     * @brief pre-increment operator
     * @returns incremented value of this.
     */
    inline uint256_t &operator++() {
        *this += 1;
        return *this;
    }

    /**
     * @brief post-increment operator
     * @returns incremented value of this.
     */
    inline uint256_t operator++(int) {
        ++*this;
        return *this;
    }

    /**
     * @brief operator - for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning uint256_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator-(const T &p) {
        bool app = (p > s);
        return uint256_t(f - app, s - p);
    }

    /**
     * @brief operator - for uint256_t
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning uint256_t integer
     */
    inline uint256_t operator-(const uint256_t &p) {
        bool app = s < p.s;
        return {f - p.f - app, s - p.s};
    }

    /**
     * @brief operator - using twos complement
     * @returns 2's complement of this.
     */
    inline uint256_t operator-() { return ~*this + uint256_t(1); }

    /**
     * @brief operator -- (pre-decrement)
     * @returns decremented value of this
     */
    inline uint256_t &operator--() {
        *this -= 1;
        return *this;
    }

    /**
     * @brief operator -- (post-decrement)
     * @returns decremented value of this
     */
    inline uint256_t operator--(int p) {
        --*this;
        return *this;
    }

    /**
     * @brief operator -= for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns subtraction of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator-=(const T p) {
        bool app = (p > s);
        f = f - app;
        s = s - p;
        return *this;
    }

    /**
     * @brief operator -= for uint256_t
     * @param p 256-bit unsigned integer
     * @returns subtraction of this and p, returning this
     */
    inline uint256_t &operator-=(const uint256_t &p) {
        bool app = s < p.s;
        f = f - app - p.f;
        s = s - p.s;
        return *this;
    }

    /**
     * @brief operator * for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns multiplication of this and p, returning uint256_t integer
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator*(const T &p) {
        return *this * uint256_t(p);
    }

    /**
     * @brief operator * for uint256_t and other integer types.
     * @param p 256-bit unsigned integer
     * @returns multiplication of this and p, returning uint256_t integer
     */
    uint256_t operator*(const uint256_t &p) {
        uint128_t f_first(s.upper()), f_second(s.lower()), s_first(p.s.upper()),
            s_second(p.s.lower());
        uint128_t fi = f_first * s_first, se = f_first * s_second,
                  th = s_first * f_second, fo = s_second * f_second;
        uint128_t tmp = se << 64, tmp2 = th << 64;
        int cc = (tmp + tmp2 < tmp);
        tmp += tmp2;
        cc += (tmp + fo < tmp);
        return {f * p.s + s * p.f + fi + se.upper() + th.upper() + cc,
                tmp + fo};
    }

    /**
     * @brief operator *= for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns multiplication of this and p, returning this
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator*=(const T &p) {
        return (*this *= uint256_t(p));
    }

    /**
     * @brief operator *= for uint256_t and other integer types.
     * @param p 256-bit unsigned integer
     * @returns multiplication of this and p, returning this
     */
    uint256_t &operator*=(const uint256_t &p) {
        uint128_t f_first(s.upper()), f_second(s.lower()), s_first(p.s.upper()),
            s_second(p.s.lower());
        uint128_t fi = f_first * s_first, se = f_first * s_second,
                  th = s_first * f_second, fo = s_second * f_second;
        uint128_t tmp = se << 64, tmp2 = th << 64;
        int cc = (tmp + tmp2 < tmp);
        tmp += tmp2;
        cc += (tmp + fo < tmp);
        f = f * p.s + s * p.f + fi + se.upper() + th.upper() + cc;
        s = tmp + fo;
        return *this;
    }

    /**
     * @brief divide function for uint256_t and other integer types.
     * @details divide this value and
     * @param p 256-bit unsigned integer
     * @returns pair denoting quotient and remainder.
     */
    std::pair<uint256_t, uint256_t> divide(const uint256_t &p) {
        if (*this < p) {  // if this is less than divisor
            return {uint256_t(0), *this};
        } else if (*this == p) {  // if this is equal to divisor
            return {uint256_t(1), uint256_t(0)};
        }
        uint256_t tmp = p, tmp2 = *this;
        uint16_t left = tmp._lez() - _lez();
        tmp <<= left;
        uint256_t quotient(0);
        uint256_t zero(0);
        while (tmp2 >= p) {
            uint16_t shf = tmp2._lez() - tmp._lez();
            if (shf) {
                tmp >>= shf;
                quotient <<= shf;
                left -= shf;
            }
            if (tmp2 < tmp) {
                tmp >>= 1;
                quotient <<= 1;
                --left;
            }
            tmp2 -= tmp;
            ++quotient;
        }
        return {quotient << left, tmp2};
    }

    /**
     * @brief operator / for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns unsigned 256-bit quotient.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator/(const T &p) {
        uint256_t tmp = *this;
        tmp /= uint256_t(p);
        return tmp;
    }

    /**
     * @brief operator / for uint256_t and other integer types.
     * @param p 256-bit unsigned integer
     * @returns unsigned 256-bit quotient.
     */
    inline uint256_t operator/(const uint256_t &p) { return divide(p).first; }

    /**
     * @brief operator /= for uint256_t
     * @param p 256-bit unsigned integer
     * @returns this set as unsigned 256-bit quotient.
     */
    inline uint256_t &operator/=(const uint256_t &p) {
        *this = divide(p).first;
        return *this;
    }

    /**
     * @brief operator /= for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns this set as unsigned 256-bit quotient.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator/=(const T &p) {
        *this /= uint256_t(p);
        return *this;
    }

    /**
     * @brief operator % for uint256_t
     * @param p 256-bit unsigned integer
     * @returns unsigned 256-bit remainder.
     */
    inline uint256_t operator%(const uint256_t &p) { return divide(p).second; }

    /**
     * @brief operator % for uint256_t and other integer types.
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns unsigned 256-bit remainder.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator%(const T &p) {
        uint256_t tmp = *this;
        tmp %= uint256_t(p);
        return tmp;
    }

    /**
     * @brief operator %= for uint256_t
     * @param p 256-bit unsigned integer
     * @returns this set as unsigned 256-bit remainder.
     */
    inline uint256_t &operator%=(const uint256_t &p) {
        *this = divide(p).second;
        return *this;
    }

    /**
     * @brief operator %= for uint256_t
     * @tparam T denoting integral type
     * @param p a type of integer variable
     * @returns this set as unsigned 256-bit remainder.
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator%=(const T &p) {
        *this %= uint256_t(p);
        return *this;
    }

    /**
     * @brief operator < for uint256_t
     * @param other number to be compared with this
     * @returns true if this is less than other, else false
     */
    inline bool operator<(const uint256_t &other) {
        return f < other.f || (f == other.f && s < other.s);
    }

    /**
     * @brief operator <= for uint256_t
     * @param other number to be compared with this
     * @returns true if this is less than or equal to other, else false
     */
    inline bool operator<=(const uint256_t &other) {
        return f < other.f || (f == other.f && s <= other.s);
    }

    /**
     * @brief operator > for uint256_t
     * @param other number to be compared with this
     * @returns true if this is greater than other, else false
     */
    inline bool operator>(const uint256_t &other) {
        return f > other.f || (f == other.f && s > other.s);
    }

    /**
     * @brief operator >= for uint256_t
     * @param other number to be compared with this
     * @returns true if this is greater than or equal than other, else false
     */
    inline bool operator>=(const uint256_t &other) {
        return (f > other.f) || (f == other.f && s >= other.s);
    }

    /**
     * @brief operator == for uint256_t
     * @param other number to be compared with this
     * @returns true if this is equal than other, else false
     */
    inline bool operator==(const uint256_t &other) {
        return f == other.f && s == other.s;
    }

    /**
     * @brief operator != for uint256_t
     * @param other number to be compared with this
     * @returns true if this is not equal than other, else false
     */
    inline bool operator!=(const uint256_t &other) {
        return !((*this) == other);
    }

    /**
     * @brief operator ! for uint256_t
     * @returns true if this has zero value, else false
     */
    inline bool operator!() { return !f && !s; }

    /**
     * @brief operator && for uint256_t
     * @param b number to be compared with this
     * @returns true if both of the values are not zero, else false
     */
    inline bool operator&&(const uint256_t &b) {
        return (s || f) && (b.s || b.f);
    }

    /**
     * @brief operator || for uint256_t
     * @param b number to be compared with this
     * @returns true if one of the values are not zero, else false
     */
    inline bool operator||(const uint256_t &b) {
        return (s || f) || (b.s || b.f);
    }

    /**
     * @brief operator () for uint256_t
     * @returns true if this value is non-zero, else false
     */
    inline bool operator()() { return s || f; }

    /**
     * @brief operator < for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is less than other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator<(const T &other) {
        return *this < uint256_t(other);
    }

    /**
     * @brief operator <= for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is less than or equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator<=(const T &other) {
        return *this <= uint256_t(other);
    }

    /**
     * @brief operator > for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is greater than other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator>(const T &other) {
        return *this > uint256_t(other);
    }

    /**
     * @brief operator >= for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is greater than or equal other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator>=(const T &other) {
        return *this >= uint256_t(other);
    }

    /**
     * @brief operator == for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator==(const T &other) {
        return *this == uint256_t(other);
    }

    /**
     * @brief operator != for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is not equal to other, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    bool operator!=(const T &other) {
        return *this != uint256_t(other);
    }

    /**
     * @brief operator && for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is both values are non-zero, else false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator&&(const T &b) {
        return (s || f) && (b);
    }

    /**
     * @brief operator || for other types
     * @tparam T integral type
     * @param other number to be compared with this
     * @returns true if this is either one of the values are non-zero, else
     * false
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline bool operator||(const T &b) {
        return (s || f) || (b);
    }

    /**
     * @brief operator ~ for uint256_t
     * @returns 1's complement of this number
     */
    inline uint256_t operator~() { return {~f, ~s}; }

    /**
     * @brief operator << for uint256_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns value of this shifted by p to left
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint256_t operator<<(const T &p) {
        if (!p) {
            return {this->f, this->s};
        } else if (p >= 128) {
            return uint256_t((this->s << (p - 128)), uint128_t(0));
        }
        return uint256_t((this->f << p) + (this->s >> (128 - p)),
                         (this->s << p));
    }

    /**
     * @brief operator <<= for uint256_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns this shifted by p to left
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint256_t &operator<<=(const T &p) {
        if (p) {
            if (p >= 128) {
                this->f = (this->s << (p - 128));
                this->s = uint128_t(0);
            } else {
                f = ((this->s >> (128 - p)) + (this->f << p));
                s = (this->s << p);
            }
        }
        return *this;
    }

    /**
     * @brief operator >> for uint256_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns value of this shifted by p to right
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint256_t operator>>(const T &p) {
        if (!p) {
            return {this->f, this->s};
        } else if (p >= 128) {
            return uint256_t(uint128_t(0), (this->f >> (p - 128)));
        }
        return uint256_t((this->f >> p),
                         (this->s >> p) + (this->f << (128 - p)));
    }

    /**
     * @brief operator >>= for uint256_t
     * @tparam T integral type
     * @param p number denoting number of shifts
     * @returns this shifted by p to right
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    uint256_t &operator>>=(const T &p) {
        if (p) {
            if (p >= 128) {
                f = uint128_t(0);
                s = (this->f >> (p - 128));
            } else {
                s = (this->s >> p) + (this->f << (128 - p));
                f = (this->f >> p);
            }
        }
        return *this;
    }

    /**
     * @brief operator & for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this & p (& is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator&(const T &p) {
        return *this & uint256_t(p);
    }

    /**
     * @brief operator & for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this & p (& is bit-wise operator)
     */
    inline uint256_t operator&(const uint256_t &p) {
        return {f & p.f, s & p.s};
    }

    /**
     * @brief operator &= for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this & p (& is bit-wise operator)
     */
    inline uint256_t &operator&=(const uint256_t &p) {
        f &= p.f;
        s &= p.s;
        return *this;
    }

    /**
     * @brief operator &= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this & p (& is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator&=(const T p) {
        s &= p.s;
        return *this;
    }

    /**
     * @brief operator | for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this | p (| is bit-wise operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator|(const T &p) {
        return *this | uint256_t(p);
    }

    /**
     * @brief operator | for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this | p (| is bit-wise OR operator)
     */
    inline uint256_t operator|(const uint256_t &p) {
        return {this->f | p.f, this->s | p.s};
    }

    /**
     * @brief operator |= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this | p (| is bit-wise OR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator|=(const T &p) {
        s |= p;
        return *this;
    }

    /**
     * @brief operator |= for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this | p (| is bit-wise OR operator)
     */
    inline uint256_t &operator|=(const uint256_t &p) {
        f |= p.f;
        s |= p.s;
        return *this;
    }

    /**
     * @brief operator ^ for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns value of this ^ p (^ is bit-wise XOR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t operator^(const T &p) {
        return uint256_t(f, s ^ p);
    }

    /**
     * @brief operator ^ for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns value of this ^ p (^ is bit-wise XOR operator)
     */
    inline uint256_t operator^(const uint256_t &p) {
        return {this->f ^ p.f, this->s ^ p.s};
    }

    /**
     * @brief operator ^= for uint256_t (bitwise operator)
     * @param p number to be operated
     * @returns this = this ^ p (^ is bit-wise XOR operator)
     */
    inline uint256_t &operator^=(const uint256_t &p) {
        f ^= p.f;
        s ^= p.s;
        return *this;
    }

    /**
     * @brief operator ^= for other types (bitwise operator)
     * @tparam T integral type
     * @param p number to be operated
     * @returns this = this ^ p (^ is bit-wise XOR operator)
     */
    template <typename T, typename = typename std::enable_if<
                              std::is_integral<T>::value, T>::type>
    inline uint256_t &operator^=(const T &p) {
        s ^= p;
        return *this;
    }

    /**
     * @brief operator << for printing uint256_t integer
     * @details Prints the uint256_t integer in decimal form
     * @note Note that this operator is costly since it uses strings to print
     * the value
     * @param op ostream object
     * @param p 256-bit integer
     * @returns op, ostream object.
     */
    friend std::ostream &operator<<(std::ostream &op, uint256_t p) {
        if (!p.f) {
            op << p.s;
        } else {
            std::string out = "0", p_2 = "1";
            uint128_t L(1);
            for (uint64_t i = 0; i < 128; ++i) {
                if ((p.s & L)) {
                    out = add(out, p_2);
                }
                p_2 = add(p_2, p_2);
                L <<= 1;
            }
            L = uint128_t(1);
            for (int i = 0; i < 128; ++i) {
                if ((p.f & L)) {
                    out = add(out, p_2);
                }
                p_2 = add(p_2, p_2);
                L <<= 1;
            }
            op << out;
        }
        return op;
    }
};

// Artihmetic
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator+(const T p, const uint256_t &q) {
    return uint256_t(p) + q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator-(const T p, const uint256_t &q) {
    return (uint256_t(p) - q);
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator*(const T p, const uint256_t &q) {
    return uint256_t(p) * q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator/(const T p, const uint256_t &q) {
    return uint256_t(p) / q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator%(const T p, const uint256_t &q) {
    return uint256_t(p) % q;
}

// Bitwise operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator&(const T &p, const uint256_t &q) {
    return uint256_t(p) & q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator|(const T p, const uint256_t &q) {
    return uint256_t(p) | q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline uint256_t operator^(const T p, const uint256_t &q) {
    return uint256_t(p) ^ q;
}

// Boolean operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator&&(const T p, const uint256_t &q) {
    return uint256_t(p) && q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator||(const T p, const uint256_t &q) {
    return uint256_t(p) || q;
}

// Comparison operators
template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator==(const T p, const uint256_t &q) {
    return uint256_t(p) == q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator!=(const T p, const uint256_t &q) {
    return uint256_t(p) != q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator<(const T p, const uint256_t &q) {
    return uint256_t(p) < q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator<=(const T p, const uint256_t &q) {
    return uint256_t(p) <= q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator>(const T p, const uint256_t &q) {
    return uint256_t(p) > q;
}

template <typename T, typename = typename std::enable_if<
                          std::is_integral<T>::value, T>::type>
inline bool operator>=(const T p, const uint256_t &q) {
    return uint256_t(p) >= q;
}

#endif  // CIPHERS_UINT256_T_HPP_
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.