Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers

This commit is contained in:
Ashish Bhanu Daulatabad 2021-04-10 21:43:52 +05:30
parent ff7e9e5c5e
commit 3cfa917e5e
3 changed files with 2087 additions and 0 deletions

View File

@ -0,0 +1,298 @@
/**
* @file elliptic_curve_key_exchange.cpp
* @brief Implementation of [Elliptic Curve Diffie Hellman Key
* Exchange](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange).
*
* @details
* The ECDH (Elliptic Curve DiffieHellman Key Exchange) is anonymous key
* agreement scheme, which allows two parties, each having an elliptic-curve
* publicprivate key pair, to establish a shared secret over an insecure
* channel.
* ECDH is very similar to the classical DHKE (DiffieHellman Key Exchange)
* algorithm, but it uses ECC point multiplication instead of modular
* exponentiations. ECDH is based on the following property of EC points:
* (a * G) * b = (b * G) * a
* If we have two secret numbers a and b (two private keys, belonging to Alice
* and Bob) and an ECC elliptic curve with generator point G, we can exchange
* over an insecure channel the values (a * G) and (b * G) (the public keys of
* Alice and Bob) and then we can derive a shared secret:
* secret = (a * G) * b = (b * G) * a.
* Pretty simple. The above equation takes the following form:
* alicePubKey * bobPrivKey = bobPubKey * alicePrivKey = secret
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
*/
#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iostream>
#include "uint256_t.hpp"
/**
* @namespace ciphers
* @brief Cipher algorithms
*/
namespace ciphers {
/**
* @brief namespace elliptic_curve_key_exchange
* @details Demonstration of ECDH (Elliptic Curve Diffie-Hellman) key exchange.
*/
namespace elliptic_curve_key_exchange {
/**
* @brief Definition of struct Point
* @details Definition of Point in the curve.
*/
typedef struct Point {
uint256_t x, y;
inline bool operator==(const Point &p) { return x == p.x && y == p.y; }
friend std::ostream &operator<<(std::ostream &op, const Point &p) {
op << p.x << " " << p.y;
return op;
}
} Point;
/**
* @brief This function calculates number raised to exponent power under modulo
* mod using [Modular
* Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_exponentiation.cpp).
* @param number integer base
* @param power unsigned integer exponent
* @param mod integer modulo
* @return number raised to power modulo mod
*/
uint256_t exp(uint256_t number, uint256_t power, const uint256_t &mod) {
if (!power) {
return uint256_t(1);
}
uint256_t ans(1);
number = number % mod;
while (power) {
if ((power & 1)) {
ans = (ans * number) % mod;
}
power >>= 1;
if (power)
number = (number * number) % mod;
}
return ans;
}
/**
* @brief Addition of points
* @details Add given point to generate third point
* @param a First point
* @param b Second point
* @param curve_a_coeff Coefficient of given curve (y^2 = x^3 + ax + b) % mod
* @param mod Given field
* @return the resultant point
*/
Point addition(Point a, Point b, uint256_t curve_a_coeff, uint256_t mod) {
uint256_t lambda; /// Slope
uint256_t zero; /// value zero
lambda = zero = 0;
uint256_t inf = ~zero;
if (a.x != b.x || a.y != b.y) {
// Slope being infinite.
if (b.x == a.x) {
return {inf, inf};
}
uint256_t num = (b.y - a.y + mod), den = (b.x - a.x + mod);
lambda = (num * (exp(den, mod - 2, mod))) % mod;
} else {
// Slope being infinite
// Taking dertivative of y^2 = x^3 + ax + b
// 2y dy = (3 * x^2 + a)dx
// (dy/dx) = (3x^2 + a)/(2y)
if (!a.y) {
return {inf, inf};
}
uint256_t axsq = ((a.x * a.x)) % mod;
// Mulitply by 3 adjustment
axsq += (axsq << 1);
axsq %= mod;
// Mulitply by 2 adjustment
uint256_t a_2 = (a.y << 1);
lambda =
(((axsq + curve_a_coeff) % mod) * exp(a_2, mod - 2, mod)) % mod;
}
Point c;
// new point: x = ((lambda^2) - x1 - x2)
// y = (lambda * (x1 - x)) - y1
c.x = ((lambda * lambda) % mod + (mod << 1) - a.x - b.x) % mod;
c.y = (((lambda * (a.x + mod - c.x)) % mod) + mod - a.y) % mod;
return c;
}
/**
* @brief multiply Point and integer
* @details Multiply Point by a scalar factor (here it is a private key p). The
* multiplication is called as double and add method
* @param a Point to multiply
* @param curve_a_coeff Coefficient of given curve (y^2 = x^3 + ax + b) % mod
* @param p The scalar value
* @param mod Given field
* @returns the resultant point
*/
Point multiply(const Point &a, const uint256_t &curve_a_coeff, uint256_t p,
uint256_t mod) {
Point N = a;
N.x %= mod;
N.y %= mod;
uint256_t inf;
inf = ~uint256_t(0);
Point Q = {inf, inf};
while (p) {
if ((p & 1)) {
if (Q.x == inf && Q.y == inf) {
Q.x = N.x;
Q.y = N.y;
} else {
Q = addition(Q, N, curve_a_coeff, mod);
}
}
p >>= 1;
if (p)
N = addition(N, N, curve_a_coeff, mod);
}
return Q;
}
} // namespace elliptic_curve_key_exchange
} // namespace ciphers
/**
* @brief Function to test the
* uint128_t header
* @returns void
*/
static void uint128_t_tests() {
// Tests 1: Operations test
uint128_t a("122"), b("2312");
assert(a + b == uint128_t("2434"));
assert(b - a == uint128_t("2190"));
assert(a * b == uint128_t("282064"));
assert(b / a == uint128_t("18"));
assert(b % a == uint128_t("116"));
assert((a & b) == uint128_t(8));
assert((a | b) == 2426);
assert((a ^ b) == 2418);
assert((a << 64) == uint128_t("2250502776992565297152"));
assert((b >> 7) == 18);
// Tests 2: Operations test
a = uint128_t("12321421424232142122");
b = uint128_t("23123212");
assert(a + b == uint128_t("12321421424255265334"));
assert(a - b == uint128_t("12321421424209018910"));
assert(a * b == uint128_t("284910839733861759501135864"));
assert(a / b == uint128_t("532859423865"));
assert(a % b == uint128_t("3887742"));
assert((a & b) == uint128_t(18912520));
assert((a | b) == uint128_t("12321421424236352814"));
assert((a ^ b) == uint128_t("12321421424217440294"));
assert((a << 64) == uint128_t("227290107637132170748078080907806769152"));
}
/**
* @brief Function to test the
* uint256_t header
* @returns void
*/
static void uint256_t_tests() {
// Tests 1: Operations test
uint256_t a("122"), b("2312");
assert(a + b == uint256_t("2434"));
assert(b - a == uint256_t("2190"));
assert(a * b == uint256_t("282064"));
assert(b / a == uint256_t("18"));
assert(b % a == uint256_t("116"));
assert((a & b) == uint256_t(8));
assert((a | b) == 2426);
assert((a ^ b) == 2418);
assert((a << 64) == uint256_t("2250502776992565297152"));
assert((b >> 7) == 18);
// Tests 2: Operations test
a = uint256_t("12321423124513251424232142122");
b = uint256_t("23124312431243243215354315132413213212");
assert(a + b == uint256_t("23124312443564666339867566556645355334"));
// Since a < b, the value is greater
assert(a - b == uint256_t("115792089237316195423570985008687907853246860353"
"221642219366742944204948568846"));
assert(a * b == uint256_t("284924437928789743312147393953938013677909398222"
"169728183872115864"));
assert(b / a == uint256_t("1876756621"));
assert(b % a == uint256_t("2170491202688962563936723450"));
assert((a & b) == uint256_t("3553901085693256462344"));
assert((a | b) == uint256_t("23124312443564662785966480863388892990"));
assert((a ^ b) == uint256_t("23124312443564659232065395170132430646"));
assert((a << 128) == uint256_t("4192763024643754272961909047609369343091683"
"376561852756163540549632"));
}
/**
* @brief Function to test the
* provided algorithm above
* @returns void
*/
static void test() {
// demonstration of key exchange using curve secp112r1
// Equation of the form y^2 = (x^3 + ax + b) % P (here p is mod)
uint256_t a("4451685225093714772084598273548424"),
b("2061118396808653202902996166388514"),
mod("4451685225093714772084598273548427");
// Generator value: is pre-defined for the given curve
ciphers::elliptic_curve_key_exchange::Point ptr = {
uint256_t("188281465057972534892223778713752"),
uint256_t("3419875491033170827167861896082688")};
// Shared key generation.
// For alice
std::cout << "For alice:\n";
// Alice's private key (can be generated randomly)
uint256_t alice_private_key("164330438812053169644452143505618");
ciphers::elliptic_curve_key_exchange::Point alice_public_key =
multiply(ptr, a, alice_private_key, mod);
std::cout << "\tPrivate key: " << alice_private_key << "\n";
std::cout << "\tPublic Key: " << alice_public_key << std::endl;
// For Bob
std::cout << "For Bob:\n";
// Bob's private key (can be generated randomly)
uint256_t bob_private_key("1959473333748537081510525763478373");
ciphers::elliptic_curve_key_exchange::Point bob_public_key =
multiply(ptr, a, bob_private_key, mod);
std::cout << "\tPrivate key: " << bob_private_key << "\n";
std::cout << "\tPublic Key: " << bob_public_key << std::endl;
// After public key exchange, create a shared key for communication.
// create shared key:
ciphers::elliptic_curve_key_exchange::Point alice_shared_key = multiply(
bob_public_key, a,
alice_private_key, mod),
bob_shared_key = multiply(
alice_public_key, a,
bob_private_key, mod);
std::cout << "Shared keys:\n";
std::cout << alice_shared_key << std::endl;
std::cout << bob_shared_key << std::endl;
assert(alice_shared_key == bob_shared_key);
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
uint128_t_tests(); // running predefined 128-bit unsigned integer tests.
uint256_t_tests(); // running predefined 256-bit unsigned integer tests.
test(); // running predefined tests
return 0;
}

896
ciphers/uint128_t.hpp Normal file
View File

@ -0,0 +1,896 @@
/**
* @file uint128_t.hpp
*
* @details Implementation of 128-bit unsigned integers.
* @note The implementation can be flagged as not completed. This header is used
* with enough operations as a part of bigger integer types 256-bit integer.
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
*/
#include <algorithm>
#include <ostream>
#include <string>
#include <utility>
#ifndef CIPHERS_UINT128_T_HPP_
#define CIPHERS_UINT128_T_HPP_
class uint128_t;
template <>
struct std::is_integral<uint128_t> : std::true_type {};
template <>
struct std::is_arithmetic<uint128_t> : std::true_type {};
template <>
struct std::is_unsigned<uint128_t> : std::true_type {};
/**
* @brief Adding two string
* @details Adds two long integer, only used for printing numbers
* @param first First integer string
* @param second Second integer string
* @returns string denoting the addition of both the strings.
*/
std::string add(const std::string &first, const std::string &second) {
std::string third;
int16_t sum = 0, carry = 0;
for (int i = first.size() - 1, j = second.size() - 1; i >= 0 || j >= 0;
--i, --j) {
sum = ((i >= 0 ? first[i] - '0' : 0) + (j >= 0 ? second[j] - '0' : 0) +
carry);
carry = sum / 10;
sum %= 10;
third.push_back(sum + '0');
}
if (carry) {
third.push_back('1');
}
std::reverse(third.begin(), third.end());
return third;
}
/**
* @class uint128_t
* @details 128-bit numbers.
*/
class uint128_t {
uint64_t f, s; /// First and second half of 128 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 = 0;
if (str.size() > 1 && str[1] == 'x') { // if hexadecimal
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 { // if decimal
for (auto &x : str) {
*this *= 10LL;
*this += (x - '0');
}
}
}
public:
uint128_t() = default;
/**
* @brief Parameterized constructor
* @param low lower part 8-bit unisgned integer
*/
explicit uint128_t(uint8_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 16-bit unisgned integer
*/
explicit uint128_t(uint16_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 32-bit unisgned integer
*/
explicit uint128_t(uint32_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 64-bit unisgned integer
*/
explicit uint128_t(uint64_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 8-bit integer
*/
explicit uint128_t(int8_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 16-bit integer
*/
explicit uint128_t(int16_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 32-bit integer
*/
explicit uint128_t(int32_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 64-bit integer
*/
explicit uint128_t(int64_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param str Integer string (hexadecimal starting with 0x.. or decimal)
*/
explicit uint128_t(const std::string &str) {
__get_integer_from_string(str);
}
/**
* @brief Parameterized constructor
* @param high higher part 64-bit unsigned integer
* @param low lower part 64-bit unsigned integer
*/
uint128_t(const uint64_t high, const uint64_t low) : f(high), s(low) {}
/**
* @brief Copy constructor
* @param num 128-bit unsigned integer
*/
uint128_t(const uint128_t &num) : f(num.f), s(num.s) {}
/**
* @brief Move constructor
* @param num 128-bit unsigned integer
*/
uint128_t(uint128_t &&num) : f(std::move(num.f)), s(std::move(num.s)) {}
/**
* @brief Leading zeroes in binary
* @details Calculates leading zeros in 128-bit integer
* @returns Integer denoting leading zeroes
*/
inline uint32_t _lez() {
if (f)
return __builtin_clzll(f);
return 64 + __builtin_clzll(s);
}
/**
* @brief Trailing zeroes in binary
* @details Calculates leading zeros in 128-bit integer
* @returns Integer denoting Trailing zeroes
*/
inline uint32_t _trz() {
if (s)
return __builtin_ctzll(s);
return 64 + __builtin_ctzll(f);
}
inline uint32_t _len() { return _lez(); }
// Casting operators
inline operator bool() const { return f || s; }
inline operator uint8_t() const { return s & 0xFF; }
inline operator uint16_t() const { return s & 0xFFFF; }
inline operator uint32_t() const { return s & 0xFFFFFFFF; }
inline operator uint64_t() const { return s; }
/**
* @brief returns lower 64-bit integer part
* @returns returns lower 64-bit integer part
*/
inline uint64_t lower() const { return s; }
/**
* @brief returns upper 64-bit integer part
* @returns returns upper 64-bit integer part
*/
inline uint64_t upper() const { return f; }
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t &operator=(const T &p) {
this->s = p;
return *this;
}
inline uint128_t &operator=(const std::string &p) {
__get_integer_from_string(p);
return *this;
}
inline uint128_t &operator=(const uint128_t &p) {
this->f = p.f;
this->s = p.s;
return *this;
}
inline uint128_t &operator=(uint128_t &&p) = default;
/**
* @brief operator + for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns addition of this and p, returning uint128_t integer
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t operator+(const T p) {
return uint128_t(f + (p + s < s), p + s);
}
/**
* @brief operator + for uint128_t and other integer types.
* @param p 128-bit unsigned integer
* @returns addition of this and p, returning uint128_t integer
*/
inline uint128_t operator+(const uint128_t &p) {
return uint128_t(f + (p.s + s < s) + p.f, p.s + s);
}
/**
* @brief operator += for uint128_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 uint128_t &operator+=(const T p) {
bool app = p + s < s;
this->f += app;
this->s += p;
return *this;
}
/**
* @brief operator += for uint128_t
* @param p 128-bit unsigned integer
* @returns addition of this and p, returning this
*/
uint128_t &operator+=(const uint128_t &p) {
bool app = p.s + s < s;
f = f + app + p.f;
s = p.s + s;
return *this;
}
/**
* @brief pre-increment operator
* @returns incremented value of this.
*/
inline uint128_t &operator++() {
*this += 1;
return *this;
}
/**
* @brief post-increment operator
* @returns incremented value of this.
*/
inline uint128_t operator++(int) {
++*this;
return *this;
}
/**
* @brief operator - for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns subtraction of this and p, returning uint128_t integer
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t operator-(const T &p) {
bool app = p > s;
return uint128_t(f - app, s - p);
}
/**
* @brief operator - for uint128_t
* @param p a type of integer variable
* @returns subtraction of this and p, returning uint128_t integer
*/
inline uint128_t operator-(const uint128_t &p) {
bool app = p.s > s;
return uint128_t(f - p.f - app, s - p.s);
}
/**
* @brief operator - using twos complement
* @returns 2's complement of this.
*/
inline uint128_t operator-() { return ~*this + uint128_t(1); }
/**
* @brief operator -- (pre-decrement)
* @returns decremented value of this
*/
inline uint128_t &operator--() {
*this -= 1;
return *this;
}
/**
* @brief operator -- (post-decrement)
* @returns decremented value of this
*/
inline uint128_t operator--(int p) {
--*this;
return *this;
}
/**
* @brief operator -= for uint128_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>
uint128_t &operator-=(const T &p) {
bool app = p > s;
f -= app;
s -= p;
return *this;
}
/**
* @brief operator -= for uint128_t
* @param p 128-bit unsigned integer
* @returns subtraction of this and p, returning this
*/
uint128_t &operator-=(const uint128_t &p) {
bool app = p.s > s;
f = f - p.f - app;
s = s - p.s;
return *this;
}
/**
* @brief operator * for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns multiplication of this and p, returning uint128_t integer
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t operator*(const T p) {
return *this * uint128_t(p);
}
/**
* @brief operator * for uint128_t and other integer types.
* @param p 128-bit unsigned integer
* @returns multiplication of this and p, returning uint128_t integer
*/
uint128_t operator*(const uint128_t &p) {
uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF,
s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF;
uint64_t fi = f_first * s_first, se = f_first * s_second,
th = s_first * f_second, fo = s_second * f_second;
uint64_t tmp = ((se & 0xFFFFFFFF) << 32), tmp2 = (th & 0xFFFFFFFF)
<< 32;
int cc = (tmp + tmp2 < tmp);
tmp += tmp2;
cc += (tmp + fo < tmp);
uint64_t carry = fi + (se >> 32) + (th >> 32);
return uint128_t(this->f * p.s + this->s * p.f + carry + cc, tmp + fo);
}
/**
* @brief operator *= for uint128_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 uint128_t &operator*=(const T p) {
*this *= uint128_t(p);
return *this;
}
/**
* @brief operator *= for uint128_t and other integer types.
* @param p 128-bit unsigned integer
* @returns multiplication of this and p, returning this
*/
uint128_t &operator*=(const uint128_t &p) {
uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF,
s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF;
uint64_t fi = f_first * s_first, se = f_first * s_second,
th = s_first * f_second, fo = s_second * f_second;
uint64_t tmp = (se << 32), tmp2 = (th << 32);
int cc = (tmp + tmp2 < tmp);
tmp += tmp2;
cc += (tmp + fo < tmp);
uint64_t carry = fi + (se >> 32) + (th >> 32);
f = this->f * p.s + this->s * p.f + carry + cc;
s = tmp + fo;
return *this;
}
/**
* @brief divide function for uint128_t and other integer types.
* @details divide this value and
* @param p 128-bit unsigned integer
* @returns pair denoting quotient and remainder.
*/
std::pair<uint128_t, uint128_t> divide(const uint128_t &p) {
if (*this < p) { // if this is less than divisor
return {uint128_t(0ULL), *this};
} else if (*this == p) { // if this is equal to divisor
return {uint128_t(1ULL), uint128_t(0ULL)};
}
uint128_t tmp = p, tmp2 = *this;
uint16_t left = tmp._lez() - _lez();
tmp <<= left;
uint128_t quotient(0);
uint128_t zero(0);
while (left >= 0 && 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 uint128_t and other integer types.
* @param p 128-bit unsigned integer
* @returns unsigned 128-bit quotient.
*/
inline uint128_t operator/(const uint128_t &p) { return divide(p).first; }
/**
* @brief operator / for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns unsigned 128-bit quotient.
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t operator/(const T p) {
uint128_t tmp = *this;
tmp /= uint128_t(0, p);
return tmp;
}
/**
* @brief operator /= for uint128_t
* @param p 128-bit unsigned integer
* @returns this set as unsigned 128-bit quotient.
*/
inline uint128_t &operator/=(const uint128_t &p) {
*this = divide(p).first;
return *this;
}
/**
* @brief operator /= for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns this set as unsigned 128-bit quotient.
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t &operator/=(const T p) {
*this /= uint128_t(0, p);
return *this;
}
/**
* @brief operator % for uint128_t
* @param p 128-bit unsigned integer
* @returns unsigned 128-bit remainder.
*/
inline uint128_t operator%(const uint128_t &p) { return divide(p).second; }
/**
* @brief operator % for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns unsigned 128-bit remainder.
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t operator%(const T &p) {
return *this % uint128_t(p);
}
/**
* @brief operator %= for uint128_t
* @param p 128-bit unsigned integer
* @returns this set as unsigned 128-bit remainder.
*/
inline uint128_t &operator%=(const uint128_t &p) {
*this = divide(p).second;
return *this;
}
/**
* @brief operator %= for uint128_t
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns this set as unsigned 128-bit remainder.
*/
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline uint128_t &operator%=(const T &p) {
*this %= uint128_t(p);
return *this;
}
// Comparison operators
inline bool operator<(const uint128_t &other) {
return f < other.f || (f == other.f && s < other.s);
}
inline bool operator<=(const uint128_t &other) {
return f < other.f || (f == other.f && s <= other.s);
}
inline bool operator>(const uint128_t &other) {
return f > other.f || (f == other.f && s > other.s);
}
inline bool operator>=(const uint128_t &other) {
return (f > other.f) || (f == other.f && s >= other.s);
}
inline bool operator==(const uint128_t &other) {
return f == other.f && s == other.s;
}
inline bool operator!=(const uint128_t &other) {
return f != other.f || s != other.s;
}
inline bool operator!() { return !f && !s; }
inline bool operator&&(const uint128_t &b) {
return (s || f) && (b.s || b.f);
}
inline bool operator||(const uint128_t &b) {
return (s || f) || (b.s || b.f);
}
inline bool operator()() { return s || f; }
// other operators
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator<(const T other) {
return *this < uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator<=(const T other) {
return *this <= uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator>(const T other) {
return *this > uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator>=(const T other) {
return *this >= uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator==(const T other) {
return *this == uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator!=(const T other) {
return *this != uint128_t(other);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator&&(const T b) {
return (f || s) && b;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
inline bool operator||(const T b) {
return (f || s) || b;
}
// Bitwise operators
uint128_t operator~() { return uint128_t(~this->f, ~this->s); }
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator<<(const T p) {
if (!p) {
return uint128_t(f, s);
}
if (p >= 64) {
return uint128_t((this->s << (p - 64)), 0);
}
return uint128_t((this->f << p) + ((this->s >> (64 - p))),
this->s << p);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t &operator<<=(const T p) {
if (p) {
if (p >= 64) {
this->f = (this->s << (p - 64));
this->s = 0;
} else {
f = ((this->f << p) + (this->s >> (64 - p)));
s = (this->s << p);
}
}
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator>>(const T p) {
if (!p) {
return uint128_t(this->f, this->s);
}
if (p >= 64) {
return uint128_t(0, (this->f >> (p - 64)));
}
return uint128_t((this->f >> p),
(this->s >> p) + (this->f << (64 - p)));
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t &operator>>=(const T p) {
if (p) {
if (p >= 64) {
f = 0;
s = (this->f >> (p - 64));
} else {
s = (this->s >> p) + (this->f << (64 - p));
f = (this->f >> p);
}
}
return *this;
}
uint128_t operator&(const uint128_t &p) {
return uint128_t(this->f & p.f, this->s & p.s);
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator&(const T p) {
uint128_t tmp = *this;
return tmp & uint128_t(p);
}
uint128_t &operator&=(const uint128_t &p) {
this->f &= p.f;
this->s &= p.s;
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t &operator&=(const T p) {
*this &= uint128_t(p);
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator|(const T p) {
return uint128_t(p | s);
}
uint128_t operator|(const uint128_t &p) {
return uint128_t(this->f | p.f, this->s | p.s);
}
uint128_t &operator|=(const uint128_t &p) {
f |= p.f;
s |= p.s;
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t &operator|=(const T p) {
s |= p.s;
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator^(const T p) {
return uint128_t(this->f, this->s ^ p);
}
uint128_t operator^(const uint128_t &p) {
return uint128_t(this->f ^ p.f, this->s ^ p.s);
}
uint128_t &operator^=(const uint128_t &p) {
f ^= p.f;
s ^= p.s;
return *this;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t &operator^=(const T &p) {
s ^= p;
return *this;
}
/**
* @brief Costly std::cout operation.
*/
friend std::ostream &operator<<(std::ostream &op, const uint128_t &p) {
if (!p.f) {
op << p.s;
} else {
std::string out = "0", p_2 = "1";
for (int i = 0; i < 64; ++i) {
if (p.s & (1LL << i)) {
out = add(out, p_2);
}
p_2 = add(p_2, p_2);
}
for (int i = 0; i < 64; ++i) {
if (p.f & (1LL << i)) {
out = add(out, p_2);
}
p_2 = add(p_2, p_2);
}
op << out;
}
return op;
}
};
// Arithmetic operators
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator+(const T &p, const uint128_t &q) {
return uint128_t(p) + q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator-(const T p, const uint128_t &q) {
return uint128_t(p) - q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator*(const T p, const uint128_t &q) {
return q * p;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator/(const T p, const uint128_t &q) {
return uint128_t(p) / q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator%(const T p, const uint128_t &q) {
return uint128_t(p) % q;
}
// Bitwise operators
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator&(const T &p, const uint128_t &q) {
return uint128_t(p) & q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator|(const T p, const uint128_t &q) {
return uint128_t(p) | q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint128_t operator^(const T p, const uint128_t &q) {
return uint128_t(p) ^ q;
}
// Boolean operators
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator&&(const T p, const uint128_t &q) {
return uint128_t(p) && q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator||(const T p, const uint128_t &q) {
return uint128_t(p) || q;
}
// Comparison operators
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator==(const T p, const uint128_t &q) {
return uint128_t(p) == q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator!=(const T p, const uint128_t &q) {
return uint128_t(p) != q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator<(const T p, const uint128_t &q) {
return uint128_t(p) < q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator<=(const T p, const uint128_t &q) {
return uint128_t(p) <= q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator>(const T p, const uint128_t &q) {
return uint128_t(p) > q;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
bool operator>=(const T p, const uint128_t &q) {
return uint128_t(p) >= q;
}
#endif // CIPHERS_UINT128_T_HPP_

893
ciphers/uint256_t.hpp Normal file
View File

@ -0,0 +1,893 @@
/**
* @file uint128_t.hpp
*
* @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>
#include <utility>
#include "uint128_t.hpp"
#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
* @details 256-bit number class.
*/
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
* @param low lower part 8-bit unisgned integer
*/
explicit uint256_t(uint8_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 16-bit unisgned integer
*/
explicit uint256_t(uint16_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 32-bit unisgned integer
*/
explicit uint256_t(uint32_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 64-bit unisgned integer
*/
explicit uint256_t(uint64_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 128-bit unisgned integer
*/
explicit uint256_t(const uint128_t &low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 8-bit integer
*/
explicit uint256_t(int8_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 16-bit integer
*/
explicit uint256_t(int16_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 32-bit integer
*/
explicit uint256_t(int32_t low) : s(low), f(0) {}
/**
* @brief Parameterized constructor
* @param low lower part 64-bit integer
*/
explicit uint256_t(int64_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) : f(num.f), s(num.s) {}
/**
* @brief Move constructor
* @param num 256-bit unsigned integer
*/
uint256_t(uint256_t &&num) : 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(const uint128_t &high, const uint128_t &low) : f(high), s(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 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();
}
inline uint32_t _len() { return _lez(); }
inline operator bool() const { return f || s; }
inline operator uint8_t() const { return s.lower(); }
inline operator uint16_t() const { return s.lower(); }
inline operator uint32_t() const { return s.lower(); }
inline operator uint64_t() const { return s.lower(); }
inline 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; }
// Assign
inline uint256_t &operator=(const uint256_t &p) {
this->f = p.f;
this->s = p.s;
return *this;
}
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;
}
inline uint256_t &operator=(const std::string &p) {
__get_integer_from_string(p);
return *this;
}
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 128-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 uint256_t(f + app + p.f, p.s + 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 = (p.s + s < s);
f += _app + p.f;
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 = p.s > s;
return uint256_t(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 -= app;
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 = p.s > s;
f = f - app - p.f;
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 uint256_t(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 128-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(0ULL), *this};
} else if (*this == p) { // if this is equal to divisor
return {uint256_t(1ULL), uint256_t(0ULL)};
}
uint256_t tmp = p, tmp2 = *this;
uint16_t left = tmp._lez() - _lez();
tmp <<= left;
uint256_t quotient(0);
uint256_t zero(0);
while (left >= 0 && 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 uint128_t
* @param p 128-bit unsigned integer
* @returns unsigned 128-bit remainder.
*/
inline uint256_t operator%(const uint256_t &p) { return divide(p).second; }
/**
* @brief operator % for uint128_t and other integer types.
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns unsigned 128-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 uint128_t
* @param p 128-bit unsigned integer
* @returns this set as unsigned 128-bit remainder.
*/
inline uint256_t &operator%=(const uint256_t &p) {
*this = divide(p).second;
return *this;
}
/**
* @brief operator %= for uint128_t
* @tparam T denoting integral type
* @param p a type of integer variable
* @returns this set as unsigned 128-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;
}
// Comparison operators
inline bool operator<(const uint256_t &other) {
return f < other.f || (f == other.f && s < other.s);
}
inline bool operator<=(const uint256_t &other) {
return f < other.f || (f == other.f && s <= other.s);
}
inline bool operator>(const uint256_t &other) {
return f > other.f || (f == other.f && s > other.s);
}
inline bool operator>=(const uint256_t &other) {
return (f > other.f) || (f == other.f && s >= other.s);
}
inline bool operator==(const uint256_t &other) {
return f == other.f && s == other.s;
}
inline bool operator!=(const uint256_t &other) {
return !((*this) == other);
}
inline bool operator!() { return !f && !s; }
inline bool operator&&(const uint256_t &b) {
return (s || f) && (b.s || b.f);
}
inline bool operator||(const uint256_t &b) {
return (s || f) || (b.s || b.f);
}
inline bool operator()() { return s || f; }
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
// Bitwise operators
inline uint256_t operator~() { return uint256_t(~f, ~s); }
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint256_t operator<<(const T &p) {
if (!p) {
return uint256_t(this->f, this->s);
}
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));
}
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;
}
template <typename T, typename = typename std::enable_if<
std::is_integral<T>::value, T>::type>
uint256_t operator>>(const T &p) {
if (!p) {
return uint256_t(this->f, this->s);
}
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)));
}
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;
}
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(p & s);
}
inline uint256_t operator&(const uint256_t &p) {
return uint256_t(f & p.f, s & p.s);
}
inline uint256_t &operator&=(const uint256_t &p) {
f &= p.f;
s &= p.s;
return *this;
}
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;
}
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(this->s | p);
}
inline uint256_t operator|(const uint256_t &p) {
return uint256_t(this->f | p.f, this->s | p.s);
}
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;
}
inline uint256_t &operator|=(const uint256_t &p) {
f |= p.f;
s |= p.s;
return *this;
}
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);
}
inline uint256_t operator^(const uint256_t &p) {
return uint256_t(this->f ^ p.f, this->s ^ p.s);
}
inline uint256_t &operator^=(const uint256_t &p) {
f ^= p.f;
s ^= p.s;
return *this;
}
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 Costly std::cout operation.
*/
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_