forked from TheAlgorithms/C-Plus-Plus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: Implementation of Elliptic Curve Diffie Hellman Key Exchange. (T…
…heAlgorithms#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 276fde9 * Comment modification * clang-format and clang-tidy fixes for ae6a048 * Comment modification * Wrong return * clang-format and clang-tidy fixes for bb40ea4 * Type checks * windows error * clang-format and clang-tidy fixes for 2c41f11 * Error handling * Error handling-2 * Comments * Comment modifications * Update ciphers/uint128_t.hpp Co-authored-by: David Leal <[email protected]> * Comment modifications-2 * Comment modifications-3 * Empty commit * Comments * Additional comments * clang-format and clang-tidy fixes for f7daaa1 * 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 <[email protected]>
- Loading branch information
1 parent
c854b78
commit d9a97f1
Showing
4 changed files
with
2,508 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Oops, something went wrong.