This library provides a way to easily handle arbitrary large integers.

This library provides the following operations :

  • addition, substraction, multiplication, division and modulo
  • bits operators (AND, OR, XOR, left and right shifts)
  • boolean operators
  • modular exponentiation (using montgomery algorithm)
  • modular inverse

Example

In this example, we use a 1024 bits long RSA key to encrypt and decrypt a message. We first encrypt the value 0x41 (65 in decimal) and then decrypt it. At the end, m should be equal to 0x41. The encryption is fast (0, 4 second) while the decryption is really slow. This code will take between 30 seconds and 2 minutes to execute depending on the compiler and optimization flags.

main.cpp

#include "mbed.h"
#include "BigInt.h"
#include <stdlib.h>
#include <stdio.h>

uint8_t modbits[] = {
0xd9, 0x4d, 0x88, 0x9e, 0x88, 0x85, 0x3d, 0xd8, 0x97, 0x69, 0xa1, 0x80, 0x15, 0xa0, 0xa2, 0xe6,
0xbf, 0x82, 0xbf, 0x35, 0x6f, 0xe1, 0x4f, 0x25, 0x1f, 0xb4, 0xf5, 0xe2, 0xdf, 0x0d, 0x9f, 0x9a,
0x94, 0xa6, 0x8a, 0x30, 0xc4, 0x28, 0xb3, 0x9e, 0x33, 0x62, 0xfb, 0x37, 0x79, 0xa4, 0x97, 0xec,
0xea, 0xea, 0x37, 0x10, 0x0f, 0x26, 0x4d, 0x7f, 0xb9, 0xfb, 0x1a, 0x97, 0xfb, 0xf6, 0x21, 0x13,
0x3d, 0xe5, 0x5f, 0xdc, 0xb9, 0xb1, 0xad, 0x0d, 0x7a, 0x31, 0xb3, 0x79, 0x21, 0x6d, 0x79, 0x25,
0x2f, 0x5c, 0x52, 0x7b, 0x9b, 0xc6, 0x3d, 0x83, 0xd4, 0xec, 0xf4, 0xd1, 0xd4, 0x5c, 0xbf, 0x84,
0x3e, 0x84, 0x74, 0xba, 0xbc, 0x65, 0x5e, 0x9b, 0xb6, 0x79, 0x9c, 0xba, 0x77, 0xa4, 0x7e, 0xaf,
0xa8, 0x38, 0x29, 0x64, 0x74, 0xaf, 0xc2, 0x4b, 0xeb, 0x9c, 0x82, 0x5b, 0x73, 0xeb, 0xf5, 0x49
};

uint8_t dbits[] = {
0x04, 0x7b, 0x9c, 0xfd, 0xe8, 0x43, 0x17, 0x6b, 0x88, 0x74, 0x1d, 0x68, 0xcf, 0x09, 0x69, 0x52,
0xe9, 0x50, 0x81, 0x31, 0x51, 0x05, 0x8c, 0xe4, 0x6f, 0x2b, 0x04, 0x87, 0x91, 0xa2, 0x6e, 0x50,
0x7a, 0x10, 0x95, 0x79, 0x3c, 0x12, 0xba, 0xe1, 0xe0, 0x9d, 0x82, 0x21, 0x3a, 0xd9, 0x32, 0x69,
0x28, 0xcf, 0x7c, 0x23, 0x50, 0xac, 0xb1, 0x9c, 0x98, 0xf1, 0x9d, 0x32, 0xd5, 0x77, 0xd6, 0x66,
0xcd, 0x7b, 0xb8, 0xb2, 0xb5, 0xba, 0x62, 0x9d, 0x25, 0xcc, 0xf7, 0x2a, 0x5c, 0xeb, 0x8a, 0x8d,
0xa0, 0x38, 0x90, 0x6c, 0x84, 0xdc, 0xdb, 0x1f, 0xe6, 0x77, 0xdf, 0xfb, 0x2c, 0x02, 0x9f, 0xd8,
0x92, 0x63, 0x18, 0xee, 0xde, 0x1b, 0x58, 0x27, 0x2a, 0xf2, 0x2b, 0xda, 0x5c, 0x52, 0x32, 0xbe,
0x06, 0x68, 0x39, 0x39, 0x8e, 0x42, 0xf5, 0x35, 0x2d, 0xf5, 0x88, 0x48, 0xad, 0xad, 0x11, 0xa1
};

int main() 
{
    BigInt e = 65537, mod, d;
    mod.importData(modbits, sizeof(modbits));
    d.importData(dbits, sizeof(dbits));

    BigInt c = modPow(0x41,e,mod);
    c.print();
    BigInt m = modPow(c,d,mod);
    m.print();
    printf("done\n");
    
    return 0;
}

Files at this revision

API Documentation at this revision

Comitter:
feb11
Date:
Wed Mar 05 19:36:22 2014 +0000
Parent:
9:3c191fa04f6e
Child:
11:2f16a220ebbb
Commit message:
division implemented

Changed in this revision

BigInt.cpp Show annotated file Show diff for this revision Revisions of this file
BigInt.h Show annotated file Show diff for this revision Revisions of this file
--- a/BigInt.cpp	Sat Oct 05 15:26:03 2013 +0000
+++ b/BigInt.cpp	Wed Mar 05 19:36:22 2014 +0000
@@ -5,17 +5,14 @@
 #include <iostream>
 #include <climits>
 #include <cassert>
-
-static uint32_t max(const uint32_t a, const uint32_t b)
-{
-    return a < b ? b : a;
-}
+#include <algorithm>
 
 static uint32_t num(const uint32_t a)
 {
     return a/4 + (a%4 ? 1:0); 
 }
-    
+
+
 BigInt::BigInt():
 size(0),
 bits(0)
@@ -48,12 +45,10 @@
 
 BigInt::~BigInt()
 {
-    if(bits)
+    if(size)
     {
-        printf("deleting %d bytes\n", size);
         delete[] bits;
     }
-    bits = 0;
 }
 
 BigInt& BigInt::operator=(const BigInt& a)
@@ -105,7 +100,7 @@
         if(i < bl)
             tmpB = b.bits[i];
         result.bits[i] = tmpA + tmpB + carry;
-        carry = result.bits[i] < max(tmpA, tmpB);
+        carry = result.bits[i] < std::max(tmpA, tmpB);
     }
     if(carry)
     {
@@ -262,6 +257,40 @@
     return (*this = (*this) * b);
 }
 
+
+BigInt operator/(const BigInt &a, const BigInt& b)
+{
+    assert(a.isValid() && b.isValid() && b != 0);
+
+    if(b == 1)
+        return a;
+    if(a < b)
+        return 0;
+    if(a == b)
+        return 1;
+    BigInt u = a, v = b;   
+    int m = u.numBits() - v.numBits();
+    printf("m=%d\n", m);
+    BigInt q = 0;
+    BigInt tmp = 1;
+    tmp <<= m;
+    for(int j = m; j >= 0; --j)
+    {
+        if(v*tmp <= u)
+        {
+            u -= v*tmp;
+            q += tmp;    
+        }   
+        tmp >>= 1;
+    }
+    return q;    
+}
+
+BigInt& BigInt::operator/=(const BigInt &b)
+{
+    return (*this = (*this) / b);
+} 
+
 BigInt operator>>(const BigInt &a, const uint32_t m)
 {
     assert(a.isValid());
@@ -284,7 +313,8 @@
             result.bits[i] = (a.bits[m/32+i] >> s);
     }
     
-    
+    result.trim();
+        
     return result;
 }
 
@@ -331,14 +361,17 @@
 
 BigInt operator%(const BigInt &a, const BigInt &b)
 {
-    assert(a.isValid() && b.isValid());
+    assert(a.isValid() && b.isValid() && b > 0);
 
-    BigInt result = a;
+    BigInt i = 1, result;
+        
+    while(a >= b*i && a < b*(i+1))
+    {
+        ++i;
+    }
+    --i;
+    result = a - b*i;
     
-    
-    while(result > b)
-        result -= b;
-
     result.trim();
     
     return result;
@@ -450,8 +483,8 @@
 
     uint32_t na = num(a.size);
     uint32_t nb = num(b.size);
-    uint32_t l = max(na,nb);
-    result.size = max(a.size, b.size);
+    uint32_t l = std::max(na,nb);
+    result.size = std::max(a.size, b.size);
     result.bits = new uint32_t[l];
     memset(result.bits, 0, l);
     
@@ -482,8 +515,8 @@
 
     uint32_t na = num(a.size);
     uint32_t nb = num(b.size);
-    uint32_t l = max(na,nb);
-    result.size = max(a.size, b.size);
+    uint32_t l = std::max(na,nb);
+    result.size = std::max(a.size, b.size);
     result.bits = new uint32_t[l];
     memset(result.bits, 0, l);
     
@@ -507,22 +540,62 @@
     return (*this = *this ^ a);
 }
 
+BigInt montgomeryStep2(const BigInt &a, const BigInt &m, uint32_t r)
+{
+    BigInt result = a;
+    uint32_t tmpR = r;
+    while(r > 0)
+    {
+        if(r == 1)
+            result += (2 << tmpR);   
+        
+        if(result.bits[0] & 0x01)
+            result += m;
+        --r;
+    }
+    return result;
+}
+
+BigInt montgomeryStep(const BigInt &a, const BigInt &b, const BigInt &m, uint32_t r)
+{
+    BigInt result = 0;
+    BigInt tmp = a;
+    while(r > 0)
+    {
+        if(tmp.bits[0] & 0x01)
+            result += b;   
+        
+        if(result.bits[0] & 0x01)
+            result += m;
+      
+        --r;
+        result >>= 1;    
+        tmp >>= 1;
+    }
+    return result;
+}
+  
+// Implementation using Montgomery algorithm
 BigInt modPow(const BigInt &a, const BigInt &expn, const BigInt &modulus)
 {
     assert(a.isValid() && expn.isValid() && modulus.isValid());
     
-    BigInt result = 1;
+    // precompute R and R^2
+    uint32_t r = 8*modulus.size;
+
+    // convert a in montgomery world
+    BigInt montA = montgomeryStep2(a,modulus,r);
+    montA.print();
+    BigInt tmp = montA;
     BigInt tmpE = expn;
-    BigInt base = a;
-    while(tmpE > 0)
+    while(tmpE > 1)
     {
-        if(tmpE % 2 == 1)
-           result = (result * base) % modulus;
-        tmpE >>= 1;
-        base = (base * base) % modulus;
+        tmp = montgomeryStep(montA, tmp, modulus, r);
+        --tmpE;
     }
     
-    return result;
+    // convert a to normal world
+    return montgomeryStep(tmp, 1, modulus, r);
 }
 
 bool BigInt::isValid() const
@@ -547,8 +620,29 @@
     uint32_t newSize = size;
     while(tmp[newSize-1] == 0 && newSize > 0)
         newSize--;
+    if(newSize == 0)
+        newSize = 1;
     if(num(newSize) < num(size))
+    {
         bits = (uint32_t*)realloc(bits, sizeof(uint32_t)*num(newSize)); 
+    }
     size = newSize; 
 }
 
+uint32_t BigInt::numBits()
+{
+    assert(isValid());
+    
+    uint32_t n = (size-1)*8;
+    uint8_t a = bits[size/4] >> ((size-1)%4)*8;
+    uint8_t tmp = 0x80;
+    uint8_t tmp2 = 8;
+    while(!(a & tmp)) 
+    {
+        tmp >>= 1;
+        --tmp2;
+    }
+    n += tmp2;
+
+    return n;
+}
--- a/BigInt.h	Sat Oct 05 15:26:03 2013 +0000
+++ b/BigInt.h	Wed Mar 05 19:36:22 2014 +0000
@@ -28,7 +28,10 @@
         
         friend BigInt operator*(const BigInt &a, const BigInt& b);
         BigInt& operator*=(const BigInt &b);
-        
+
+        friend BigInt operator/(const BigInt &a, const BigInt& b);
+        BigInt& operator/=(const BigInt &b);
+                
         friend BigInt operator>>(const BigInt &a, const uint32_t m);
         BigInt& operator>>=(const uint32_t m);
         friend BigInt operator<<(const BigInt &a, const uint32_t m);
@@ -56,17 +59,21 @@
         
         // modular exponentiation
         friend BigInt modPow(const BigInt &a, const BigInt &expn, const BigInt &modulus);
-        
+
         bool isValid() const;
         
         // debug
         void print();
-        
+
     private :
     
-        void trim();
-    
-        uint32_t size;  // number of bytes
+        void trim();  
+        uint32_t numBits();    
+     
+        friend BigInt montgomeryStep(const BigInt &a, const BigInt &b, const BigInt &m, uint32_t r);
+        friend BigInt montgomeryStep2(const BigInt &a, const BigInt &m, uint32_t r);
+
+        uint32_t size;  // smaller number of bytes needed to represent integer
         uint32_t *bits;
 };