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; }
Revision 9:3c191fa04f6e, committed 2013-10-05
- Comitter:
- feb11
- Date:
- Sat Oct 05 15:26:03 2013 +0000
- Parent:
- 8:2a361f1b41da
- Child:
- 10:116e201f7d89
- Commit message:
- refactored code + implemented modular exponentiation
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 Fri Oct 04 15:16:06 2013 +0000 +++ b/BigInt.cpp Sat Oct 05 15:26:03 2013 +0000 @@ -4,7 +4,7 @@ #include <stdlib.h> #include <iostream> #include <climits> - +#include <cassert> static uint32_t max(const uint32_t a, const uint32_t b) { @@ -49,7 +49,10 @@ BigInt::~BigInt() { if(bits) + { + printf("deleting %d bytes\n", size); delete[] bits; + } bits = 0; } @@ -81,8 +84,10 @@ BigInt operator+(const BigInt &a, const BigInt& b) { + assert(a.isValid() && b.isValid()); + BigInt result; - + result.size = a.size > b.size ? a.size : b.size; size_t l = result.size/4; if(result.size % 4 != 0) @@ -141,6 +146,8 @@ // No negative number allowed BigInt operator-(const BigInt &a, const BigInt& b) { + assert(a.isValid() && b.isValid()); + BigInt result; if(b >= a) @@ -185,15 +192,7 @@ } } - // trim result - uint8_t *tmp = (uint8_t*)result.bits; - uint32_t newSize = result.size; - while(tmp[newSize-1] == 0 && newSize > 0) - newSize--; - result.size = newSize; - uint32_t tmpL = num(result.size); - if(tmpL < l) - result.bits = (uint32_t*)realloc(result.bits, sizeof(uint32_t)*tmpL); + result.trim(); return result; } @@ -218,6 +217,8 @@ BigInt operator*(const BigInt &a, const BigInt& b) { + assert(a.isValid() && b.isValid()); + BigInt result; // if a == 0 or b == 0 then result = 0 @@ -251,14 +252,7 @@ carry = tmp >> 32; } - // trim result - uint8_t *tmp = (uint8_t*)result.bits; - uint32_t newSize = result.size; - while(tmp[newSize-1] == 0 && newSize > 0) - newSize--; - if(num(newSize) < num(result.size)) - result.bits = (uint32_t*)realloc(result.bits, sizeof(uint32_t)*num(newSize)); - result.size = newSize; + result.trim(); return result; } @@ -270,7 +264,10 @@ BigInt operator>>(const BigInt &a, const uint32_t m) { + assert(a.isValid()); + BigInt result; + if(m == 0) return result = a; if(m/8 >= a.size) @@ -298,8 +295,10 @@ BigInt operator<<(const BigInt &a, const uint32_t m) { + assert(a.isValid()); + BigInt result; - + if(m == 0) return result = a; @@ -332,18 +331,15 @@ BigInt operator%(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + BigInt result = a; + + while(result > b) result -= b; - // trim result - uint8_t *tmp = (uint8_t*)result.bits; - uint32_t newSize = result.size; - while(tmp[newSize-1] == 0 && newSize > 0) - newSize--; - if(num(newSize) < num(result.size)) - result.bits = (uint32_t*)realloc(result.bits, sizeof(uint32_t)*num(newSize)); - result.size = newSize; + result.trim(); return result; } @@ -355,6 +351,8 @@ bool operator==(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + if(a.size != b.size) return false; @@ -372,6 +370,8 @@ bool operator<(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + if(a.size < b.size) return true; if(a.size > b.size) @@ -385,11 +385,13 @@ bool operator<=(const BigInt &a, const BigInt &b) { - return (a < b) || (a == b); + return !(a > b); } bool operator>(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + if(a.size > b.size) return true; if(a.size < b.size) @@ -403,11 +405,13 @@ bool operator>=(const BigInt &a, const BigInt &b) { - return (a > b) || (a == b); + return !(a < b); } bool operator!(const BigInt &a) { + assert(a.isValid()); + if(a.size != 1) return false; return a.bits[0] == 0; @@ -416,6 +420,8 @@ BigInt operator&(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + BigInt result; result.size = a.size < b.size ? a.size : b.size; @@ -426,15 +432,7 @@ for(uint32_t i = 0; i < l; ++i) result.bits[i] = a.bits[i] & b.bits[i]; - - // trim result - uint8_t *tmp = (uint8_t*)result.bits; - uint32_t newSize = result.size; - while(tmp[newSize-1] == 0 && newSize > 0) - newSize--; - if(num(newSize) < num(result.size)) - result.bits = (uint32_t*)realloc(result.bits, sizeof(uint32_t)*num(newSize)); - result.size = newSize; + result.trim(); return result; } @@ -446,6 +444,8 @@ BigInt operator|(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + BigInt result; uint32_t na = num(a.size); @@ -475,6 +475,9 @@ BigInt operator^(const BigInt &a, const BigInt &b) { + assert(a.isValid() && b.isValid()); + + BigInt result; uint32_t na = num(a.size); @@ -494,6 +497,8 @@ result.bits[i] = b.bits[i]; } + result.trim(); + return result; } @@ -501,7 +506,30 @@ { return (*this = *this ^ a); } - + +BigInt modPow(const BigInt &a, const BigInt &expn, const BigInt &modulus) +{ + assert(a.isValid() && expn.isValid() && modulus.isValid()); + + BigInt result = 1; + BigInt tmpE = expn; + BigInt base = a; + while(tmpE > 0) + { + if(tmpE % 2 == 1) + result = (result * base) % modulus; + tmpE >>= 1; + base = (base * base) % modulus; + } + + return result; +} + +bool BigInt::isValid() const +{ + return size != 0 && bits != 0; +} + void BigInt::print() { printf("size: %d bytes\n", size); @@ -512,3 +540,15 @@ } printf("\n"); } + +void BigInt::trim() +{ + uint8_t *tmp = (uint8_t*)bits; + uint32_t newSize = size; + while(tmp[newSize-1] == 0 && newSize > 0) + newSize--; + if(num(newSize) < num(size)) + bits = (uint32_t*)realloc(bits, sizeof(uint32_t)*num(newSize)); + size = newSize; +} +
--- a/BigInt.h Fri Oct 04 15:16:06 2013 +0000 +++ b/BigInt.h Sat Oct 05 15:26:03 2013 +0000 @@ -50,15 +50,22 @@ friend BigInt operator&(const BigInt &a, const BigInt &b); BigInt& operator&=(const BigInt &a); friend BigInt operator|(const BigInt &a, const BigInt &b); - BigInt& operator|=(const BigInt &a); + BigInt& operator|=(const BigInt &a); friend BigInt operator^(const BigInt &a, const BigInt &b); - BigInt& operator^=(const BigInt &a); - + BigInt& operator^=(const BigInt &a); + + // 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 uint32_t *bits; };