mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
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 for276fde9d
* Comment modification * clang-format and clang-tidy fixes forae6a048d
* Comment modification * Wrong return * clang-format and clang-tidy fixes forbb40ea4c
* Type checks * windows error * clang-format and clang-tidy fixes for2c41f111
* Error handling * Error handling-2 * Comments * Comment modifications * Update ciphers/uint128_t.hpp Co-authored-by: David Leal <halfpacho@gmail.com> * Comment modifications-2 * Comment modifications-3 * Empty commit * Comments * Additional comments * clang-format and clang-tidy fixes forf7daaa15
* 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 <halfpacho@gmail.com>
This commit is contained in:
parent
c854b78bc9
commit
d9a97f106f
@ -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)
|
||||
|
||||
|
325
ciphers/elliptic_curve_key_exchange.cpp
Normal file
325
ciphers/elliptic_curve_key_exchange.cpp
Normal file
@ -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 <cassert> /// for assert
|
||||
#include <iostream> /// 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;
|
||||
}
|
1106
ciphers/uint128_t.hpp
Normal file
1106
ciphers/uint128_t.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1074
ciphers/uint256_t.hpp
Normal file
1074
ciphers/uint256_t.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user