
cifrado con ecc
main.cpp
- Committer:
- saranieves92
- Date:
- 2015-02-20
- Revision:
- 0:71704ec698ca
File content as of revision 0:71704ec698ca:
#include <cstdlib> #include <iostream> #include <vector> using namespace std; #include <math.h> #include "FiniteFieldElement.hpp" namespace Cryptography { /* Elliptic Curve over a finite field of order P: y^2 mod P = x^3 + ax + b mod P NOTE: this implementation is simple and uses normal machine integers for its calculations. No special "big integer" manipulation is supported so anything _big_ won't work. However, it is a complete finite field EC implementation in that it can be used to learn and understand the behaviour of these curves and in particular to experiment with them for their use in cryptography Template parameter P is the order of the finite field Fp over which this curve is defined */ template<int P> class EllipticCurve { public: // this curve is defined over the finite field (Galois field) Fp, this is the // typedef of elements in it typedef FiniteFieldElement<P> ffe_t; /* A point, or group element, on the EC, consisting of two elements of the field FP Points can only created by the EC instance itself as they have to be elements of the group generated by the EC */ class Point { friend class EllipticCurve<P>; typedef FiniteFieldElement<P> ffe_t; ffe_t x_; ffe_t y_; EllipticCurve *ec_; // core of the doubling multiplier algorithm (see below) // multiplies acc by m as a series of "2*acc's" void addDouble(int m, Point& acc) { if ( m > 0 ) { Point r = acc; for ( int n=0; n < m; ++n ) { r += r; // doubling step } acc = r; } } // doubling multiplier algorithm // multiplies a by k by expanding in multiplies by 2 // a is also an accumulator that stores the intermediate results // between the "1s" of the binary form of the input scalar k Point scalarMultiply(int k, const Point& a) { Point acc = a; Point res = Point(0,0,*ec_); int i = 0, j = 0; int b = k; while( b ) { if ( b & 1 ) { // bit is set; acc = 2^(i-j)*acc addDouble(i-j,acc); res += acc; j = i; // last bit set } b >>= 1; ++i; } return res; } // adding two points on the curve void add(ffe_t x1, ffe_t y1, ffe_t x2, ffe_t y2, ffe_t & xR, ffe_t & yR) const { // special cases involving the additive identity if ( x1 == 0 && y1 == 0 ) { xR = x2; yR = y2; return; } if ( x2 == 0 && y2 == 0 ) { xR = x1; yR = y1; return; } if ( y1 == -y2 ) { xR = yR = 0; return; } // the additions ffe_t s; if ( x1 == x2 && y1 == y2 ) { //2P s = (3*(x1.i()*x1.i()) + ec_->a()) / (2*y1); xR = ((s*s) - 2*x1); } else { //P+Q s = (y1 - y2) / (x1 - x2); xR = ((s*s) - x1 - x2); } if ( s != 0 ) { yR = (-y1 + s*(x1 - xR)); } else { xR = yR = 0; } } Point(int x, int y) : x_(x), y_(y), ec_(0) {} Point(int x, int y, EllipticCurve<P> & EllipticCurve) : x_(x), y_(y), ec_(&EllipticCurve) {} Point(const ffe_t& x, const ffe_t& y, EllipticCurve<P> & EllipticCurve) : x_(x), y_(y), ec_(&EllipticCurve) {} public: static Point ONE; // copy ctor Point(const Point& rhs) { x_ = rhs.x_; y_ = rhs.y_; ec_ = rhs.ec_; } // assignment Point& operator=(const Point& rhs) { x_ = rhs.x_; y_ = rhs.y_; ec_ = rhs.ec_; return *this; } // access x component as element of Fp ffe_t x() const { return x_; } // access y component as element of Fp ffe_t y() const { return y_; } // calculate the order of this point by brute-force additions // WARNING: this can be VERY slow if the period is long and might not even converge // so maxPeriod should probably be set to something sensible... unsigned int Order(unsigned int maxPeriod = ~0) const { Point r = *this; unsigned int n = 0; while( r.x_ != 0 && r.y_ != 0 ) { ++n; r += *this; if ( n > maxPeriod ) break; } return n; } // negate Point operator-() { return Point(x_,-y_); } // == friend bool operator==(const Point& lhs, const Point& rhs) { return (lhs.ec_ == rhs.ec_) && (lhs.x_ == rhs.x_) && (lhs.y_ == rhs.y_); } // != friend bool operator!=(const Point& lhs, const Point& rhs) { return (lhs.ec_ != rhs.ec_) || (lhs.x_ != rhs.x_) || (lhs.y_ != rhs.y_); } // a + b friend Point operator+(const Point& lhs, const Point& rhs) { ffe_t xR, yR; lhs.add(lhs.x_,lhs.y_,rhs.x_,rhs.y_,xR,yR); return Point(xR,yR,*lhs.ec_); } // a * int friend Point operator*(int k, const Point& rhs) { return Point(rhs).operator*=(k); } // += Point& operator+=(const Point& rhs) { add(x_,y_,rhs.x_,rhs.y_,x_,y_); return *this; } // a *= int 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_ << ")"); } }; // ==================================================== EllipticCurve impl typedef EllipticCurve<P> this_t; typedef class EllipticCurve<P>::Point point_t; // ctor // Initialize EC as y^2 = x^3 + ax + b EllipticCurve(int a, int b) : a_(a), b_(b), m_table_(), table_filled_(false) { } // Calculate *all* the points (group elements) for this EC //NOTE: if the order of this curve is large this could take some time... void CalculatePoints() { int x_val[P]; int y_val[P]; for ( int n = 0; n < P; ++n ) { int nsq = n*n; x_val[n] = ((n*nsq) + a_.i() * n + b_.i()) % P; y_val[n] = nsq % P; } for ( int n = 0; n < P; ++n ) { for ( int m = 0; m < P; ++m ) { if ( x_val[n] == y_val[m] ) { m_table_.push_back(Point(n,m,*this)); } } } table_filled_ = true; } // get a point (group element) on the curve Point operator[](int n) { if ( !table_filled_ ) { CalculatePoints(); } return m_table_[n]; } // number of elements in this group size_t Size() const { return m_table_.size(); } // the degree P of this EC int Degree() const { return P; } // the parameter a (as an element of Fp) FiniteFieldElement<P> a() const { return a_; } // the paramter b (as an element of Fp) FiniteFieldElement<P> b() const { return b_; } // ostream handler: print this curve in human readable form template<int T> friend ostream& operator <<(ostream& os, const EllipticCurve<T>& EllipticCurve); // print all the elements of the EC group ostream& PrintTable(ostream &os, int columns=4); private: typedef std::vector<Point> m_table_t; m_table_t m_table_; // table of points FiniteFieldElement<P> a_; // paramter a of the EC equation FiniteFieldElement<P> b_; // parameter b of the EC equation bool table_filled_; // true if the table has been calculated }; template<int T> typename EllipticCurve<T>::Point EllipticCurve<T>::Point::ONE(0,0); template<int T> ostream& operator <<(ostream& os, const EllipticCurve<T>& EllipticCurve) { os << "y^2 mod " << T << " = (x^3" << showpos; if ( EllipticCurve.a_ != 0 ) { os << EllipticCurve.a_ << "x"; } if ( EllipticCurve.b_.i() != 0 ) { os << EllipticCurve.b_; } os << noshowpos << ") mod " << T; return os; } template<int P> ostream& EllipticCurve<P>::PrintTable(ostream &os, int columns) { if ( table_filled_ ) { int col = 0; typename EllipticCurve<P>::m_table_t::iterator iter = m_table_.begin(); for ( ; iter!=m_table_.end(); ++iter ) { os << "(" << (*iter).x_.i() << ", " << (*iter).y_.i() << ") "; if ( ++col > columns ) { os << "\n"; col = 0; } } } else { os << "EllipticCurve, F_" << P; } return os; } } namespace utils { float frand() { static float norm = 1.0f / (float)RAND_MAX; return (float)rand()*norm; } int irand(int min, int max) { return min+(int)(frand()*(float)(max-min)); } } using namespace Cryptography; using namespace utils; int main(int argc, char *argv[]) { typedef EllipticCurve<263> ec_t; ec_t myEllipticCurve(1,1); /* cout << "A little Elliptic Curve cryptography example\nby Jarl Ostensen, 2007\n\n"; // print out a little info and test some properties cout << "The elliptic curve: " << myEllipticCurve << "\n"; // calulate all the points for this curve. NOTE: in the real world this would not // be a very sensible thing to do. If the period is very large this is big and slow myEllipticCurve.CalculatePoints(); cout << "\nPoints on the curve (i.e. the group elements):\n"; myEllipticCurve.PrintTable(cout,5); cout << "\n\n"; ec_t::Point P = myEllipticCurve[2]; cout << "some point P = " << P << ", 2P = " << (P+P) << "\n"; ec_t::Point Q = myEllipticCurve[3]; cout << "some point Q = " << Q << ", P+Q = " << (P+Q) << "\n"; ec_t::Point R = P; R += Q; cout << "P += Q = " << R << "\n"; R = P; R += R; cout << "P += P = 2P = " << R << "\n"; cout << "\nEC message encryption example\n===============================================\n\n"; */ // Menes-Vanstone EC message encryption scheme // Public: the base point on the curve (i.e. base group element) used to generate keys // this is a REALLY slow way of picking a base point... ec_t::Point G = myEllipticCurve[0]; while( (G.y() == 0 || G.x() == 0) || (G.Order()<2) ) { int n = (int)(frand()*myEllipticCurve.Size()); G = myEllipticCurve[n]; } cout << "G = " << G << ", order(G) is " << G.Order() << "\n"; // Alice int a = irand(1,myEllipticCurve.Degree()-1); ec_t::Point Pa = a*G; // public key cout << "Alice' public key Pa = " << a << "*" << G << " = " << Pa << endl; // Bob int b = irand(1,myEllipticCurve.Degree()-1);; ec_t::Point Pb = b*G; // public key cout << "Bob's public key Pb = " << b << "*" << G << " = " << Pb << endl; // Jane, the eavesdropper int j = irand(1,myEllipticCurve.Degree()-1);; ec_t::Point Pj = j*G; cout << "Jane's public key Pj = " << j << "*" << G << " = " << Pj << endl; cout << "\n\n"; // Alice encrypts her message to send to Bob // NOTE: the message first has to be split up into chunks that are in the Galois field F_p that is // the domain of the EC // With P quite small (like in these examples) this is a serious limitation, but in the real world // P could be very sizeable indeed, thus providing enough bits for good chunks int m1 = 19; int m2 = 72; cout << "Plain text message from Alice to Bob: (" << m1 << ", " << m2 << ")\n"; // encrypt using Bob`s key ec_t::Point Pk = a*Pb; ec_t::ffe_t c1( m1*Pk.x() ); ec_t::ffe_t c2( m2*Pk.y() ); // encrypted message is: Pa,c1,c2 cout << "Encrypted message from Alice to Bob = {Pa,c1,c2} = {" << Pa << ", " << c1 << ", " << c2 << "}\n\n"; // Bob now decrypts Alice`s message, using her public key and his session integer "b" which was also used to generate his public key Pk = b*Pa; ec_t::ffe_t m1d = c1/Pk.x(); ec_t::ffe_t m2d = c2/Pk.y(); cout << "\tBob's decrypted message from Alice = (" << m1d << ", " << m2d << ")" << endl; // Jane intercepts the message and tries to decrypt it using her key Pk = j*Pa; m1d = c1/Pk.x(); m2d = c2/Pk.y(); cout << "\nJane's decrypted message from Alice = (" << m1d << ", " << m2d << ")" << endl; cout << endl; system("PAUSE"); return EXIT_SUCCESS; }