From d9a97f106f8e6b93e1d78cec6d7c9a85330cae3e Mon Sep 17 00:00:00 2001 From: Ashish Bhanu Daulatabad Date: Wed, 14 Apr 2021 11:04:01 +0530 Subject: [PATCH] Feat: Implementation of Elliptic Curve Diffie Hellman Key Exchange. (#1479) * updating DIRECTORY.md * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers * updating DIRECTORY.md * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling-2 * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling-bit handling * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling-bit handling * Feat: Elliptic Curve Diffie Hellman Key Exchange, Ciphers: Error handling-bit handling * Type checks and destructor added * Type checks and integer shift checked * clang-format and clang-tidy fixes for 276fde9d * Comment modification * clang-format and clang-tidy fixes for ae6a048d * Comment modification * Wrong return * clang-format and clang-tidy fixes for bb40ea4c * Type checks * windows error * clang-format and clang-tidy fixes for 2c41f111 * Error handling * Error handling-2 * Comments * Comment modifications * Update ciphers/uint128_t.hpp Co-authored-by: David Leal * Comment modifications-2 * Comment modifications-3 * Empty commit * Comments * Additional comments * clang-format and clang-tidy fixes for f7daaa15 * Empty commit for build * Additional test correction and comment modification Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal --- DIRECTORY.md | 3 + ciphers/elliptic_curve_key_exchange.cpp | 325 +++++++ ciphers/uint128_t.hpp | 1106 +++++++++++++++++++++++ ciphers/uint256_t.hpp | 1074 ++++++++++++++++++++++ 4 files changed, 2508 insertions(+) create mode 100644 ciphers/elliptic_curve_key_exchange.cpp create mode 100644 ciphers/uint128_t.hpp create mode 100644 ciphers/uint256_t.hpp diff --git a/DIRECTORY.md b/DIRECTORY.md index d144131db8f..5117a9ba585 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -16,8 +16,11 @@ ## Ciphers * [Base64 Encoding](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/base64_encoding.cpp) * [Caesar Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/caesar_cipher.cpp) + * [Elliptic Curve Key Exchange](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/elliptic_curve_key_exchange.cpp) * [Hill Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/hill_cipher.cpp) * [Morse Code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/morse_code.cpp) + * [Uint128 T](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/uint128_t.hpp) + * [Uint256 T](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/uint256_t.hpp) * [Vigenere Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/vigenere_cipher.cpp) * [Xor Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/xor_cipher.cpp) diff --git a/ciphers/elliptic_curve_key_exchange.cpp b/ciphers/elliptic_curve_key_exchange.cpp new file mode 100644 index 00000000000..0a9ce3cd0e3 --- /dev/null +++ b/ciphers/elliptic_curve_key_exchange.cpp @@ -0,0 +1,325 @@ +/** + * @file + * @brief Implementation of [Elliptic Curve Diffie Hellman Key + * Exchange](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange). + * + * @details + * The ECDH (Elliptic Curve Diffie–Hellman Key Exchange) is anonymous key + * agreement scheme, which allows two parties, each having an elliptic-curve + * public–private key pair, to establish a shared secret over an insecure + * channel. + * ECDH is very similar to the classical DHKE (Diffie–Hellman 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 /// for assert +#include /// for IO operations + +#include "uint256_t.hpp" /// for 256-bit integer + +/** + * @namespace ciphers + * @brief Cipher algorithms + */ +namespace ciphers { +/** + * @brief namespace elliptic_curve_key_exchange + * @details Demonstration of [Elliptic Curve + * Diffie-Hellman](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange) + * 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; /// x and y co-ordinates + + /** + * @brief operator == for Point + * @details check whether co-ordinates are equal to the given point + * @param p given point to be checked with this + * @returns true if x and y are both equal with Point p, else false + */ + inline bool operator==(const Point &p) { return x == p.x && y == p.y; } + + /** + * @brief ostream operator for printing Point + * @param op ostream operator + * @param p Point to be printed on console + * @returns op, the ostream object + */ + 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. More description can be + * found + * [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition), + * and + * [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_doubling) + * @param a First point + * @param b Second point + * @param curve_a_coeff Coefficient `a` of the given curve (y^2 = x^3 + ax + b) + * % mod + * @param mod Given field + * @return the resultant point + */ +Point addition(Point a, Point b, const uint256_t &curve_a_coeff, + uint256_t mod) { + uint256_t lambda(0); /// Slope + uint256_t zero(0); /// 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 when the line is tangent to curve. This operation is performed + * while doubling. Taking derivative of `y^2 = x^3 + ax + b` + * => `2y dy = (3 * x^2 + a)dx` + * => `(dy/dx) = (3x^2 + a)/(2y)` + */ + /** + * if y co-ordinate is zero, the slope is infinite, return inf. + * else calculate the slope (here % mod and store in lambda) + */ + 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](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add) + * @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, + const 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() { + // 1st test: Operations test + uint128_t a("122"), b("2312"); + assert(a + b == 2434); + assert(b - a == 2190); + assert(a * b == 282064); + assert(b / a == 18); + assert(b % a == 116); + assert((a & b) == 8); + assert((a | b) == 2426); + assert((a ^ b) == 2418); + assert((a << 64) == uint128_t("2250502776992565297152")); + assert((b >> 7) == 18); + + // 2nd test: 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 == 532859423865LL); + assert(a % b == 3887742); + assert((a & b) == 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() { + // 1st test: Operations test + uint256_t a("122"), b("2312"); + assert(a + b == 2434); + assert(b - a == 2190); + assert(a * b == 282064); + assert(b / a == 18); + assert(b % a == 116); + assert((a & b) == 8); + assert((a | b) == 2426); + assert((a ^ b) == 2418); + assert((a << 64) == uint256_t("2250502776992565297152")); + assert((b >> 7) == 18); + + // 2nd test: 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; + + // Check whether shared keys are equal + 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 self-test implementations + return 0; +} diff --git a/ciphers/uint128_t.hpp b/ciphers/uint128_t.hpp new file mode 100644 index 00000000000..917d4a95414 --- /dev/null +++ b/ciphers/uint128_t.hpp @@ -0,0 +1,1106 @@ +/** + * @file + * + * @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 /// for `std::reverse` and other operations +#include /// for `std::cout` overload +#include /// for `std::string` +#include /// for `std::pair` library + +#ifdef _MSC_VER +#include /// for _BitScanForward64 and __BitScanReverse64 operation +#endif + +#ifndef CIPHERS_UINT128_T_HPP_ +#define CIPHERS_UINT128_T_HPP_ +class uint128_t; + +template <> +struct std::is_integral : std::true_type {}; +template <> +struct std::is_arithmetic : std::true_type {}; +template <> +struct std::is_unsigned : 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 (int32_t i = static_cast(first.size()) - 1, + j = static_cast(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 + * @brief class for 128-bit unsigned integer + */ +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 + * @tparam T integral type + * @param low lower part 8-bit unisgned integer + */ + template ::value, T>::type> + explicit uint128_t(T low) : s(low) {} + + /** + * @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) = default; + + /** + * @brief Move constructor + * @param num 128-bit unsigned integer + */ + uint128_t(uint128_t &&num) noexcept : f(num.f), s(num.s) {} + + /** + * @brief Destructor for uint128_t + */ + ~uint128_t() = default; + + /** + * @brief Leading zeroes in binary + * @details Calculates leading zeros in 128-bit integer + * @returns Integer denoting leading zeroes + */ + inline uint32_t _lez() { +#ifndef _MSC_VER + if (f) { + return __builtin_clzll(f); + } + return 64 + __builtin_clzll(s); +#else + unsigned long r = 0; + _BitScanForward64(&r, f); + if (r == 64) { + unsigned long l = 0; + _BitScanForward64(&l, s); + return 64 + l; + } + return r; +#endif + } + + /** + * @brief Trailing zeroes in binary + * @details Calculates leading zeros in 128-bit integer + * @returns Integer denoting Trailing zeroes + */ + inline uint32_t _trz() { +#ifndef _MSC_VER + if (f) { + return __builtin_ctzll(f); + } + return 64 + __builtin_ctzll(s); +#else + unsigned long r = 0; + _BitScanReverse64(&r, s); + if (r == 64) { + unsigned long l = 0; + _BitScanReverse64(&l, f); + return 64 + l; + } + return r; +#endif + } + + /** + * @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 valu + * @tparam T any integer type + * @returns integer value casted to mentioned type + */ + template ::value, T>::type> + inline explicit operator T() const { + return static_cast(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; } + + /** + * @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 ::value, T>::type> + inline uint128_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 uint128_t &operator=(const std::string &p) { + this->__get_integer_from_string(p); + return *this; + } + + /** + * @brief operator = for uint128_t + * @param p an 128-bit integer to assign it's value + * @returns this pointer with it's value equal to `p` + */ + inline uint128_t &operator=(const uint128_t &p) = default; + + /** + * @brief Move assignment operator + */ + 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 ::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 ::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 ::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 ::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 ::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 ::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 divide(const uint128_t &p) { + if (*this < p) { // if this is less than divisor + return {uint128_t(0), *this}; + } else if (*this == p) { // if this is equal to divisor + return {uint128_t(1), uint128_t(0)}; + } + 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 ::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 ::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 ::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 ::value, T>::type> + inline uint128_t &operator%=(const T &p) { + *this %= uint128_t(p); + return *this; + } + + /** + * @brief operator < for uint128_t + * @param other number to be compared with this + * @returns true if this is less than other, else false + */ + inline bool operator<(const uint128_t &other) { + return f < other.f || (f == other.f && s < other.s); + } + + /** + * @brief operator <= for uint128_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 uint128_t &other) { + return f < other.f || (f == other.f && s <= other.s); + } + + /** + * @brief operator > for uint128_t + * @param other number to be compared with this + * @returns true if this is greater than other, else false + */ + inline bool operator>(const uint128_t &other) { + return f > other.f || (f == other.f && s > other.s); + } + + /** + * @brief operator >= for uint128_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 uint128_t &other) { + return (f > other.f) || (f == other.f && s >= other.s); + } + + /** + * @brief operator == for uint128_t + * @param other number to be compared with this + * @returns true if this is equal than other, else false + */ + inline bool operator==(const uint128_t &other) { + return f == other.f && s == other.s; + } + + /** + * @brief operator != for uint128_t + * @param other number to be compared with this + * @returns true if this is not equal than other, else false + */ + inline bool operator!=(const uint128_t &other) { + return f != other.f || s != other.s; + } + + /** + * @brief operator ! for uint128_t + * @returns true if this has zero value, else false + */ + inline bool operator!() { return !f && !s; } + + /** + * @brief operator && for uint128_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 uint128_t &b) { + return (s || f) && (b.s || b.f); + } + + /** + * @brief operator || for uint128_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 uint128_t &b) { + return (s || f) || (b.s || b.f); + } + + /** + * @brief operator () for uint128_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 ::value, T>::type> + inline bool operator<(const T other) { + return *this < uint128_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 ::value, T>::type> + inline bool operator<=(const T other) { + return *this <= uint128_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 ::value, T>::type> + inline bool operator>(const T other) { + return *this > uint128_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 ::value, T>::type> + inline bool operator>=(const T other) { + return *this >= uint128_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 ::value, T>::type> + inline bool operator==(const T other) { + return *this == uint128_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 ::value, T>::type> + inline bool operator!=(const T other) { + return *this != uint128_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 ::value, T>::type> + inline bool operator&&(const T b) { + return (f || s) && 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 ::value, T>::type> + inline bool operator||(const T b) { + return (f || s) || b; + } + + /** + * @brief operator ~ for uint128_t + * @returns 1's complement of this number + */ + uint128_t operator~() { return uint128_t(~this->f, ~this->s); } + + /** + * @brief operator << for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to left + */ + template ::value, T>::type> + uint128_t operator<<(const T p) { + if (!p) { + return uint128_t(f, s); + } else if (p >= 64 && p <= 128) { + return uint128_t((this->s << (p - 64)), 0); + } else if (p < 64 && p > 0) { + return uint128_t((this->f << p) + ((this->s >> (64 - p))), + this->s << p); + } + return uint128_t(0); + } + + /** + * @brief operator <<= for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to left + */ + template ::value, T>::type> + uint128_t &operator<<=(const T p) { + if (p) { + if (p >= 64 && p <= 128) { + this->f = (this->s << (p - 64)); + this->s = 0; + } else { + f = ((this->f << p) + (this->s >> (64 - p))); + s = (this->s << p); + } + } + return *this; + } + + /** + * @brief operator >> for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to right + */ + template ::value, T>::type> + uint128_t operator>>(const T p) { + if (!p) { + return uint128_t(this->f, this->s); + } else if (p >= 64 && p <= 128) { + return uint128_t(0, (this->f >> (p - 64))); + } else if (p < 64 && p > 0) { + return uint128_t((this->f >> p), + (this->s >> p) + (this->f << (64 - p))); + } + return uint128_t(0); + } + + /** + * @brief operator >>= for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to right + */ + template ::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; + } + + /** + * @brief operator & for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this & p (& is bit-wise operator) + */ + inline uint128_t operator&(const uint128_t &p) { + return uint128_t(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 value of this & p (& is bit-wise operator) + */ + template ::value, T>::type> + uint128_t operator&(const T p) { + uint128_t tmp = *this; + return tmp & uint128_t(p); + } + + /** + * @brief operator &= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this & p (& is bit-wise operator) + */ + uint128_t &operator&=(const uint128_t &p) { + this->f &= p.f; + this->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 ::value, T>::type> + uint128_t &operator&=(const T p) { + *this &= uint128_t(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 ::value, T>::type> + inline uint128_t operator|(const T p) { + return uint128_t(p | s); + } + + /** + * @brief operator | for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this | p (| is bit-wise OR operator) + */ + inline uint128_t operator|(const uint128_t &p) { + return uint128_t(this->f | p.f, this->s | p.s); + } + + /** + * @brief operator |= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this | p (| is bit-wise OR operator) + */ + uint128_t &operator|=(const uint128_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 OR operator) + */ + template ::value, T>::type> + inline uint128_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 XOR operator) + */ + template ::value, T>::type> + inline uint128_t operator^(const T p) { + return uint128_t(this->f, this->s ^ p); + } + + /** + * @brief operator ^ for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this ^ p (^ is bit-wise XOR operator) + */ + inline uint128_t operator^(const uint128_t &p) { + return uint128_t(this->f ^ p.f, this->s ^ p.s); + } + + /** + * @brief operator ^= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this ^ p (^ is bit-wise XOR operator) + */ + uint128_t &operator^=(const uint128_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 ::value, T>::type> + inline uint128_t &operator^=(const T &p) { + s ^= p; + return *this; + } + + /** + * @brief operator << for printing uint128_t integer + * @details Prints the uint128_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 128-bit integer + * @returns op, ostream object. + */ + 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 ::value, T>::type> +inline uint128_t operator+(const T &p, const uint128_t &q) { + return uint128_t(p) + q; +} + +template ::value, T>::type> +inline uint128_t operator-(const T p, const uint128_t &q) { + return uint128_t(p) - q; +} + +template ::value, T>::type> +inline uint128_t operator*(const T p, const uint128_t &q) { + return uint128_t(p) * q; +} + +template ::value, T>::type> +inline uint128_t operator/(const T p, const uint128_t &q) { + return uint128_t(p) / q; +} + +template ::value, T>::type> +inline uint128_t operator%(const T p, const uint128_t &q) { + return uint128_t(p) % q; +} + +// Bitwise operators +template ::value, T>::type> +inline uint128_t operator&(const T &p, const uint128_t &q) { + return uint128_t(p) & q; +} + +template ::value, T>::type> +inline uint128_t operator|(const T p, const uint128_t &q) { + return uint128_t(p) | q; +} + +template ::value, T>::type> +inline uint128_t operator^(const T p, const uint128_t &q) { + return uint128_t(p) ^ q; +} + +// Boolean operators +template ::value, T>::type> +inline bool operator&&(const T p, const uint128_t &q) { + return uint128_t(p) && q; +} + +template ::value, T>::type> +inline bool operator||(const T p, const uint128_t &q) { + return uint128_t(p) || q; +} + +// Comparison operators +template ::value, T>::type> +inline bool operator==(const T p, const uint128_t &q) { + return uint128_t(p) == q; +} + +template ::value, T>::type> +inline bool operator!=(const T p, const uint128_t &q) { + return uint128_t(p) != q; +} + +template ::value, T>::type> +inline bool operator<(const T p, const uint128_t &q) { + return uint128_t(p) < q; +} + +template ::value, T>::type> +inline bool operator<=(const T p, const uint128_t &q) { + return uint128_t(p) <= q; +} + +template ::value, T>::type> +inline bool operator>(const T p, const uint128_t &q) { + return uint128_t(p) > q; +} + +template ::value, T>::type> +inline bool operator>=(const T p, const uint128_t &q) { + return uint128_t(p) >= q; +} + +#endif // CIPHERS_UINT128_T_HPP_ diff --git a/ciphers/uint256_t.hpp b/ciphers/uint256_t.hpp new file mode 100644 index 00000000000..ad300ed3743 --- /dev/null +++ b/ciphers/uint256_t.hpp @@ -0,0 +1,1074 @@ +/** + * @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 /// for `std::string` +#include /// 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 : std::true_type {}; + +template <> +struct std::is_arithmetic : std::true_type {}; + +template <> +struct std::is_unsigned : 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 ::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 ::value, T>::type> + inline explicit operator T() const { + return static_cast(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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 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 (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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 ::value, T>::type> +inline uint256_t operator+(const T p, const uint256_t &q) { + return uint256_t(p) + q; +} + +template ::value, T>::type> +inline uint256_t operator-(const T p, const uint256_t &q) { + return (uint256_t(p) - q); +} + +template ::value, T>::type> +inline uint256_t operator*(const T p, const uint256_t &q) { + return uint256_t(p) * q; +} + +template ::value, T>::type> +inline uint256_t operator/(const T p, const uint256_t &q) { + return uint256_t(p) / q; +} + +template ::value, T>::type> +inline uint256_t operator%(const T p, const uint256_t &q) { + return uint256_t(p) % q; +} + +// Bitwise operators +template ::value, T>::type> +inline uint256_t operator&(const T &p, const uint256_t &q) { + return uint256_t(p) & q; +} + +template ::value, T>::type> +inline uint256_t operator|(const T p, const uint256_t &q) { + return uint256_t(p) | q; +} + +template ::value, T>::type> +inline uint256_t operator^(const T p, const uint256_t &q) { + return uint256_t(p) ^ q; +} + +// Boolean operators +template ::value, T>::type> +inline bool operator&&(const T p, const uint256_t &q) { + return uint256_t(p) && q; +} + +template ::value, T>::type> +inline bool operator||(const T p, const uint256_t &q) { + return uint256_t(p) || q; +} + +// Comparison operators +template ::value, T>::type> +inline bool operator==(const T p, const uint256_t &q) { + return uint256_t(p) == q; +} + +template ::value, T>::type> +inline bool operator!=(const T p, const uint256_t &q) { + return uint256_t(p) != q; +} + +template ::value, T>::type> +inline bool operator<(const T p, const uint256_t &q) { + return uint256_t(p) < q; +} + +template ::value, T>::type> +inline bool operator<=(const T p, const uint256_t &q) { + return uint256_t(p) <= q; +} + +template ::value, T>::type> +inline bool operator>(const T p, const uint256_t &q) { + return uint256_t(p) > q; +} + +template ::value, T>::type> +inline bool operator>=(const T p, const uint256_t &q) { + return uint256_t(p) >= q; +} + +#endif // CIPHERS_UINT256_T_HPP_