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; }
Diff: BigInt.cpp
- Revision:
- 24:a3453a18388c
- Parent:
- 23:002f471a973e
- Child:
- 25:3d5c1f299da2
--- a/BigInt.cpp Mon Mar 10 21:59:19 2014 +0000 +++ b/BigInt.cpp Sun Apr 06 08:12:52 2014 +0000 @@ -15,7 +15,12 @@ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000 }; -static uint32_t num(const uint32_t a) +static uint32_t BITS2[] = +{ + 0x00FFFFFF, 0x0000FFFF, 0x00FFFFFF +}; + +static inline uint32_t num(const uint32_t a) { return a/4 + (a%4 ? 1:0); } @@ -539,14 +544,14 @@ while(r > 0) { if(a.bits[j/32] & BITS[j%32]) - result += b; + result.add(b); if(result.bits[0] & BITS[0]) - result += m; + result.add(m); ++j; --r; - result >>= 1; + result.shr(); } if(result >= m) @@ -579,6 +584,7 @@ uint32_t j = 0; while(j <= n) { + if(expn.bits[j/32] & BITS[j%32]) { if(tmp.isValid()) @@ -589,6 +595,7 @@ ++j; if(j <= n) montA = montgomeryStep(montA, montA, modulus, r); + } // convert tmp to normal world @@ -613,6 +620,50 @@ printf("\n"); } +void BigInt::add(const BigInt &b) +{ + uint32_t al = num(size); + uint32_t bl = num(b.size); + uint32_t rsize = std::max(size, b.size) + 1; + size_t l = num(rsize); + + if(l > al) + { + bits = (uint32_t*)realloc(bits, sizeof(uint32_t)*l); + memset(&bits[al], 0, (l-al)*sizeof(uint32_t)); + size = rsize; + } + + uint32_t carry = 0; + for(int i = 0; i < l; ++i) + { + uint32_t tmpA = 0, tmpB = 0; + if(i < al) + tmpA = bits[i]; + if(i < bl) + tmpB = b.bits[i]; + bits[i] = tmpA + tmpB + carry; + carry = bits[i] < std::max(tmpA, tmpB); + } + + trim(); +} + +void BigInt::shr() +{ + uint32_t lastBit = 0; + uint32_t tmp; + for(int i = num(size)-1; i >= 0; --i) + { + tmp = bits[i] & BITS[0]; + bits[i] >>= 1; + bits[i] |= (lastBit ? BITS[31] : 0); + lastBit = tmp; + } + + trim(); +} + void BigInt::trim() { assert(isValid()); @@ -623,15 +674,12 @@ newSize--; if(newSize == 0) newSize = 1; - if(num(newSize) < num(size)) + uint32_t n = num(newSize); + if(n < num(size)) { - uint32_t *tmp = new uint32_t[num(size)]; - memcpy(tmp, bits, num(size)*sizeof(uint32_t)); - delete[] bits; - bits = new uint32_t[num(newSize)]; - memset(bits, 0, sizeof(uint32_t)*num(newSize)); - memcpy(bits, tmp, newSize); - delete[] tmp; + bits = (uint32_t*)realloc(bits, n*sizeof(uint32_t)); + if(newSize % 4 != 0) + bits[n-1] &= BITS2[newSize%4]; } size = newSize; } @@ -651,4 +699,4 @@ n += tmp2; return n; -} +} \ No newline at end of file