• No results found

Elliptic Curve Cryptography

e lliptic c urve c ryptography

Algorithm 9.4: NegativeModulus(a, p) Begin

3. Adding a point with the point at infinity: When a point is added to the point of infinity, it produces the same point,

9.5 Elliptic Curve Cryptography

In the following sections, we detail the ECC techniques by separating them into three subsections according to their functionalities.

9.5.1 Elliptic Curve Diffie–Hellman Key Exchange

Let us assume that A and B are two parties who desire to perform a  secure message exchange. The first requirement to complete this process is to generate keys that can be done utilizing the steps men-tioned below:

1. Both parties must agree upon a large prime number p and two elliptic curve parameters a and b of Equation (9.3), which defines the elliptic group of points EP(a, b).

2. Then, they have to pick a base point P on the elliptic curve EP(a, b) over a finite field ZP.

3. It is also necessary to choose a large integer number between 1 and the order of the abelian group EP(a, b), which would be considered a private key. Let us consider that A chooses m as its private key (PRA), and B chooses n as its private key (PRB).

4. A then generates a public key PUA = m × P.

5. B similarly generates a public key PUB = n × P.

6. After generating their relevant keys, they must exchange their public keys between each other. When A has the public key of B, it can now generate the secret key K = m × PUB. On the other hand, B can also generate the secret key K = n × PUA. If we keenly observe the two produced secret keys, we see that they are the same because

m × PUB = m × (n × P) = n × (m × P)= n × PUB

9.5.2 Key Exchange Example

Let us now assume that the base point P = (15, 3). A chooses its pri-vate key m = 7, and B chooses its pripri-vate key n = 5. Now,

PUA = m × P = 7 × (15, 3) = (15, 20) PUB = n × P = 5 × (15, 3) = (20, 19)

Then, secret key K can be found as

KA = m × PUB

= 7 × (20, 19)

= (20, 4)

KB = n × PUA

= 5 × (15, 20)

= (20, 4)

KA = KB = K

9.5.3 Elliptic Curve Encryption/Decryption

There are a lot of methods available in the literature that propose vari-ous techniques of elliptic curve encryption and decryption. In this chapter, one of the simplest techniques is chosen for those operations for a better understanding of the ECC algorithm. Let us consider that A wants to send a message to B that is also a point on the ellip-tic curve, M = (xM, yM). A must perform the following operations to encrypt the message:

C = M + m × PUB

Then, A sends the pair (m × P, C) to B, where P is the base point. After receiving the encrypted message, B utilizes its secret key to decrypt the message as follows:

C + (−n) × (m × P) = C −n × (m × P)

= M + m × PUB −n × (m × P)

= M + m × (n × P) −n × (m × P)

= M

9.5.4 Encryption/Decryption Example

Let us assume that A wants to transmit a message to B that is encoded on the elliptic point M = (19, 1). Consider the previous key exchange

example where A and B have selected their own private key and also have exchanged their public key between each other. Now, encryption of message M can be found as follows:

C = (19, 1) + 7 × (20, 19)

= (19, 1) + (20, 19)

= (16, 8)

m × P = 7 × (15, 3)

= (15, 20)

Then, A sends the ciphertext {(15, 20), (16, 8)}. When B receives this ciphertext, it decrypts the message as follows:

M = (16, 8) − 5 × (15, 20)

= (16, 8) − (20, 4)

= (16, 8) + (20, −4)

= (19, 1)

9.6 Implementation 1

#include <iostream>

#include <cmath>

#include <conio.h>

using namespace std;

void ec_points(int a, int b, int p) {

cout << "Points of Elliptic Curve" << endl;

cout << "— — — — — — — — — — — — — — — — — — — — — —

— — — — — — -" << endl;

for (int x = 0; x < p; x++) { for (int y = 0; y < p; y++) {

int k = y * y;

int m = (x * x * x) + a * x + b;

if (k% p = = m% p) {

cout << "(" << x << "," << y << ")" << endl;

} }

} }

static int EGCD(int a, int b, int& u, int &v)//

Extended GCD gives g = a*u + b*v {

u = 1;

v = 0;

int g = a;

int u1 = 0;

int v1 = 1;

int g1 = b;

while (g1 ! = 0) {

int q = g/g1;//Integer divide int t1 = u - q*u1;

int t2 = v - q*v1;

int t3 = g - q*g1;

u = u1; v = v1; g = g1;

u1 = t1; v1 = t2; g1 = t3;

}

return g;

}

//exitit 2

static int InvMod(int x, int n)//Solve linear congruence equation x * z = = 1 (mod n) for z {

//n = Abs(n);

x = x% n;//% is the remainder function, 0 < = x%

n < |n|

int u,v,g,z;

g = EGCD(x, n, u,v);

if (g ! = 1) {

/ /x and n have to be relative prime for there to exist an x^-1 mod n

z = 0;

} else {

z = u% n;

}

return z;

}

int NegMod (int a, int p) {

int b = a * -1;

int n = ceil((float)b/p);

return (n * p) - b;

}

void add_points (int xp, int yp, int xq, int yq, int

&xr, int &yr, int p) {

int s;

int n = yp - yq;

int d = xp - xq;

if (d < 0) { n * = -1;

d * = -1;

}

int x = InvMod(d, p);

if (n * x > 0) { s = (n * x)% p;

}

else {

s = NegMod(n * x, p);

}

int xr_ = (s * s - xp - xq);

if (xr_ < 0)

xr = NegMod (xr_, p);

else

xr = xr_% p;

int yr_ = (-yp + s * (xp - xr));

if (yr_ < 0)

yr = NegMod(yr_, p);

else

yr = yr_% p;

}

void add_double (int xp, int yp, int &xr, int &yr, int a, int p)

{

int s;

int n = 3 * xp * xp + a;

int d = 2 * yp;

if (d < 0) {

n * = -1;

d * = -1;

}

int x = InvMod(d, p);

if (n * x > 0) { s = (n * x)% p;

}

else {

s = NegMod(n * x, p);

}

int xr_ = (s * s - 2 * xp);

if (xr_ < 0)

xr = NegMod (xr_, p);

else

xr = xr_% p;

int yr_ = (-yp + s * (xp - xr));

if (yr_ < 0)

yr = NegMod(yr_, p);

else

yr = yr_% p;

}

void scalar_multiplication (int xp, int yp, int k, int a, int p, int &PUx, int &PUy)

{

if (k = = 2) {

add_double(xp, yp, PUx, PUy, a, p);

}

else if (k > 2) {

add_double(xp, yp, PUx, PUy, a, p);

for (int i = 0; i < k - 2; i++) { int xq = PUx;

int yq = PUy;

PUx = PUy = 0;

add_points(xp, yp, xq, yq, PUx, PUy, p);

} } else {

cout << "Wrong key" << endl;

} }

void key_generation (int Px, int Py, int k, int a, int p, int &PUx, int &PUy)

{

scalar_multiplication(Px, Py, k, a, p, PUx, PUy);

return;

}

void encryption (int Mx, int My, int k, int a, int p, int PUx, int PUy, int &Cx, int &Cy)

{

int xr, yr;

scalar_multiplication(PUx, PUy, k, a, p, xr, yr);

add_points(Mx, My, xr, yr, Cx, Cy, p);

}

void decryption (int Cx, int Cy, int k, int a, int p, int x1, int y1, int &Mx, int &My)

{

int xr, yr;

scalar_multiplication(x1, y1, k, a, p, xr, yr);

add_points(Cx, Cy, xr, -yr, Mx, My, p);

}

int main() {

int a, b, p;

cout << "put a prime number: ";

cin >> p;

bool check;

do {

check = false;

cout << "put a value for a: ";

cin >> a;

cout << "put a value for b: ";

cin >> b;

if (((4 * a * a * a + 27 * b * b)% p) = = 0) { cout << "Your values do not satisfied the condition" << endl;

cout << "Please put values again" << endl;

check = true;

}

} while (check);

cout << "— — — — — — — — — — — — — — — — — — — — — — —

— — — — — — " << endl;

ec_points(a, b, p);

int Px, Py, PUAx, PUAy, PUBx, PUBy, Mx, My, Cx, Cy, m, n;

cout << "— — — — — — — — — — — — — -" << endl;

cout << "Key " << endl;

cout << "— — — — — — — — — — — — — -" << endl;

cout << "Select a base point (x,y) from the curve: ";

cin >> Px >> Py;

cout << "Select a private key for Alice: ";

cin >> m;

key_generation(Px, Py, m, a, p, PUAx, PUAy);

cout << "Public key of Alice is (" << PUAx << "," <<

PUAy << ")" << endl;

cout << "Select a private key for Bob: ";

cin >> n;

key_generation(Px, Py, n, a, p, PUBx, PUBy);

cout << "Public key of Bob is (" << PUBx << "," <<

PUBy << ")" << endl;

cout << "— — — — — — — — — — — — — — — — — — — — — — —

— — — " << endl;

cout << "Encryption/Decryption" << endl;

cout << "— — — — — — — — — — — — — — — — — — — — — — —

— — — " << endl;

cout << "Select a Message point (x,y) from the curve (for encryption): ";

cin >> Mx >> My;

encryption(Mx, My, m, a, p, PUBx, PUBy, Cx, Cy);

cout << "Cipher is (" << Cx << "," << Cy << ")" << endl;

int x1, y1;

scalar_multiplication(Px, Py, m, a, p, x1, y1);

cout << "Alice send message pair(("<< x1 << "," << y1

<< "),(" << Cx << "," << Cy << "))" << endl;

cout << "||— — — — — — — — — — — — — — — — — — — — -||" << endl;

cout << "Bob receive the message and start decrypting"

<< endl;

decryption(Cx, Cy, n, a, p, x1, y1, Mx, My);

cout << "Decrypted message is (" << Mx << "," << My <<

")" << endl;

getch();

return 0;

}

9.7 Implementation 2

#include<cstdlib>

#include<iostream>

#include<vector>

#include <math.h>

//contains utility functions

#define PrimeNumber 23 using namespace std;

class utils {

public:

static float frand()//renerate random float number {

static float norm = 1.0f/(float)RAND_MAX;

return (float)rand()*norm;

}

static int irand(int min, int max)//renerate random integer number

{

return min+(int)(frand()*(float)(max-min));

}

//exhibit 1

static int EGCD(int a, int b, int& u, int

&v)//Extended GCD gives g = a*u + b*v {

u = 1;

v = 0;

int g = a;

int u1 = 0;

int v1 = 1;

int g1 = b;

while (g1 ! = 0) {

int q = g/g1;//Integer divide int t1 = u - q*u1;

int t2 = v - q*v1;

int t3 = g - q*g1;

u = u1; v = v1; g = g1;

u1 = t1; v1 = t2; g1 = t3;

}

return g;

}

//exitit 2

static int InvMod(int x, int n)//Solve linear congruence equation x * z = = 1 (mod n) for z

//x and n have to be relative prime for there to exist an x^-1 mod n

//Template parameter 'curveOrder' is the order of the finite field over which this curve is defined

template<int curveOrder>

class EllipticCurve;

//Template parameter 'curveOrder' is the order of the finite field over which this curve is defined

template<int curveOrder>

value = (i%curveOrder) +

2*curveOrder;//ensure that the value is in the correct range }

value% = curveOrder;

}

public:

//default constructor Element()

//copy constructor

Element(const Element<curveOrder>& rhs) {

value = rhs.value;

}

//access Element Value

int getValue() const {return value;}

//negate

Element<curveOrder> operator-() const {

return Element<curveOrder>(-value);

}

//setValue from integer

Element<curveOrder>& operator = (int i) {

setValue(i);

return *this;

}

//" = " operator overload

Element<curveOrder>& operator = (const Element<curveOrder>& rhs)

{

value = rhs.value;

return *this;

}

//"* = " operator overload

Element<curveOrder>& operator* = (const Element<curveOrder>& rhs)

{

value = (value*rhs.value)%curveOrder;

return *this;

}

//"* = " operator overload

friend bool operator = =(const Element<curveOrder>& lhs, const Element<curveOrder>& rhs)

{

return (lhs.value = = rhs.value);

}

//" = =" operator overload friend bool operator = =(const Element<curveOrder>& lhs, int rhs) {

return (lhs.value = = rhs);

}

//"! = " operator overload friend bool operator! = (const Element<curveOrder>& lhs, int rhs) {

return (lhs.value ! = rhs);

}

//"/" operator overload

friend Element<curveOrder> operator/

(const Element<curveOrder>& lhs, const Element<curveOrder>& rhs)

{

return Element<curveOrder>(lhs.

value * utils::InvMod(rhs.

value,curveOrder));

}

//"+" operator overload

friend Element<curveOrder>

operator+(const Element<curveOrder>& lhs, const Element<curveOrder>& rhs)

{

return Element<curveOrder>(lhs.

value + rhs.value);

}

//"+" operator overload

friend Element<curveOrder> operator+(int i, const Element<curveOrder>& rhs)

{

return Element<curveOrder>(rhs.

value+i);

}

//"+" operator overload

friend Element<curveOrder> operator+(const Element<curveOrder>& lhs, int i)

{

return Element<curveOrder>(lhs.

value+i);

}

//"-" operator overload

friend Element<curveOrder> operator-(const Element<curveOrder>& lhs, const

Element<curveOrder>& rhs) {

return Element<curveOrder>(lhs.

value - rhs.value);

}

//"-"(binary) operator overload

friend Element<curveOrder> operator*(int n, const Element<curveOrder>& rhs)

{

return Element<curveOrder>(n*rhs.

value);

}

//"*"(binary) operator overload

friend Element<curveOrder> operator*(const Element<curveOrder>& lhs, const

Element<curveOrder>& rhs) {

return Element<curveOrder>(lhs.

value * rhs.value);

}

//output stream handler template<int T>

friend ostream& operator<<(ostream& os, const Element<T>& opt)

{

return os << opt.value;

} };

//Template parameter 'curveOrder' is the order of the finite field over which this curve is defined

template<int curveOrder>

class Point {

//elliptic curve pointer in which this point will belong

EllipticCurve<curveOrder> *ellipticCurve;

/*

Given a curve 'ec' defined along some equation in a finite field (such as 'ec':

y^2 = x^3 + ax + b)

point multiplication is defined as the repeated addition of a point along that curve.

wiki link http://en.wikipedia.org/wiki/

Elliptic_curve_point_multiplication point multiply

*/

Point scalarMultiply(int k, const Point& a) {

Point acc = a;

Point res = Point(0,0,*ellipticCurve);

int i = 0, j = 0;

set; acc = 2^(i-j)*acc

res + = acc;

j = i; //last bit set }

b >> = 1;

++i;

cout << res.getX() << "\t" << res.

getY() << endl;

}

return res;

}

//doubling step for point multiplication void addDouble(int multiplier, Point& point) {

if (multiplier > 0) {

Point tempPoint = point;

for (int i = 0; i < multiplier; i++)

}

//adding two points on the curve

void addPoints(Element<curveOrder> x1,

Element<curveOrder> y1, Element<curveOrder> x2, Element<curveOrder> y2, Element<curveOrder> &

xR, Element<curveOrder> & yR) const {

//special cases involving the additive identity

Element<curveOrder> s;

if (x1 = = x2 && y1 = = y2)

} //point constructor with x and y value Point(int x, int y)

{

this->x = x;

this->y = y;

this->ellipticCurve = 0;

}

//point constructor with x value, y value and EllipticCurve pointer

Point(int x, int y, EllipticCurve<curveOrder> &

EllipticCurve)

//point constructor with constant x pointer, constant y pointer and EllipticCurve pointer Point(const Element<curveOrder>& x, const Element<curveOrder>& y,

//access x component as element

Element<curveOrder> getX() const {return x;}

//access y component as element

Element<curveOrder> getY() const {return y;}

//calculate the order of this point using brute-force additions

unsigned int Order(unsigned int maxPeriod = ~0) const

if (n > maxPeriod) break;

}

//" = " operator overload

Point& operator = (const Point& rhs) {

//" = =" operator overload

friend bool operator = =(const Point& lhs, const Point& rhs)

{

return (lhs.ellipticCurve = = rhs.

ellipticCurve) && (lhs.x = = rhs.x) &&

(lhs.y = = rhs.y);

}

//"! = " operator overload

friend bool operator! = (const Point& lhs, const Point& rhs)

{

return (lhs.ellipticCurve ! = rhs.

ellipticCurve) || (lhs.x ! = rhs.x) ||

(lhs.y ! = rhs.y);

}

//"+" operator overload

friend Point operator+(const Point& lhs, const Point& rhs)

{

Element<curveOrder> xR, yR;

lhs.addPoints(lhs.x,lhs.y,rhs.x,rhs.

y,xR,yR);

return Point(xR,yR,*lhs.ellipticCurve);

}

//"*" operator overload

friend Point operator*(int k, const Point& rhs) {

return Point(rhs).operator* = (k);

}

//"*" operator overload

Point& operator+ = (const Point& rhs) {

addPoints(x,y,rhs.x,rhs.y,x,y);

return *this;

}

//"* = " operator overload Point& operator* = (int k) {

return (*this = scalarMultiply(k,*this));

}

//ostream handler: print this point

friend ostream& operator <<(ostream& os, const Point& p)

{

return (os << "(" << p.x << ", " << p.y <<

")");

} };

//Template parameter 'curveOrder' is the order of the finite field over which this curve is defined

template<int curveOrder>

class EllipticCurve {

vector<Point<curveOrder> > pointTable; //table of points

Element<curveOrder> a; //paramter a of the EC equation

Element<curveOrder> b; //parameter b of the EC equation

bool tableFilled; //true if the table has been calculated

public:

//constructor with a and b as parameters (such as 'elliptic curve' : y^2 = x^3 + ax + b)

EllipticCurve(int a, int b) {

this->a = a;

this->b = b;

this->tableFilled = false;

}

//Calculate *all* the points (group elements) for this 'elliptic curve'

void CalculatePoints() {

//calculate points

for (int x = 0; x < curveOrder; x++) { for (int y = 0; y < curveOrder; y++) {

int k = y * y;

int m = (x * x * x) + a.getValue() * x + b.getValue();

if (k% curveOrder = = m% curveOrder)

pointTable.push_back(Point<curveOrder>(x,y,

*this));

}

}

tableFilled = true;//table fill successful }

//access the point vector like an array Point<curveOrder> operator[](int n) {

if (!tableFilled) {

CalculatePoints();

}

return pointTable[n];

}

//number of elements in this group

size_t Size() const {return pointTable.size();}

//the degree P of this EC

int Degree() const {return curveOrder;}

//the parameter a (as an element of Fp) Element<curveOrder> getA() const {return a;}

//the parameter b (as an element of Fp) Element<curveOrder> getB() const {return b;}

//ostream handler: print this curve in human readable form

template<int cO>

friend ostream& operator <<(ostream& os, const EllipticCurve<curveOrder>& EllipticCurve)

{

//y^2 mod P = x^3 + ax + b mod P

os << "y^2 mod " << cO << " = (x^3 + ";

if (EllipticCurve.a ! = 0) {

os << EllipticCurve.a.getValue() <<

"x + ";

}

if (EllipticCurve.b ! = 0) {

os << EllipticCurve.b.getValue() ; }

os << noshowpos << ") mod " << cO;

return os;

}

//print all the elements of the curve

ostream& PrintTable(ostream &os, int columns = 4) {

if (tableFilled) {

int col = 0;

vector<Point<PrimeNumber>

>::iterator iter = pointTable.

begin();

for (; iter! = pointTable.end();

++iter) {

os << "(" <<

(*iter).x.getValue() << ", "

<< (*iter).y.getValue()

else {

os << "EllipticCurve, F_" <<

PrimeNumber;

}

return os;

} };

int main(int argc, char *argv[]) {

cout << "Put the value for a (an integer number between 0 to " << PrimeNumber - 1 << ": ";

cin >> A;

cout << "Put the value for b (an integer number between 0 to " << PrimeNumber - 1 << ": ";

cin >> B;

cout << endl;

if (((4 * A * A * A) + (27 * B * B))%

PrimeNumber = = 0) { flag = true;

cout << "WARNING: Enterned values failed to pass the singularity test" << endl;

cout << "Put the values again " << endl <<

endl;

}

} while (flag);

EllipticCurve<PrimeNumber> curveObject(A,B);

cout << "Elliptic Curve cryptography example\n—

— — — — — — — — — — — — — — — — — \n\n";

//print some information about the curve

//cout << "The curve object: " << curveObject <<

"\n";

curveObject.CalculatePoints();//

cout << "\npoints on the curve object\n";

curveObject.PrintTable(cout,4);

cout << "\n = = = = = = = = = = = = = = = = = =

= = = = = = = = = = = = = = = = = = = = = = = =

= = = = = \n";

//Elliptic curve message encryption scheme