cifrado con ecc

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
saranieves92
Date:
Fri Feb 20 18:18:19 2015 +0000
Commit message:
cifrado que va en linux

Changed in this revision

FiniteFieldElement.hpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FiniteFieldElement.hpp	Fri Feb 20 18:18:19 2015 +0000
@@ -0,0 +1,175 @@
+
+
+namespace Cryptography
+{
+       // helper functions
+        namespace   detail
+        {            
+            //From Knuth; Extended GCD gives g = a*u + b*v
+            int EGCD(int a, int b, int& u, int &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;
+            }
+            
+            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;
+            }
+        }
+        
+        /*
+            An element in a Galois field FP
+            Adapted for the specific behaviour of the "mod" function where (-n) mod m returns a negative number
+            Allows basic arithmetic operations between elements:
+                +,-,/,scalar multiply                
+                
+            The template argument P is the order of the field
+        */
+        template<int P>
+        class   FiniteFieldElement
+        {
+            int     i_;
+            
+            void    assign(int i)
+            {
+                i_ = i;
+                if ( i<0 )
+                {                    
+                    // ensure (-i) mod p correct behaviour
+                    // the (i%P) term is to ensure that i is in the correct range before normalizing
+                    i_ = (i%P) + 2*P;
+                }
+
+                i_ %= P;
+            }
+            
+            public:
+                // ctor
+                FiniteFieldElement()
+                 : i_(0)
+                {}
+                // ctor
+                explicit FiniteFieldElement(int i)
+                {
+                    assign(i);
+                }
+                // copy ctor
+                FiniteFieldElement(const FiniteFieldElement<P>& rhs) 
+                 : i_(rhs.i_)               
+                {
+                }
+                
+                // access "raw" integer
+                int i() const { return i_; }                
+                // negate
+                FiniteFieldElement  operator-() const
+                {
+                    return FiniteFieldElement(-i_);
+                }                                
+                // assign from integer
+                FiniteFieldElement& operator=(int i)
+                {
+                    assign(i);
+                    return *this;
+                }
+                // assign from field element
+                FiniteFieldElement<P>& operator=(const FiniteFieldElement<P>& rhs)
+                {
+                    i_ = rhs.i_;
+                    return *this;
+                }
+                // *=
+                FiniteFieldElement<P>& operator*=(const FiniteFieldElement<P>& rhs)
+                {
+                    i_ = (i_*rhs.i_) % P;
+                    return *this;           
+                }
+                // ==
+                friend bool    operator==(const FiniteFieldElement<P>& lhs, const FiniteFieldElement<P>& rhs)
+                {
+                    return (lhs.i_ == rhs.i_);
+                }
+                // == int
+                friend bool    operator==(const FiniteFieldElement<P>& lhs, int rhs)
+                {
+                    return (lhs.i_ == rhs);
+                }
+                // !=
+                friend bool    operator!=(const FiniteFieldElement<P>& lhs, int rhs)
+                {
+                    return (lhs.i_ != rhs);
+                }                
+                // a / b
+                friend FiniteFieldElement<P> operator/(const FiniteFieldElement<P>& lhs, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( lhs.i_ * detail::InvMod(rhs.i_,P));
+                }
+                // a + b
+                friend FiniteFieldElement<P> operator+(const FiniteFieldElement<P>& lhs, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( lhs.i_ + rhs.i_);
+                }
+                // a - b
+                friend FiniteFieldElement<P> operator-(const FiniteFieldElement<P>& lhs, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( lhs.i_ - rhs.i_);
+                }
+                // a + int
+                friend FiniteFieldElement<P> operator+(const FiniteFieldElement<P>& lhs, int i)
+                {
+                    return FiniteFieldElement<P>( lhs.i_+i);
+                }
+                // int + a
+                friend FiniteFieldElement<P> operator+(int i, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( rhs.i_+i);
+                }
+                // int * a
+                friend FiniteFieldElement<P> operator*(int n, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( n*rhs.i_);
+                }                
+                // a * b
+                friend FiniteFieldElement<P> operator*(const FiniteFieldElement<P>& lhs, const FiniteFieldElement<P>& rhs)
+                {
+                    return FiniteFieldElement<P>( lhs.i_ * rhs.i_);
+                }
+                // ostream handler
+                template<int T>
+                friend  ostream&    operator<<(ostream& os, const FiniteFieldElement<T>& g)
+                {
+                    return os << g.i_;
+                }
+        };
+}
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Feb 20 18:18:19 2015 +0000
@@ -0,0 +1,464 @@
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Feb 20 18:18:19 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e188a91d3eaa
\ No newline at end of file