diff mbox

[cbootimage,v1,3/8] Add in libmcrypto

Message ID 1441228760-26042-4-git-send-email-jimmzhang@nvidia.com
State Superseded, archived
Headers show

Commit Message

jimmzhang Sept. 2, 2015, 9:19 p.m. UTC
Libmcrypto is an open source crypto library. It can be found at
http://code.google.com/p/libmcrypto/

Libmcrypto provides functions for rsa pss signature calculation.

Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com>
---
 src/libm/base64.c          |  132 +++++
 src/libm/bigdUtils.c       |  208 +++++++
 src/libm/bigdigits.h       |  294 ++++++++++
 src/libm/common.c          |   58 ++
 src/libm/elliptic-ff2n.c   |  347 +++++++++++
 src/libm/elliptic-ff2n.h   |   97 +++
 src/libm/elliptic-ffp.c    | 1403 ++++++++++++++++++++++++++++++++++++++++++++
 src/libm/elliptic-ffp.h    |  232 ++++++++
 src/libm/ff2n.c            |  810 +++++++++++++++++++++++++
 src/libm/ff2n.h            |  127 ++++
 src/libm/galois.c          |  497 ++++++++++++++++
 src/libm/galois.h          |  101 ++++
 src/libm/hash.c            |  114 ++++
 src/libm/hash.h            |   49 ++
 src/libm/mcrypto.h         |   34 ++
 src/libm/md5.c             |  296 ++++++++++
 src/libm/md5.h             |   57 ++
 src/libm/mpAND.c           |    9 +
 src/libm/mpAdd.c           |   41 ++
 src/libm/mpBitLength.c     |   24 +
 src/libm/mpCompare.c       |   21 +
 src/libm/mpComplement.c    |    9 +
 src/libm/mpDivide.c        |  202 +++++++
 src/libm/mpEqual.c         |   19 +
 src/libm/mpGcd.c           |   26 +
 src/libm/mpHalfDiv.c       |   99 ++++
 src/libm/mpHalfMod.c       |   46 ++
 src/libm/mpIsOne.c         |   18 +
 src/libm/mpIsPrime.c       |  124 ++++
 src/libm/mpIsZero.c        |   19 +
 src/libm/mpJacobi.c        |   44 ++
 src/libm/mpLegendre.c      |    8 +
 src/libm/mpModAdd.c        |   32 +
 src/libm/mpModExp.c        |   40 ++
 src/libm/mpModInv.c        |   49 ++
 src/libm/mpModMult.c       |   20 +
 src/libm/mpModSquare.c     |   18 +
 src/libm/mpModSquareRoot.c |   96 +++
 src/libm/mpModSubtract.c   |   38 ++
 src/libm/mpModulo.c        |   34 ++
 src/libm/mpMultiply.c      |   55 ++
 src/libm/mpOR.c            |    9 +
 src/libm/mpSetDigit.c      |   15 +
 src/libm/mpSetEqual.c      |   11 +
 src/libm/mpSetZero.c       |   11 +
 src/libm/mpShiftLeft.c     |   43 ++
 src/libm/mpShiftRight.c    |   45 ++
 src/libm/mpShortAdd.c      |   38 ++
 src/libm/mpShortCmp.c      |   25 +
 src/libm/mpShortDiv.c      |   55 ++
 src/libm/mpShortMod.c      |   22 +
 src/libm/mpShortModMult.c  |   30 +
 src/libm/mpShortMult.c     |   40 ++
 src/libm/mpShortSub.c      |   39 ++
 src/libm/mpSizeof.c        |   14 +
 src/libm/mpSolinasPrime.c  |   41 ++
 src/libm/mpSquare.c        |   65 ++
 src/libm/mpSubtract.c      |   41 ++
 src/libm/mpSwap.c          |   16 +
 src/libm/mpXOR.c           |    9 +
 src/libm/pkcs1-rsa.c       |  833 ++++++++++++++++++++++++++
 src/libm/pkcs1-rsa.h       |  119 ++++
 src/libm/sha1.c            |  155 +++++
 src/libm/sha1.h            |   26 +
 src/libm/sha2.c            |  724 +++++++++++++++++++++++
 src/libm/sha2.h            |  128 ++++
 src/libm/spDivide.c        |  175 ++++++
 src/libm/spGcd.c           |   24 +
 src/libm/spIsPrime.c       |   89 +++
 src/libm/spModExp.c        |   64 ++
 src/libm/spModInv.c        |   41 ++
 src/libm/spModMult.c       |   17 +
 src/libm/spMultiply.c      |   76 +++
 src/libm/spPseudoRand.c    |   30 +
 74 files changed, 9017 insertions(+)
 create mode 100644 src/libm/base64.c
 create mode 100644 src/libm/bigdUtils.c
 create mode 100644 src/libm/bigdigits.h
 create mode 100644 src/libm/common.c
 create mode 100644 src/libm/elliptic-ff2n.c
 create mode 100644 src/libm/elliptic-ff2n.h
 create mode 100644 src/libm/elliptic-ffp.c
 create mode 100644 src/libm/elliptic-ffp.h
 create mode 100644 src/libm/ff2n.c
 create mode 100644 src/libm/ff2n.h
 create mode 100644 src/libm/galois.c
 create mode 100644 src/libm/galois.h
 create mode 100644 src/libm/hash.c
 create mode 100644 src/libm/hash.h
 create mode 100644 src/libm/mcrypto.h
 create mode 100644 src/libm/md5.c
 create mode 100644 src/libm/md5.h
 create mode 100644 src/libm/mpAND.c
 create mode 100644 src/libm/mpAdd.c
 create mode 100644 src/libm/mpBitLength.c
 create mode 100644 src/libm/mpCompare.c
 create mode 100644 src/libm/mpComplement.c
 create mode 100644 src/libm/mpDivide.c
 create mode 100644 src/libm/mpEqual.c
 create mode 100644 src/libm/mpGcd.c
 create mode 100644 src/libm/mpHalfDiv.c
 create mode 100644 src/libm/mpHalfMod.c
 create mode 100644 src/libm/mpIsOne.c
 create mode 100644 src/libm/mpIsPrime.c
 create mode 100644 src/libm/mpIsZero.c
 create mode 100644 src/libm/mpJacobi.c
 create mode 100644 src/libm/mpLegendre.c
 create mode 100644 src/libm/mpModAdd.c
 create mode 100644 src/libm/mpModExp.c
 create mode 100644 src/libm/mpModInv.c
 create mode 100644 src/libm/mpModMult.c
 create mode 100644 src/libm/mpModSquare.c
 create mode 100644 src/libm/mpModSquareRoot.c
 create mode 100644 src/libm/mpModSubtract.c
 create mode 100644 src/libm/mpModulo.c
 create mode 100644 src/libm/mpMultiply.c
 create mode 100644 src/libm/mpOR.c
 create mode 100644 src/libm/mpSetDigit.c
 create mode 100644 src/libm/mpSetEqual.c
 create mode 100644 src/libm/mpSetZero.c
 create mode 100644 src/libm/mpShiftLeft.c
 create mode 100644 src/libm/mpShiftRight.c
 create mode 100644 src/libm/mpShortAdd.c
 create mode 100644 src/libm/mpShortCmp.c
 create mode 100644 src/libm/mpShortDiv.c
 create mode 100644 src/libm/mpShortMod.c
 create mode 100644 src/libm/mpShortModMult.c
 create mode 100644 src/libm/mpShortMult.c
 create mode 100644 src/libm/mpShortSub.c
 create mode 100644 src/libm/mpSizeof.c
 create mode 100644 src/libm/mpSolinasPrime.c
 create mode 100644 src/libm/mpSquare.c
 create mode 100644 src/libm/mpSubtract.c
 create mode 100644 src/libm/mpSwap.c
 create mode 100644 src/libm/mpXOR.c
 create mode 100644 src/libm/pkcs1-rsa.c
 create mode 100644 src/libm/pkcs1-rsa.h
 create mode 100644 src/libm/sha1.c
 create mode 100644 src/libm/sha1.h
 create mode 100644 src/libm/sha2.c
 create mode 100644 src/libm/sha2.h
 create mode 100644 src/libm/spDivide.c
 create mode 100644 src/libm/spGcd.c
 create mode 100644 src/libm/spIsPrime.c
 create mode 100644 src/libm/spModExp.c
 create mode 100644 src/libm/spModInv.c
 create mode 100644 src/libm/spModMult.c
 create mode 100644 src/libm/spMultiply.c
 create mode 100644 src/libm/spPseudoRand.c

Comments

Stephen Warren Sept. 21, 2015, 8:11 p.m. UTC | #1
On 09/02/2015 03:19 PM, Jimmy Zhang wrote:
> Libmcrypto is an open source crypto library. It can be found at
> http://code.google.com/p/libmcrypto/

Not for much longer; Google code is shutting down. Is there a new 
upstream location for the code that we can reference? Is the project 
still alive?

Can we not link against a distribution package rather than copying the 
code inside cbootimage, and having to forever maintain it ourselves, 
including watching out for security holes and backporting fixes etc.?

Has an internal IP audit been performed for this use of libmcrypto? The 
Google code page says:

> There is no license associated with this library (although I have to
> select BSD license as code.google.com forced me to) except the
> respective licenses of included hash implementation. Anyway, if you
> use it, it would be nice if you drop me and David Ireland a line to
> say thank.

... and indeed there are no license headers in any of the files except 
one. I'd like our IP audit team to validate that using the code from 
cbootimage is acceptable and that copying the code into cbootimage is 
acceptable.

>  src/libm/base64.c          |  132 +++++
>  src/libm/bigdUtils.c       |  208 +++++++
>  src/libm/bigdigits.h       |  294 ++++++++++
>  src/libm/common.c          |   58 ++

"libm" is not the name of the library, and this directory layout does 
not match the upstream package. Please follow upstream's layout:

libmcrypto/include/bigdigits.h
libmcrypto/src/base64.c

... although I still think it'd be even better to just link against a 
distro package of libmcrypto, or otherwise require it to already exist 
when building cbootimage, if at all possible.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
jimmzhang Sept. 22, 2015, 12:05 a.m. UTC | #2
> -----Original Message-----
> From: Stephen Warren [mailto:swarren@wwwdotorg.org]
> Sent: Monday, September 21, 2015 1:11 PM
> To: Jimmy Zhang
> Cc: Allen Martin; Stephen Warren; linux-tegra@vger.kernel.org
> Subject: Re: [cbootimage PATCH v1 3/8] Add in libmcrypto
> 
> On 09/02/2015 03:19 PM, Jimmy Zhang wrote:
> > Libmcrypto is an open source crypto library. It can be found at
> > http://code.google.com/p/libmcrypto/
> 
> Not for much longer; Google code is shutting down. Is there a new upstream
> location for the code that we can reference? Is the project still alive?
> 
> Can we not link against a distribution package rather than copying the code
> inside cbootimage, and having to forever maintain it ourselves, including
> watching out for security holes and backporting fixes etc.?
> 
> Has an internal IP audit been performed for this use of libmcrypto? The
> Google code page says:
> 
> > There is no license associated with this library (although I have to
> > select BSD license as code.google.com forced me to) except the
> > respective licenses of included hash implementation. Anyway, if you
> > use it, it would be nice if you drop me and David Ireland a line to
> > say thank.
> 
> ... and indeed there are no license headers in any of the files except one. I'd
> like our IP audit team to validate that using the code from cbootimage is
> acceptable and that copying the code into cbootimage is acceptable.
> 
OK. I am going to open bug for IP audit team if that is what you mean.

> >  src/libm/base64.c          |  132 +++++
> >  src/libm/bigdUtils.c       |  208 +++++++
> >  src/libm/bigdigits.h       |  294 ++++++++++
> >  src/libm/common.c          |   58 ++
> 
> "libm" is not the name of the library, and this directory layout does not match
> the upstream package. Please follow upstream's layout:
> 
> libmcrypto/include/bigdigits.h
> libmcrypto/src/base64.c
> 
> ... although I still think it'd be even better to just link against a distro package
> of libmcrypto, or otherwise require it to already exist when building
> cbootimage, if at all possible.

I agree with you.  I will try to build libmcrypto as library and link with it. 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/libm/base64.c b/src/libm/base64.c
new file mode 100644
index 000000000000..00aba9cc4785
--- /dev/null
+++ b/src/libm/base64.c
@@ -0,0 +1,132 @@ 
+/* Base64 Encode/Decode Functions */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bigdigits.h"
+
+/* base64 encoding table */
+static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* base64 decoding table */
+static const char dectab[256] = {	
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+   52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1,
+   -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+   -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 
+}; 
+
+
+char *mpBase64Encode(DIGIT_T *p, UINT len)
+{
+	BYTE *pp;
+	char *str;
+	UINT i;
+	UINT j;
+	UINT k;
+	UINT nbyte;
+	UINT slen;
+	DWORD b;
+	DWORD mask = 0x003F;
+	UINT idx[4];
+	
+	nbyte = len*BITS_PER_DIGIT / 8;
+	
+	/* make input data 3-byte blocks */
+	if(nbyte % 3) {
+		nbyte = nbyte + 3 - (nbyte % 3);
+		pp = (BYTE *)malloc(nbyte);
+		memset(pp, 0x00, nbyte);
+		memcpy(pp, p, len*BITS_PER_DIGIT / 8);	
+	}
+	else
+		pp = (BYTE *)p;
+		
+	/* init output string */
+	slen = 4*nbyte/3;
+	str = (char *)malloc(slen+1);
+	memset(str, 0x00, slen+1);
+	
+	i = 0;
+	k = 0;		
+	while(i<nbyte){
+		/* convert 3 bytes = 24 bits each */
+		b = 0x0000;
+		for(j=0;j<3;j++)
+			b |= *(pp+i+j) << (j*8);
+		
+		/* split into four 6-bit codes and append to output string */
+		for(j=0;j<4;j++){
+			idx[j] = (b & (mask << (j*6))) >> (j*6);
+			*(str+j+k) = *(base64+idx[j]);
+		}
+		
+		/* Ouput Next 4 digits */
+		k+=4;
+		
+		/* Next 3 bytes */
+		i+=3;
+		
+	}
+	
+	free(pp);
+
+	return str;
+}
+
+DIGIT_T *mpBase64Decode(UINT *len, char *str)
+{
+	BYTE *p;
+	int i;
+	UINT j;
+	UINT k;
+	DWORD b;
+	UINT nbyte;
+	DWORD mask = 0x00FF;
+	
+	if((strlen(str) % 4)){
+		*len = 0;
+		return NULL;
+	}
+	
+	/* init output big integer */
+	nbyte = strlen(str)*3/4;
+	p = (BYTE *)malloc(nbyte);
+	memset(p, 0x00, nbyte);
+	
+	*len = nbyte / (BITS_PER_DIGIT / 8);
+	
+	
+	i = 0;
+	k = 0;
+	while(i < strlen(str)){
+		/* convert each 4 digits to 3 bytes */
+		b = 0x0000;
+		for(j=0;j<4;j++)
+			b |= (((BYTE)dectab[(BYTE)*(str+i+j)]) << (6*j));
+		
+		for(j=0;j<3;j++)
+			*(p+k+j) = (BYTE)((b >> (j*8)) & mask); 
+		
+		/* next 3 bytes */
+		k+= 3;
+		
+		/* next 4 digits */
+		i+= 4;
+	}
+	
+	return (DIGIT_T *)p;	
+}
+
diff --git a/src/libm/bigdUtils.c b/src/libm/bigdUtils.c
new file mode 100644
index 000000000000..37a4888d2a8d
--- /dev/null
+++ b/src/libm/bigdUtils.c
@@ -0,0 +1,208 @@ 
+/* bigdUtils.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bigdigits.h"
+
+/* support function */
+static BYTE hex2byte(char c)
+{
+	BYTE b;
+	
+	switch(c) {
+	case '0': 	b = 0; break;
+	case '1':	b = 1; break;
+	case '2':	b = 2; break;
+	case '3':	b = 3; break;
+	case '4':	b = 4; break;
+	case '5':	b = 5; break;
+	case '6':	b = 6; break;
+	case '7':	b = 7; break;
+	case '8':	b = 8; break;
+	case '9':	b = 9; break;
+	case 'A': 	
+	case 'a':	b = 10; break;
+	case 'B':	
+	case 'b':	b = 11; break;
+	case 'C':	
+	case 'c':	b = 12; break;
+	case 'D':	
+	case 'd':	b = 13; break;
+	case 'E':	
+	case 'e':	b = 14; break;
+	case 'F': 	
+	case 'f':	b = 15; break;
+	default: b = 0;
+	}
+	
+	return b;
+}
+
+DIGIT_T *mpMalloc(UINT ndigits)
+{
+	return (DIGIT_T *)malloc(NBYTE(ndigits));
+}
+
+DIGIT_T *mpMallocB(UINT nbits, UINT *ndigits)
+{
+	*ndigits = (nbits % BITS_PER_DIGIT) ? (nbits / BITS_PER_DIGIT) + 1 : nbits / BITS_PER_DIGIT;
+	return mpMalloc(*ndigits);
+}
+
+void mpFree(DIGIT_T *p)
+{
+	if(p)
+		free(p);
+	p = NULL;
+}
+
+
+/* main functions */
+void mpPrint(const DIGIT_T *p, UINT len)
+{
+	while (len--)
+		printf("%08lx ", p[len]);
+}
+
+void mpPrintNL(const DIGIT_T *p, UINT len)
+{
+	UINT i = 0;
+
+	while (len--) {
+		if ((i % 8) == 0 && i)
+			printf("\n");
+		printf("%08lx ", p[len]);
+		i++;
+	}
+	printf("\n");
+}
+
+void mpPrintTrim(const DIGIT_T *p, UINT len)
+{
+	/* Trim leading zeroes */
+	while (len--)
+		if (p[len] != 0)
+			break;
+	len++;
+	while (len--)
+		printf("%08lx ", p[len]);
+}
+
+void mpPrintTrimNL(const DIGIT_T *p, UINT len)
+{
+	UINT i = 0;
+
+	/* Trim leading zeroes */
+	while (len--)
+		if (p[len] != 0)
+			break;
+	len++;
+	while (len--) {
+		if ((i % 8) == 0 && i)
+			printf("\n");
+		printf("%08lx ", p[len]);
+		i++;
+	}
+	printf("\n");
+}
+
+void mpMakeRandom(DIGIT_T a[], UINT ndigits)
+{
+#if STRONG_RANDOM	
+	prng((BYTE *)a, NBYTE(ndigits));
+#else
+	UINT i;
+		
+	for (i = 0; i < ndigits; i++)
+		a[i] = spPseudoRand(0, MAX_DIGIT);
+#endif	
+}
+
+BYTE *mpASC2BIN(const char *s, UINT len, UINT *nread)
+{
+	BYTE *p = NULL;
+	
+	/* init big integer storage */
+	p = (BYTE*)malloc(len);
+	memset(p, 0x00, len);
+	
+	/* Convert using ASCII table */
+	if(len>strlen(s))
+		*nread = strlen(s);
+	else
+		*nread = len;
+	
+	memcpy(p, s, *nread);
+	
+	return p;
+}
+
+char *mpBIN2ASC(const BYTE *p, UINT len)
+{
+	char *s = NULL;
+	
+	/* init string storage */
+	s = (char *)malloc(len+1);
+	memset(s, 0x00, len+1);
+	
+	memcpy(s, p, len);
+	
+	return s;
+}
+
+BYTE *mpHex2Bin(const char *s, UINT len, UINT *nread)
+{
+	BYTE *p = NULL;
+	UINT i;
+	
+	if(strlen(s) % 2){
+		*nread = 0;
+		return NULL;
+	}
+	
+	p = (BYTE *)malloc(len);
+	memset(p, 0x00, len);
+		
+	if(len < strlen(s)/2)
+		*nread = 2*len;
+	else
+		*nread = strlen(s);
+	
+	i = 0;
+	while(i<*nread){
+		/* read 2 characters each = 1 byte */
+		p[i/2] = hex2byte(s[strlen(s)-i-1]) + (hex2byte(s[strlen(s)-i-2]) << 4);
+		i+=2;
+	}
+	
+	return p;
+}
+
+char *mpBin2Hex(const BYTE *p, UINT len)
+{
+	char *s = NULL;
+	UINT i;
+	
+	s = (char *)malloc(2*len + 1);
+	memset(s, 0x00, 2*len+1);
+	
+	i = 0;
+	while (len--){
+		sprintf(s+i, "%02X", p[len]);
+		i+=2;
+	}
+	
+	return s;
+}
+
+BYTE *mpDec2Bin(const char *s, UINT *nread)
+{
+	return NULL;
+}
+
+BYTE *mpOct2Hex(const char *s, UINT *nread)
+{
+	return NULL;
+}
+
diff --git a/src/libm/bigdigits.h b/src/libm/bigdigits.h
new file mode 100644
index 000000000000..7c9f563f3d54
--- /dev/null
+++ b/src/libm/bigdigits.h
@@ -0,0 +1,294 @@ 
+/* bigdigits.h */
+
+/*
+  Most of this multi-precision arithmetic library was developed by David Ireland, 
+  the author of BIGDIGITS library, copyright (c) 2001-8 by D.I. Management
+  Services Pty Limited - www.di-mgt.com.au. 
+  
+  The bigdigits library version 1.0 has been extended by Dang Nguyen Duc and posted 
+  on public domain with permission from Davia Ireland.
+*/
+
+
+#ifndef _BIGDIGITS_H_
+#define _BIGDIGITS_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mcrypto.h"
+
+/* Define type of DIGIT here */
+typedef unsigned long DIGIT_T;
+typedef unsigned short HALF_DIGIT_T;
+
+/* Sizes to suit your machine - todo: move to mcrypto.h */
+#define MAX_DIGIT 	(DIGIT_T)(0xffffffff)
+#define MAX_HALF_DIGIT 	(DIGIT_T)(0xffff)
+#define BITS_PER_DIGIT 	32
+#define HIBITMASK 	(DIGIT_T)(0x80000000)
+
+/* Max number of digits expected in a mp array ~ 2048 bits */
+#define MAX_DIG_LEN 64	
+
+/*	temp storage to be used in:
+	mpModulo, mpShortMod, mpModMult, mpGcd,
+	mpModInv, mpIsPrime, have max number of digits
+*/
+
+/* Useful macros - todo: move to mcrypto.h */
+#define LOHALF(x) ((DIGIT_T)((x) & 0xffff))
+#define HIHALF(x) ((DIGIT_T)((x) >> 16 & 0xffff))
+#define TOHIGH(x) ((DIGIT_T)((x) << 16))
+
+#define ISODD(x) ((x) & 0x1)
+#define ISEVEN(x) (!ISODD(x))
+
+#define mpISODD(x, n) (x[0] & 0x1)
+#define mpISEVEN(x, n) (!(x[0] & 0x1))
+
+#define mpNEXTBITMASK(mask, n) if(mask==1){mask=HIBITMASK;n--;}else{mask>>=1;}
+
+#define NBYTE(len)	(len)*BITS_PER_DIGIT / 8	
+#define NDIGIT(n)	((n) % BITS_PER_DIGIT) ? ((n) / BITS_PER_DIGIT) + 1 : ((n) / BITS_PER_DIGIT)
+
+/* memory management rountines */
+DIGIT_T *mpMalloc(UINT ndigits);
+	/* allocate memory for big integer with ndigits digits */
+
+DIGIT_T *mpMallocB(UINT nbits, UINT *ndigits);
+	/* allocate memory for big integer with nbits-bit long */
+
+void mpFree(DIGIT_T *p);
+	/* free memory allocated to p */
+
+/*	Multiple precision calculations	
+	Using known, equal ndigits
+	except where noted
+*/
+
+DIGIT_T mpAdd(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits);
+	/* Computes w = u + v, returns carry */
+
+DIGIT_T mpSubtract(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits);
+	/* Computes w = u - v, returns borrow */
+
+int mpMultiply(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits);
+	/* Computes product w = u * v 
+	   u, v = ndigits long; w = 2 * ndigits long */
+
+int mpDivide(DIGIT_T q[], DIGIT_T r[], const DIGIT_T u[], UINT udigits, const DIGIT_T v[], UINT vdigits);
+	/* Computes quotient q = u / v and remainder r = u mod v 
+	   q, r, u = udigits long; v = vdigits long
+	   Warning: Trashes q and r first */
+
+int mpSquare(DIGIT_T w[], const DIGIT_T u[], UINT ndigits);
+	/* Compute w = u^2 */
+
+int mpModulo(DIGIT_T r[], const DIGIT_T u[], UINT udigits, const DIGIT_T v[], UINT vdigits);
+	/* Computes r = u mod v 
+	   u = udigits long; r, v = vdigits long */
+
+int mpModMult(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], const DIGIT_T m[], UINT ndigits);
+	/* Computes a = (x * y) mod m */
+
+int mpModSquare(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T p[], UINT ndigits);
+	/* Compute w = u^2 mod p */
+	
+int mpModExp(DIGIT_T y[], const DIGIT_T x[], const DIGIT_T n[], const DIGIT_T d[], UINT ndigits);
+	/* Computes y = x^n mod d */
+
+int mpModInv(DIGIT_T inv[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits);
+	/*	Computes inv = u^-1 mod v */
+
+int mpModAdd(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], const DIGIT_T m[], UINT ndigits);
+	/* Compute w = u + v mod m */
+
+int mpModSubtract(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], const DIGIT_T m[], UINT ndigits);
+	/* Compute w = u - v mod m */
+
+int mpJacobi(int *val, const DIGIT_T a[], const DIGIT_T m[], UINT len);
+	/* Compute Jacobian symbol val = (a/m) where m is an odd integer */
+	
+int mpLegendre(int *val, const DIGIT_T a[], const DIGIT_T p[], UINT len);
+	/* Compute Legendre symbol val = (a/p) where p is an odd prime */
+
+int mpModSquareRoot(DIGIT_T x[], const DIGIT_T a[], const DIGIT_T p[], UINT S, const DIGIT_T Q[], const DIGIT_T V[], const DIGIT_T a1[], UINT len);
+	/* 
+	   Compute modulo p square root of a, x^2 = a mod p 
+	   a1 = a^-1 mod p
+	   p-1 = Q*2^S, Q is odd
+	   V = W^Q mod p where W is a quadratic nonresidue modulo p
+	   V, S, Q are computed using mpModSquareRootPre
+	   a1 can be computed by mpModInv or mpModExp (a^(-1) = a^(p-2) mod p)
+	*/
+
+int mpModSquareRootPre(UINT *S, DIGIT_T Q[], DIGIT_T V[], const DIGIT_T p[], UINT len);
+	/* Precomputation for mpModSquareRoot */
+
+int mpGcd(DIGIT_T g[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits);
+	/* Computes g = gcd(x, y) */
+
+int mpEqual(const DIGIT_T a[], const DIGIT_T b[], UINT ndigits);
+	/* Returns true if a == b, else false */
+
+int mpCompare(const DIGIT_T a[], const DIGIT_T b[], UINT ndigits);
+	/* Returns sign of (a - b) */
+
+int mpIsZero(const DIGIT_T a[], UINT ndigits);
+	/* Returns true if a == 0, else false */
+
+int mpIsOne(const DIGIT_T a[], UINT ndigits);
+	/* Returns true if a == 1, else false */
+
+int mpSwap(DIGIT_T a[], DIGIT_T b[], UINT len);
+	/* Swap two integers */
+
+/* Bitwise operations */
+
+DIGIT_T mpShiftLeft(DIGIT_T a[], const DIGIT_T b[], UINT x, UINT ndigits);
+	/* Computes a = b << x */
+
+DIGIT_T mpShiftRight(DIGIT_T a[], const DIGIT_T b[], UINT x, UINT ndigits);
+	/* Computes a = b >> x */
+
+void mpAND(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits);	
+	/* Bitwise AND */
+
+void mpOR(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits);	
+	/* Bitwise OR */
+	
+void mpXOR(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits);
+	/* Bitwise XOR */
+
+void mpComplement(DIGIT_T a[], const DIGIT_T b[], UINT ndigits);
+	/* Bitwise Complement */
+	
+/* Other mp utilities */
+
+void mpSetZero(DIGIT_T a[], UINT ndigits);
+	/* Sets a = 0 */
+
+void mpSetDigit(DIGIT_T a[], DIGIT_T d, UINT ndigits);
+	/* Sets a = d where d is a single digit */
+
+void mpSetEqual(DIGIT_T a[], const DIGIT_T b[], UINT ndigits);
+	/* Sets a = b */
+
+UINT mpSizeof(const DIGIT_T a[], UINT ndigits);
+	/* Returns size of significant non-zero digits in a */
+
+UINT mpBitLength(const DIGIT_T d[], UINT ndigits);
+	/* Return actual bit length of d */
+
+int mpIsPrime(const DIGIT_T w[], UINT ndigits, UINT t);
+	/* Returns true if w is a probable prime 
+	   t tests using FIPS-186-2/Rabin-Miller */
+
+UINT mpSolinasPrime(DIGIT_T p[], UINT ndigits, UINT bit_len);
+	/* generate Solinas' prime of the form p = 2^a + 2^b + 1, return b if succeeded and 0 if failed */
+
+/* mpShort = mp x single digit calculations */
+
+DIGIT_T mpShortAdd(DIGIT_T w[], const DIGIT_T u[], DIGIT_T d, UINT ndigits);
+	/* Computes w = u + d, returns carry */
+
+DIGIT_T mpShortSub(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, UINT ndigits);
+	/* Computes w = u - v, returns borrow */
+
+DIGIT_T mpShortMult(DIGIT_T p[], const DIGIT_T x[], DIGIT_T y, UINT ndigits);
+	/* Computes product p = x * y */
+
+DIGIT_T mpShortDiv(DIGIT_T q[], const DIGIT_T u[], DIGIT_T v, UINT ndigits);
+	/* Computes q = u / v, returns remainder */
+
+DIGIT_T mpShortMod(const DIGIT_T a[], DIGIT_T d, UINT ndigits);
+	/* Return r = a mod d */
+
+int mpShortCmp(const DIGIT_T a[], DIGIT_T b, UINT ndigits);
+	/* Return sign of (a - b) where b is a single digit */
+
+int mpShortModMult(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, DIGIT_T m[], UINT ndigits);
+	/* Compute w = u*v mod m */
+
+/* Short division using only half-digit divisor */
+
+DIGIT_T mpHalfDiv(DIGIT_T q[], const DIGIT_T a[], HALF_DIGIT_T d, UINT ndigits);
+	/* Computes q = a mod d, returns remainder */
+
+DIGIT_T mpHalfMod(const DIGIT_T a[], HALF_DIGIT_T d, UINT ndigits);
+	/* Return r = a mod d */
+
+/* Single precision calculations (double where necessary) */
+
+int spMultiply(DIGIT_T p[2], DIGIT_T x, DIGIT_T y);
+	/* Computes p = x * y */
+
+DIGIT_T spDivide(DIGIT_T *q, DIGIT_T *r, DIGIT_T u[2], DIGIT_T v);
+	/* Computes quotient q = u / v, remainder r = u mod v */
+
+int spModExp(DIGIT_T *exp, DIGIT_T x, DIGIT_T n, DIGIT_T d);
+	/* Computes exp = x^n mod d */
+
+int spModMult(DIGIT_T *a, DIGIT_T x, DIGIT_T y, DIGIT_T m);
+	/* Computes a = (x * y) mod m */
+
+int spModInv(DIGIT_T *inv, DIGIT_T u, DIGIT_T v);
+	/* Computes inv = u^-1 mod v */
+
+DIGIT_T spGcd(DIGIT_T x, DIGIT_T y);
+	/* Returns gcd(x, y) */
+
+int spIsPrime(DIGIT_T w, UINT t);
+	/* Returns true if w is prime, else false; try t tests */
+
+DIGIT_T spPseudoRand(DIGIT_T lower, DIGIT_T upper);
+	/* Returns single pseudo-random digit between lower and upper */
+
+/* Utilities */
+
+void mpPrint(const DIGIT_T *p, UINT len);
+	/* Print all digits incl leading zero digits */
+	
+void mpPrintNL(const DIGIT_T *p, UINT len);
+	/* Print all digits with newlines */
+	
+void mpPrintTrim(const DIGIT_T *p, UINT len);
+	/* Print but trim leading zero digits */
+	
+void mpPrintTrimNL(const DIGIT_T *p, UINT len);
+	/* Print, trim leading zeroes, add newlines */
+
+void mpMakeRandom(DIGIT_T a[], UINT ndigits);
+	/* Generate a pseudorandom number */
+	
+BYTE *mpASC2BIN(const char *s, UINT len, UINT *nread);
+	/* convert an ascii string to a big integer of length len */
+
+char *mpBIN2ASC(const BYTE *p, UINT len);
+	/* convert a big integer of length len to an ascii string */
+
+BYTE *mpHex2Bin(const char *s, UINT len, UINT *nread);
+	/* Convert an hexa string to binary data */
+
+char *mpBin2Hex(const BYTE *p, UINT len);
+	/* Convert binary data to an hexa string */
+	
+BYTE *mpDec2Bin(const char *s, UINT *nread);
+	/* Convert a decimal string to binary data */
+
+BYTE *mpOct2Hex(const char *s, UINT *nread);
+	/* Convert an octal string to binary data */
+
+char *mpBase64Encode(DIGIT_T *p, UINT len);
+	/* convert binary data to an integer string in base64 */
+
+DIGIT_T *mpBase64Decode(UINT *len, char *str);
+	/* convert an integer string in base 64 to binary data */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _BIGDIGITS_H_ */
diff --git a/src/libm/common.c b/src/libm/common.c
new file mode 100644
index 000000000000..a28497592882
--- /dev/null
+++ b/src/libm/common.c
@@ -0,0 +1,58 @@ 
+/* common functions for libmcrypto */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef __linux__
+	/* linux-specific include files */
+	#include <unistd.h>
+	#include <sys/types.h>
+	#include <sys/stat.h>
+#elif defined(window)
+	/* window-specific include files */
+#endif 
+
+#include "mcrypto.h"
+
+int prng(BYTE* buf, int buf_size)
+{
+#if LINUX_URANDOM	    	
+	int fd;
+    
+    	if((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+        	perror("/dev/urandom");
+        	return -1;
+    	}
+    	read(fd, buf, buf_size);
+    	close(fd);
+#else
+	/* other platforms support here - for now fill buf with zeros :) */
+	memset(buf, 0x00, buf_size);
+#endif		
+	return 0;
+}
+
+/* Useful Function for Debug */
+void mcrypto_msg(const char *s)
+{
+#ifdef MCRYPTO_DEBUG
+	fprintf(stderr, "debugging message - file %s line %d : %s", __FILE__, __LINE__, s);
+#endif
+}
+
+void mcrypto_dump(char *desc, BYTE *p, UINT len)
+{
+#ifdef MCRYPTO_DEBUG
+	UINT i = 0;
+	
+	printf("[%s]\n", desc);
+	while (len--) {
+		if ((i % 20) == 0 && i)
+			printf("\n");
+		fprintf(stderr, "%02x ", p[len]);
+		i++;
+	}
+	fprintf(stderr, "\n");
+#endif
+}
diff --git a/src/libm/elliptic-ff2n.c b/src/libm/elliptic-ff2n.c
new file mode 100644
index 000000000000..16aa3937285c
--- /dev/null
+++ b/src/libm/elliptic-ff2n.c
@@ -0,0 +1,347 @@ 
+/*--------------------------------------------------------------------*/
+/* elliptic.c  : ellipic curve arithmetic implementation source file  */
+/* Author      : Dang Nguyen Duc - nguyenduc@icu.ac.kr		      */
+/* Last Update : 04/03/2001					      */
+/* Reference   : "Elliptic Curve Cryptography" by I. F. Blake et al.  */
+/* TO DO       :						      */
+/*--------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "elliptic-ff2n.h"
+#include "ff2n.h"
+#include "bigdigits.h"
+
+E2n_Point* e2n_point_init(E2n_Curve *E)
+{
+	E2n_Point *P = NULL;
+	
+	P = (E2n_Point *)malloc(sizeof(E2n_Point));
+	
+	P->x = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	P->y = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+
+	return P;
+}
+	
+
+int e2n_point_copy(E2n_Curve *E, E2n_Point *Q, E2n_Point *P)
+{
+	ff2n_set_equal(Q->x, P->x, E->len);
+	ff2n_set_equal(Q->y, P->y, E->len);
+	
+	return 0;
+}
+
+int e2n_point_zero(E2n_Curve *E, E2n_Point *P)
+{
+	/* P = infinity */
+	ff2n_set_zero(P->x, E->len);
+	ff2n_set_zero(P->y, E->len);
+	
+	return 0;
+}
+
+
+int e2n_point_inv(E2n_Curve *E, E2n_Point *Q, E2n_Point *P)
+{
+	/* Q = -P: Xq = Xp, Yq = Xp + Yp */
+	ff2n_set_equal(Q->x, P->x, E->len);
+	ff2n_add(Q->y, P->x, P->y, E->len);
+	
+	return 0;
+}
+
+int e2n_point_double(E2n_Curve *E, E2n_Point* Q, E2n_Point *P)
+{
+	FF2N_ELT *lamda;
+	FF2N_ELT *T1;
+	FF2N_ELT *T2;
+	
+	/* If P = Infinity */
+	if(ff2n_is_zero(P->x, E->len) && ff2n_is_zero(P->y, E->len))
+	{
+		e2n_point_zero(E, Q);
+		
+		return 0;
+	}
+	
+	/* Allocate memory */
+	lamda = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T1 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T2 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	
+	/* lamda = Yp/Xp + Xp */
+	ff2n_inverse(T1, P->x, E->n, E->len);		/* T1 = Xp^-1 */
+	ff2n_mul(T2, T1, P->y, E->n, E->len);		/* T2 = Yp*T1 */
+	ff2n_add(lamda, T2, P->x, E->len);		/* lamda = T2 + Xp */
+	
+	/* Xq = lamda^2 + lamda + a */
+	ff2n_sqr2(T1, lamda, E->n, E->len);		/* T1 = lamda^2 */
+	ff2n_add(T2, T1, lamda, E->len);		/* T2 = T1 + lamda */
+	ff2n_add(Q->x, T2, E->a, E->len);		/* Xq = T2 + a */
+	
+	/* Yq = (Xp + Xq)*lamda + Xq + Yp */
+	ff2n_add(T1, Q->x, P->x, E->len);		/* T1 = Xp + Xq */
+	ff2n_mul(T2, T1, lamda, E->n, E->len);		/* T2 = T1 * lamda */
+	ff2n_add(T1, T2, Q->x, E->len);			/* T1 = T2 + Xq */
+	ff2n_add(Q->y, T1, P->y, E->len);		/* Yq = T1 + Yp */
+	
+	free(lamda);
+	free(T1);
+	free(T2);
+	
+	return 0;
+}
+
+int e2n_point_add(E2n_Curve *E, E2n_Point *R, E2n_Point *P, E2n_Point *Q)
+{
+	FF2N_ELT *lamda;
+	FF2N_ELT *T1;
+	FF2N_ELT *T2;
+	
+	/* If P = Q, call e2n_point_double instead */
+	if(ff2n_is_equal(P->x, Q->x, E->len) && ff2n_is_equal(P->y, Q->y, E->len))
+		return e2n_point_double(E, R, P);
+		
+	/* if P = infinity */
+	if(ff2n_is_zero(P->x, E->len) && ff2n_is_zero(P->y, E->len))
+	{
+		e2n_point_copy(E, R, Q);
+		
+		return 0;
+	}
+	
+	/* if Q = infinity */
+	if(ff2n_is_zero(Q->x, E->len) && ff2n_is_zero(Q->y, E->len))
+	{
+		e2n_point_copy(E, R, P);
+		
+		return 0;
+	}
+	
+	/* if P = -Q */	
+	T1 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	ff2n_add(T1, Q->x, Q->y, E->len);
+	if(ff2n_is_equal(P->x, Q->x, E->len) && ff2n_is_equal(P->y, T1, E->len))
+	{
+		e2n_point_zero(E, R);
+		
+		free(T1);
+		return 0;
+	}
+	
+	/* Otherwise - Allocate memory */
+	lamda = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T2 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	
+	/* Compute lamda = (Yp + Yq) / (Xp + Xq) */
+	ff2n_add(T1, P->x, Q->x, E->len);		/* T1 =  Xp + Xq */
+	ff2n_inverse(T2, T1, E->n, E->len);		/* T2 = T1^-1 */
+	ff2n_add(T1, P->y, Q->y, E->len);		/* T1 = Yq + Yq */
+	ff2n_mul(lamda, T1, T2, E->n, E->len);		/* lamda = T1 * T2 */
+	
+	/* Compute Xr = a + lamda^2 + lamda + Xp + Xq */
+	ff2n_sqr2(T1, lamda, E->n, E->len);		/* T1 = lamda^2 */
+	ff2n_add(T2, T1, E->a, E->len);			/* T2 = T1 + a */
+	ff2n_add(T1, T2, lamda, E->len);		/* T1 = T2 + lamda */
+	ff2n_add(T2, T1, P->x, E->len);			/* T2 = T1 + Xp */
+	ff2n_add(R->x, T2, Q->x, E->len);		/* Xr = T2 + Xq */
+	
+	/* Yr = (Xp + Xr)*lamda + Xr + Yp */
+	ff2n_add(T1, R->x, P->x, E->len);		/* T1 = Xp + Xq */
+	ff2n_mul(T2, T1, lamda, E->n, E->len);		/* T2 = T1 * lamda */
+	ff2n_add(T1, T2, R->x, E->len);			/* T1 = T2 + Xq */
+	ff2n_add(R->y, T1, P->y, E->len);		/* Yq = T1 + Yp */
+	
+	free(lamda);
+	free(T1);
+	free(T2);
+	
+	return 0;
+}
+
+int e2n_point_sub(E2n_Curve *E, E2n_Point *R, E2n_Point *P, E2n_Point *Q)
+{
+	E2n_Point *T;
+	
+	T = e2n_point_init(E);
+	
+	e2n_point_inv(E, T, Q);
+	
+	e2n_point_add(E, R, P, T);
+	
+	free(T->x);
+	free(T->y);
+	free(T);
+	
+	return 0;
+}
+	
+int e2n_point_mul(E2n_Curve *E, E2n_Point *Q, E2n_Point *P, DIGIT_T *k, UINT klen)
+{
+	/* scalar multiplication using binary method */
+	DIGIT_T mask;
+	int i;
+	E2n_Point *R;
+	
+	/* Allocate temp memory */
+	R = e2n_point_init(E);
+			
+	/* Set Q = Infinity */
+	e2n_point_zero(E, Q);
+
+	while(klen--)
+	{
+		mask = HIBITMASK;
+		for(i=BITS_PER_DIGIT-1;i>=0;i--)
+		{
+			e2n_point_double(E, R, Q);
+			if(k[klen] & mask)
+			{
+				e2n_point_add(E, Q, R, P);
+			}
+			else
+			{
+				ff2n_set_equal(Q->x, R->x, E->len);
+				ff2n_set_equal(Q->y, R->y, E->len);
+			}		
+			mask >>= 1;
+		}
+	}
+	
+	free(R->x);
+	free(R->y);
+	free(R);
+	
+	return 0;
+}
+
+int e2n_point_gen(E2n_Curve *E, E2n_Point *P)
+{
+    	/* need ff2n_square_root function */
+	
+    	return 0;
+}
+
+/* Utility function */
+int e2n_load_curve(char *fname, E2n_Curve *E)
+{
+	FILE *f;
+	char s[E2N_NPARAM][E2N_MAX_LINE_LEN];
+	int i;
+	
+	f = fopen(fname, "r");
+
+	if(f==NULL){
+		printf("Failed to read file %s\n",fname);
+		return -1;
+	}
+
+	memset(s, 0x00, E2N_NPARAM*E2N_MAX_LINE_LEN);
+	
+	/* reading data */
+	for(i=0;i<E2N_NPARAM;i++)
+	{
+		if(feof(f))
+		{
+			fclose(f);
+			return -1;
+		}
+		fgets(s[i], E2N_MAX_LINE_LEN, f);
+		s[i][strlen(s[i])-1] = '\0';
+	}
+	fclose(f);
+	
+	/* Collecting data */
+	E->len = (UINT)atoi(s[1]);
+	
+	if((E->n=ff2n_str2poly(FF2N_NBYTE(E->len), s[2]))==NULL)
+		return -1;
+	
+	if((E->a=ff2n_str2poly(FF2N_NBYTE(E->len), s[3]))==NULL)
+		return -1;
+	
+	if((E->b=ff2n_str2poly(FF2N_NBYTE(E->len), s[4]))==NULL)
+		return -1;
+	
+	if((E->G.x=ff2n_str2poly(FF2N_NBYTE(E->len), s[5]))==NULL)
+		return -1;
+	
+	if((E->G.y=ff2n_str2poly(FF2N_NBYTE(E->len), s[6]))==NULL)
+		return -1;
+	
+	E->rlen = (UINT)atoi(s[7]);
+	
+	if((E->r=ff2n_str2poly(FF2N_NBYTE(E->len), s[8]))==NULL)
+		return -1;
+	
+	E->h = (DIGIT_T)atoi(s[9]);
+	
+
+	return 0;
+}
+
+int e2n_save_curve(char *fname, E2n_Curve *E)
+{
+	FILE *f;
+	
+	if((f=fopen(fname, "w")) == NULL)
+		return -1;
+	
+	fprintf(f,"------------------------BEGIN ELLIPTIC CURVE PARAMETERS-------------------------\n");
+	fprintf(f,"%d\n", E->len);
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->n, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->a, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->b, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->G.x, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->G.y, NBYTE(E->len)));
+	fprintf(f,"%d\n", E->rlen);
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->r, NBYTE(E->rlen)));
+	fprintf(f,"%lu\n", E->h);
+	fprintf(f,"-----------------------END OF ELLIPTIC CURVE PARAMETERS-------------------------\n");
+	
+	fclose(f);
+	
+	return 0;
+}
+
+int e2n_is_on_curve(E2n_Curve *E, E2n_Point *P)
+{
+	FF2N_ELT *T1;
+	FF2N_ELT *T2;
+	FF2N_ELT *T3;
+	FF2N_ELT *T4;
+	int ret;
+	
+	/* If P = Infinity */
+	if(ff2n_is_zero(P->x, E->len) && ff2n_is_zero(P->y, E->len))
+		return 1;
+	
+	T1 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T2 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T3 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	T4 = (FF2N_ELT *)malloc(FF2N_NBYTE(E->len));
+	
+	/* T1 = Yp^2 + Yp*Xp */
+	ff2n_sqr2(T1, P->y, E->n, E->len);
+	ff2n_mul(T2, P->x, P->y, E->n, E->len);
+	ff2n_add(T1, T1, T2, E->len);
+	
+	/* T2 = Xp^3 + a*Xp^2 + b */
+	ff2n_sqr2(T2, P->x, E->n, E->len);
+	ff2n_mul(T3, T2, E->a, E->n, E->len);
+	ff2n_mul(T4, T2, P->x, E->n, E->len);
+	ff2n_add(T2, T3, T4, E->len);
+	ff2n_add(T2, T2, E->b, E->len);
+	
+	ret = ff2n_is_equal(T1, T2, E->len);
+	
+	free(T1);
+	free(T2);
+	free(T3);
+	free(T4);
+	
+	return ret;
+}
diff --git a/src/libm/elliptic-ff2n.h b/src/libm/elliptic-ff2n.h
new file mode 100644
index 000000000000..1696d721f02c
--- /dev/null
+++ b/src/libm/elliptic-ff2n.h
@@ -0,0 +1,97 @@ 
+/*--------------------------------------------------------------------*/
+/* elliptic.h  : ellipic curve arithmetic implementation header file  */
+/* Author      : Dang Nguyen Duc - nguyenduc@icu.ac.kr		      */
+/* Last Update : 03/02/2007					      */
+/*--------------------------------------------------------------------*/
+
+#ifndef _ELLIPTIC_FF2N_H_
+#define _ELLIPTIC_FF2N_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ff2n.h"
+#include "bigdigits.h"
+
+/* coordinate data structure */
+typedef struct {
+		  	FF2N_ELT *x;
+		  	FF2N_ELT *y;
+		} E2n_Point;
+
+typedef struct {
+		  	FF2N_ELT *X;	/* x = X/Z^2 */
+		  	FF2N_ELT *Y;	/* y = Y/Z^3 */
+			FF2N_ELT *Z;
+		} E2n_Projective_Point;
+
+/* elliptic curve over GF(2^n) affine coordinate : y^2 + xy = x^3 + a*x^2 + b */
+/*                         projective coordinate : Y^2 + XYZ = X^3 + aX^2Z^2 + bZ^6 */
+typedef struct {
+			UINT		len;	/* Length of field element in DWORD */
+			FF2N_ELT	*n;	/* Irreducible polynomial */		
+			FF2N_ELT	*a;	
+			FF2N_ELT	*b;	/* must be non-zero */
+			E2n_Point	G;	/* base point */
+			UINT		rlen;	/* length of r in DWORD */
+			DIGIT_T		*r;	/* base point order */
+			DIGIT_T		h;	/* h*r = order of curve */
+		} E2n_Curve;
+
+#define E2N_NPARAM		9 + 2	    	/* Number of lines in domain parameter file */
+#define E2N_MAX_LINE_LEN	256+1		/* Max length of a line in domain parameter file */
+
+/* function prototypes */
+
+E2n_Point* e2n_point_init(E2n_Curve *E);
+	/* Allocate Memory for a Point */
+
+int e2n_point_copy(E2n_Curve *E, E2n_Point *P, E2n_Point *Q);
+	/* Make P = Q */
+
+int e2n_point_zero(E2n_Curve *E, E2n_Point *P);
+	/* Make P = infinity */
+
+int e2n_point_inv(E2n_Curve *E, E2n_Point *Q, E2n_Point *P);
+	/* Point Inversion */
+
+int e2n_point_add(E2n_Curve *E, E2n_Point *R, E2n_Point *P, E2n_Point *Q);
+	/* Point Addition */
+
+int e2n_point_sub(E2n_Curve *E, E2n_Point *R, E2n_Point *P, E2n_Point *Q);
+	/* Point Subtraction */
+	
+int e2n_point_double(E2n_Curve *E, E2n_Point* Q, E2n_Point *P);
+	/* Point Doubling */
+	
+int e2n_point_mul(E2n_Curve *E, E2n_Point *Q, E2n_Point *P, DIGIT_T *k, UINT klen);
+	/* Point Multiplication */
+
+int e2n_point_mulw(E2n_Curve *E, E2n_Point *Q, E2n_Point *P, DIGIT_T *k, UINT klen);
+	/* Point Multiplication Using Sliding Window Method */
+	
+int e2n_point_gen(E2n_Curve *E, E2n_Point *P);
+	/* Random Point Generation */
+
+int e2n_point_order(E2n_Curve *E, E2n_Point *P, DIGIT_T *k);
+	/* Compute order of P - todo */
+
+int e2n_curve_gen(E2n_Curve *E);
+	/* Verifiable Pseudorandom Elliptic Curve Generation - todo */
+
+/* Utility Function */
+int e2n_is_on_curve(E2n_Curve *E, E2n_Point *P);
+	/* Return 1 if P lies on E, otherwise return 0 */
+	
+int e2n_load_curve(char *fname, E2n_Curve *E);
+	/* Load Elliptic Curve Domain Parameters From File */
+
+int e2n_save_curve(char *fname, E2n_Curve *E);
+	/* Save Elliptic Curve Domain Parameters To File */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libm/elliptic-ffp.c b/src/libm/elliptic-ffp.c
new file mode 100644
index 000000000000..fd7fbcc8806d
--- /dev/null
+++ b/src/libm/elliptic-ffp.c
@@ -0,0 +1,1403 @@ 
+/*-----------------------------------------------------------*/
+/* Elliptic Curve Over Prime Field Implementation            */
+/* Built-in ElGamal Encryption and ECDSA 		     */	
+/* Author: Dang Nguyen Duc                                   */
+/* Date  : 2007/02/03                                        */
+/* Ref	 : IEEE P1363 Public Key Cryptography Specifications */
+/*         Blake, Serousi and Smart - "EC Cryptography"      */
+/*         IBCS#1 ver 2.002 by Xavier Boyen                  */
+/*-----------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mcrypto.h"
+#include "elliptic-ffp.h"
+#include "bigdigits.h"
+#include "galois.h"
+#include "sha1.h"
+
+Ep_Point* ep_point_init(Ep_Curve *E)
+{
+	Ep_Point *P = NULL;
+	
+	P = (Ep_Point *)malloc(sizeof(Ep_Point));
+	
+	if(P != NULL) {
+		P->x = (DIGIT_T*)malloc(NBYTE(E->len));
+		P->y = (DIGIT_T*)malloc(NBYTE(E->len));
+	}
+	
+	return P;
+}
+
+int ep_point_member_init(Ep_Curve*E, Ep_Point *P)
+{
+	P->x = mpMalloc(E->len);
+	P->y = mpMalloc(E->len);
+
+	return 0;
+}
+
+void ep_point_free(Ep_Point *P)
+{
+	/* free memory allocaeted for Ep_Point struct including its members */
+	mpFree(P->x);
+	mpFree(P->y);
+	free(P);
+}
+
+void ep_point_member_free(Ep_Point *P)
+{
+	/* free memory allocate for Ep_Point's members only */
+	mpFree(P->x);
+	mpFree(P->y);
+}
+
+Ep_Projective_Point *ep_projective_point_init(Ep_Curve *E)
+{
+	Ep_Projective_Point *P = NULL;
+	
+	P = (Ep_Projective_Point *)malloc(sizeof(Ep_Projective_Point));
+
+	if(P != NULL) {
+		P->X = (DIGIT_T *)malloc(NBYTE(E->len));
+		P->Y = (DIGIT_T *)malloc(NBYTE(E->len));
+		P->Z = (DIGIT_T *)malloc(NBYTE(E->len));
+	}
+
+	return P;
+}
+
+int ep_projective_point_member_init(Ep_Curve*E, Ep_Projective_Point *P)
+{
+	P->X = mpMalloc(E->len);
+	P->Y = mpMalloc(E->len);
+	P->Z = mpMalloc(E->len);
+
+	return 0;
+}
+
+void ep_projective_point_free(Ep_Projective_Point *P)
+{
+	/* free memory allocaeted for Ep_Point struct including its members */
+	mpFree(P->X);
+	mpFree(P->Y);
+	mpFree(P->Z);
+	free(P);
+}
+
+void ep_projective_point_member_free(Ep_Projective_Point *P)
+{
+	/* free memory allocate for Ep_Point's members only */
+	mpFree(P->X);
+	mpFree(P->Y);
+	mpFree(P->Z);
+}
+
+int ep_affine_to_projective(Ep_Curve *E, Ep_Projective_Point *P, Ep_Point *Q)
+{
+	/* first check if Q is inf point, then P is inf point too */
+	if(mpIsZero(Q->x, E->len))
+		return ep_projective_point_zero(E, P);
+	
+	/* How to determine Z ? Z = 1 */
+	mpSetEqual(P->X, Q->x, E->len);
+	mpSetEqual(P->Y, Q->y, E->len);
+	mpSetDigit(P->Z, 1, E->len);
+
+	return 0;
+}
+
+int ep_projective_to_affine(Ep_Curve *E, Ep_Point *P, Ep_Projective_Point *Q)
+{
+	DIGIT_T *t1;
+	DIGIT_T	*t2;
+	
+	/* first check if Q is inf point, then P is inf point too */
+	if(mpIsZero(Q->Z, E->len) || mpIsZero(Q->Y, E->len))
+		return ep_point_zero(E, P);
+	
+	/* x_p = X_q / (Z_q)^2 and y_p = Y_q / (Z_q)^3 */
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->len);
+
+	mpModSquare(t1, Q->Z, E->p, E->len);		/* t1 = (Z_Q)^2 */
+	mpModInv(t2, t1, E->p, E->len);			/* t2 = 1/t1 */
+	mpModMult(P->x, Q->X, t2, E->p, E->len);	/* x_p = t2*X_Q */
+	
+	mpModMult(t2, t1, Q->Z, E->p, E->len);		/* t2 = t1*Z_Q */
+	mpModInv(t1, t2, E->p, E->len);			/* t1 = 1/t2 */
+	mpModMult(P->y, Q->Y, t1, E->p, E->len);	/* y_p = t1*Y_Q */
+
+	mpFree(t1);
+	mpFree(t2);
+
+	return 0;
+}
+
+int ep_point_copy(Ep_Curve *E, Ep_Point *P, Ep_Point *Q)
+{
+	/* Make P = Q */
+	mpSetEqual(P->x, Q->x, E->len);
+	mpSetEqual(P->y, Q->y, E->len);
+	
+	return 0;
+}
+
+int ep_projective_point_copy(Ep_Curve *E, Ep_Projective_Point *P, Ep_Projective_Point *Q)
+{
+	/* Make P = Q in projective coordinate */
+	mpSetEqual(P->X, Q->X, E->len);
+	mpSetEqual(P->Y, Q->Y, E->len);
+	mpSetEqual(P->Z, Q->Z, E->len);
+
+	return 0;
+}
+
+int ep_point_zero(Ep_Curve *E, Ep_Point *P)
+{
+	/* Make P = infinity */
+	mpSetZero(P->x, E->len);
+	mpSetZero(P->y, E->len);
+	
+	return 0;
+}
+
+int ep_projective_point_zero(Ep_Curve *E, Ep_Projective_Point *P)
+{
+	/* Make P = infinity in projective coordinate */
+	mpSetZero(P->X, E->len);
+	mpSetDigit(P->Y, 1, E->len);
+	mpSetZero(P->Z, E->len);
+
+	return 0;
+}
+
+int ep_point_is_zero(Ep_Curve *E, Ep_Point *P)
+{
+	return (mpIsZero(P->y, E->len) && mpIsZero(P->x, E->len));
+}
+
+int ep_projective_point_is_zero(Ep_Curve *E, Ep_Projective_Point *P)
+{
+	return mpIsZero(P->Z, E->len);
+}
+
+int ep_point_is_equal(Ep_Curve *E, Ep_Point *P, Ep_Point *Q)
+{
+	return (mpEqual(P->x, Q->x, E->len) && mpEqual(P->y, Q->y, E->len));
+}
+
+int ep_point_is_inverse(Ep_Curve *E, Ep_Point *P, Ep_Point *Q)
+{
+	/* return true if P = -Q */
+	DIGIT_T *t = mpMalloc(E->len);
+	int ret;
+
+	mpSubtract(t, E->p, P->y, E->len);
+
+	ret = (mpEqual(P->x, Q->x, E->len) && mpEqual(t, Q->y, E->len));
+
+	mpFree(t);
+	
+	return ret;
+}
+
+int ep_point_inv(Ep_Curve *E, Ep_Point *Q, Ep_Point *P)
+{
+	/* Xq = Xp */
+	mpSetEqual(Q->x, P->x, E->len); 
+	
+	/* Yq = -Yp = P - Yp */
+	mpSubtract(Q->y, E->p, P->y, E->len); 
+	
+	return 0;
+}
+
+int ep_point_double(Ep_Curve *E, Ep_Point *Q, Ep_Point *P)
+{
+	DIGIT_T *lamda = NULL;
+	DIGIT_T *T1 = NULL;
+	DIGIT_T *T2 = NULL;
+	DIGIT_T *T3 = NULL;
+	DIGIT_T *T4 = NULL;
+		
+	if(ep_point_is_zero(E, P))
+		return ep_point_zero(E, Q);
+	
+	assert(Q != P);
+
+	/* Allocate memory */
+	lamda = mpMalloc(E->len);
+	T1 = mpMalloc(E->len);
+	T2 = mpMalloc(E->len);
+	T3 = mpMalloc(E->len);
+	T4 = mpMalloc(E->len);
+		
+	/* lamda = 3Xp^2 + a / 2Yp */
+	mpModSquare(T1, P->x, E->p, E->len);		/* T1 = Xp^2 mod p */
+	mpShortModMult(T2, T1, 3, E->p, E->len); 	/* T2 = 3*T1 mod p */
+	mpModAdd(T1, T2, E->a, E->p, E->len);		/* T1 = T2 + a mod p */
+	mpModAdd(T2, P->y, P->y, E->p, E->len);		/* T2 = 2*Yp mod p */
+	mpModInv(T3, T2, E->p, E->len);			/* T3 = T2^-1 mod p */
+	mpModMult(lamda, T1, T3, E->p, E->len);		/* lamda = T1*T2 mod p */
+		
+	/* Xq = lamda^2 - 2Xp */
+	mpModSquare(T1, lamda, E->p, E->len);		/* T1 = lamda^2 mod p */
+	mpModAdd(T2, P->x, P->x, E->p, E->len);		/* T2 = 2*Xp mod p */
+	mpModSubtract(Q->x, T1, T2, E->p, E->len);	/* Xq = T1 - T2 mod p */
+		
+	/* Yq = (Xp - Xq)*lamda - Yp */
+	mpModSubtract(T1, P->x, Q->x, E->p, E->len);	/* T1 = Xp - Xq mod p */
+	mpModMult(T2, lamda, T1, E->p, E->len);		/* T2 = lamda*T1 mod p */
+	mpModSubtract(Q->y, T2, P->y, E->p, E->len);	/* Yq = T2 - Yp mod p */
+	
+	/* Free used memory */
+	mpFree(lamda);
+	mpFree(T1);
+	mpFree(T2);
+	mpFree(T3);
+	
+	return 0;
+}
+
+int ep_projective_point_double(Ep_Curve *E, Ep_Projective_Point* Q, Ep_Projective_Point *P)
+{
+	DIGIT_T *t1 = NULL;
+	DIGIT_T *t2 = NULL;
+	DIGIT_T *t3 = NULL;
+	DIGIT_T *lamda_1 = NULL;
+	DIGIT_T *lamda_2 = NULL;	
+	DIGIT_T *lamda_3 = NULL;
+
+	/* check if P is inf point */
+	if(ep_projective_point_is_zero(E, P))
+		return ep_projective_point_zero(E, Q);
+	
+	assert(Q != P);
+
+	/* ref: Blake, Serousi and Smart's book at page 60 */
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->len);
+	t3 = mpMalloc(E->len);
+	lamda_1 = mpMalloc(E->len);
+	lamda_2 = mpMalloc(E->len);
+	lamda_3 = mpMalloc(E->len);
+	
+	/* Z_Q = 2*Y_P*Z_P */
+	mpModMult(t1, P->Y, P->Z, E->p, E->len);	/* t1 = (Y_P)*(Z_P) */
+	mpShortModMult(Q->Z, t1, 2, E->p, E->len);	/* Z_Q = 2*t1 */
+	
+	/* lamda_1 = 3*(X_P)^2 + a*(Z_P)^4 */
+	mpModSquare(t1, P->X, E->p, E->len);		/* t1 = (X_P)^2 */
+	mpShortModMult(t2, t1, 3, E->p, E->len);	/* t2 = 3*t1 */
+	mpModSquare(t1, P->Z, E->p, E->len);		/* t1 = (Z_P)^2 */
+	mpModSquare(t3, t1, E->p, E->len);		/* t3 = (t1)^2 */
+	mpModMult(t1, t3, E->a, E->p, E->len);		/* t1 = a*t3 */
+	mpModAdd(lamda_1, t1, t2, E->p, E->len);	/* lamda_1 = t1 + t2 */
+
+	/* lamda_2 = 4*X_P*(Y_P)^2 */
+	mpModSquare(t1, P->Y, E->p, E->len);		/* t1 = (Y_P)^2 */
+	mpModMult(t2, t1, P->X, E->p, E->len);		/* t2 = t1*X_P */
+	mpShortModMult(lamda_2, t2, 4, E->p, E->len);	/* lamda_2 = 4*t2 */
+
+	/* X_Q = (lamda_1)^2 - 2*lamda_2 */
+	mpModSquare(t3, lamda_1, E->p, E->len);		/* t3 = (lamda_1)^2 */
+	mpShortModMult(t2, lamda_2, 2, E->p, E->len);	/* t2 = 2*lamda_2 */
+	mpModSubtract(Q->X, t3, t2, E->p, E->len);	/* X_Q = t3 - t2 */
+
+	/* lamda_3 = 8*(Y_P)^4 */
+	mpModSquare(t2, t1, E->p, E->len);		/* t2 = (t1)^2 */
+	mpShortModMult(lamda_3, t2, 8, E->p, E->len);	/* lamda_3 = 8*t2 */
+
+	/* Y_Q = lamda_1*(lamda_2 - X_Q) - lamda_3 */
+	mpModSubtract(t1, lamda_2, Q->X, E->p, E->len);	/* t1 = lamda_2 - X_P */
+	mpModMult(t2, lamda_1, t1, E->p, E->len);	/* t2 = t1*lamda_1 */
+	mpModSubtract(Q->Y, t2, lamda_3, E->p, E->len);	/* done :) */
+	
+	/* free memory */
+	mpFree(t1);
+	mpFree(t2);
+	mpFree(t3);
+	mpFree(lamda_1);
+	mpFree(lamda_2);
+	mpFree(lamda_3);
+	
+	return 0;
+}
+
+int ep_point_add(Ep_Curve *E, Ep_Point *R, Ep_Point *Q, Ep_Point *P)
+{
+	DIGIT_T *lamda = NULL;
+	DIGIT_T *T1 = NULL;
+	DIGIT_T *T2 = NULL;
+	DIGIT_T *T3 = NULL;
+	
+	/* Check that whether P = O */
+	if(ep_point_is_zero(E, P))
+		return ep_point_copy(E, R, Q);
+	
+	/* Check that whether Q = O */
+	if(ep_point_is_zero(E, Q))
+		return ep_point_copy(E, R, P);
+	
+	/* Check whether P = -Q */
+	if(ep_point_is_inverse(E, P, Q))
+		return ep_point_zero(E, R);
+	
+	/* Check whether P = Q */
+	if(ep_point_is_equal(E, P, Q))
+		return ep_point_double(E, R, P);
+	
+	assert(R != Q && R != P);
+
+	/* Allocate Memory */
+	lamda = mpMalloc(E->len);
+	T1 = mpMalloc(E->len);
+	T2 = mpMalloc(E->len);
+	T3 = mpMalloc(E->len);
+	
+	/* lamda = (Yp - Yq) / (Xp - Xq) */
+	mpModSubtract(T1, P->x, Q->x, E->p, E->len);	/* T1 = Xp - Xq mod p */
+	mpModSubtract(T2, P->y, Q->y, E->p, E->len);	/* T2 = Yp - Yq mod p */
+	mpModInv(T3, T1, E->p, E->len);			/* T3 = T1^-1 mod p */
+	mpModMult(lamda, T2, T3, E->p, E->len);		/* lamda = T2*T3 mod p */
+	
+	/* Xr = lamda^2 - Xp - Xq */
+	mpModMult(T1, lamda, lamda, E->p, E->len);	/* T1 = lamda^2 mod p */
+	mpModAdd(T2, P->x, Q->x, E->p, E->len);		/* T2 = Xp + Xq mod p */
+	mpModSubtract(R->x, T1, T2, E->p, E->len);	/* Xr = T1 - T2 mod p */
+	
+	/* Yr = (Xp - Xr)*lamda - Yq */
+	mpModSubtract(T1, P->x, R->x, E->p, E->len);	/* T1 = Xp - Xr mod p */
+	mpModMult(T2, T1, lamda, E->p, E->len);		/* T2 = T1*lamda mod p */
+	mpModSubtract(R->y, T2, P->y, E->p, E->len);	/* Yr = T2 - Yp mod p */
+	
+	/* Free used memory */
+	mpFree(lamda);
+	mpFree(T1);
+	mpFree(T2);
+	mpFree(T3);
+	
+	return 0;
+}
+	
+int ep_projective_point_add(Ep_Curve *E, Ep_Projective_Point* R, \
+		                         Ep_Projective_Point *Q, \
+					 Ep_Projective_Point *P)
+{
+	DIGIT_T *lamda_1;	
+	DIGIT_T *lamda_2;
+	DIGIT_T *lamda_3;
+	DIGIT_T *lamda_4;
+	DIGIT_T *lamda_5;
+	DIGIT_T *lamda_6;
+	DIGIT_T *lamda_7;
+	DIGIT_T *lamda_8;
+	DIGIT_T *lamda_9;
+	
+	DIGIT_T *t1;
+	DIGIT_T *t2;
+	DIGIT_T *t3;		
+
+	/* first check if either P or Q is inf point */
+	if(mpIsZero(Q->Z, E->len))
+		return ep_projective_point_copy(E, R, P);
+	if(mpIsZero(P->Z, E->len))
+		return ep_projective_point_copy(E, R, Q);
+	
+	assert(R != Q && R != P);
+
+	/* do add and check if P = -Q along the way */	
+	/* ref: Blake, Serousi and Smart's "ECC" book, page 59 */
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->len);
+	t3 = mpMalloc(E->len);
+	lamda_1 = mpMalloc(E->len);
+	lamda_2 = mpMalloc(E->len);
+	lamda_3 = mpMalloc(E->len);
+	lamda_4 = mpMalloc(E->len);
+	lamda_5 = mpMalloc(E->len);
+	lamda_6 = mpMalloc(E->len);
+	lamda_7 = mpMalloc(E->len);
+	lamda_8 = mpMalloc(E->len);
+	lamda_9 = mpMalloc(E->len);
+	
+	/* lamda_1 = (X_P)*(Z_Q)^2 */
+	mpModSquare(t1, Q->Z, E->p, E->len);		/* t1 = (Z_Q)^2 */
+	mpModMult(lamda_1, P->X, t1, E->p, E->len);	/* lamda_1 = t1*X_P */
+
+	/* lamda_2 = (X_Q)*(Z_P)^2 */
+	mpModSquare(t1, P->Z, E->p, E->len);		/* t1 = (Z_P)^2 */
+	mpModMult(lamda_2, Q->X, t1, E->p, E->len);	/* lamda_2 = t1*X_Q */
+	
+	/* lamda_3 = lamda_1 - lamda_2 */
+	mpModSubtract(lamda_3, lamda_1, lamda_2, E->p, E->len);
+
+	/* lamda_4 = (Y_P)*(Z_Q)^3 */
+	mpModSquare(t1, Q->Z, E->p, E->len);		/* t1 = (Z_Q)^2 */
+	mpModMult(t2, t1, Q->Z, E->p, E->len);		/* t2 = t1*Z_Q */
+	mpModMult(lamda_4, P->Y, t2, E->p, E->len);	/* lamda_4 = t2*Y_P */
+ 	
+	/* lamda_5 = (Y_Q)*(Z_P)^3 */
+	mpModSquare(t1, P->Z, E->p, E->len);		/* t1 = (Z_P)^2 */
+	mpModMult(t2, t1, P->Z, E->p, E->len);		/* t2 = t1*Z_P */
+	mpModMult(lamda_5, Q->Y, t2, E->p, E->len);	/* lamda_4 = t2*Y_Q */
+
+	/* lamda_6 = lamda_4 - lamda_5 */
+	mpModSubtract(lamda_6, lamda_4, lamda_5, E->p, E->len);
+
+	if(mpIsZero(lamda_3, E->len)){
+		if(mpIsZero(lamda_6, E->len))
+			goto p_and_q_are_same;
+		else {
+			ep_projective_point_zero(E, R);
+			goto free_mem_n_bye;
+		}
+	}
+	
+	/* lamda_7 = lamda_1 + lamda_2 */
+	mpModAdd(lamda_7, lamda_1, lamda_2, E->p, E->len);
+
+	/* lamda_8 = lamda_4 + lamda_5 */		
+	mpModAdd(lamda_8, lamda_4, lamda_5, E->p, E->len);
+
+	/* Z_R = (Z_P)*(Z_Q)*lamda_3 */
+	mpModMult(t1, P->Z, Q->Z, E->p, E->len);	/* t1 = (Z_P)*(Z_Q) */
+	mpModMult(R->Z, t1, lamda_3, E->p, E->len);	/* Z_R = t1*lamda_3 */
+
+	/* X_R = (lamda_6)^2 - (lamda_7)*(lamda_3)^2 */
+	mpModSquare(t1, lamda_6, E->p, E->len);		/* t1 = (lamda_6)^2 */
+	mpModSquare(t2, lamda_3, E->p, E->len);		/* t2 = (lamda_3)^2 */
+	mpModMult(t3, lamda_7, t2, E->p, E->len);	/* t3 = t2*lamda_7 */
+	mpModSubtract(R->X, t1, t3, E->p, E->len);	/* X_R = t1 - t3 */
+
+	/* lamda_9 = (lamda_7)*(lamda_3)^2 - 2X_R */
+	mpShortModMult(t1, R->X, 2, E->p, E->len);	/* t1 = 2*X_R */
+	mpModSubtract(lamda_9, t3, t1, E->p, E->len);	/* lamda_9 = t3 - t1 */
+
+	/* Y_R = [((lamda_9)*(lamda_6) - (lamda_8)*(lamda_3)^3)] / 2 */
+	mpModMult(t1, lamda_9, lamda_6, E->p, E->len);	/* t1 = (lamda_9)*(lamda_6) */
+	mpModMult(t3, t2, lamda_3, E->p, E->len);	/* t3 = t2*lamda_3 */
+	mpModMult(t2, lamda_8, t3, E->p, E->len);	/* t2 = lamda_8*t3 */
+	mpModSubtract(t3, t1, t2, E->p, E->len);
+	
+	/* need to compute inverse of 2 mod p, should be precomputed otherwise, no gain */
+	mpSetDigit(t1, 2, E->len);
+	mpModInv(t2, t1, E->p, E->len);			/* t2 = 2^(-1) mod p */
+	mpModMult(R->Y, t3, t2, E->p, E->len);
+
+	goto free_mem_n_bye;
+p_and_q_are_same:
+	ep_projective_point_double(E, R, P);
+
+free_mem_n_bye:
+	mpFree(t1);	
+	mpFree(t2);
+	mpFree(t3);
+	mpFree(lamda_1);
+	mpFree(lamda_2);
+	mpFree(lamda_3);
+	mpFree(lamda_4);
+	mpFree(lamda_5);
+	mpFree(lamda_6);
+	mpFree(lamda_7);
+	mpFree(lamda_8);
+	mpFree(lamda_9);
+
+	return 0;	
+}
+
+int ep_mixed_point_add(Ep_Curve *E, Ep_Projective_Point* R, \
+		                    Ep_Projective_Point *Q, \
+				    Ep_Point *P)
+{
+	/* or ep_projective_point_add with P converted to projective coordinate will do */ 	
+	Ep_Projective_Point *T = NULL;
+
+	T = ep_projective_point_init(E);
+	ep_affine_to_projective(E, T, P);
+	ep_projective_point_add(E, R, Q, T);
+
+	ep_projective_point_free(T);
+
+	return 0;
+}
+int ep_point_sub(Ep_Curve *E, Ep_Point *R, Ep_Point *P, Ep_Point *Q)
+{
+	Ep_Point *T;
+		
+	T = ep_point_init(E);
+	
+	ep_point_inv(E, T, Q);	
+	ep_point_add(E, R, P, T);
+	
+	ep_point_free(T);
+	
+	return 0;
+}
+
+int ep_point_mul(Ep_Curve *E, Ep_Point *Q, Ep_Point *P, DIGIT_T *k, UINT klen)
+{
+	/* scalar multiplication using binary method */
+	DIGIT_T mask;
+	int i;
+	Ep_Point R;
+	
+	assert(Q != P);
+
+	/* Allocate temp memory */
+	ep_point_member_init(E, &R);
+	ep_point_zero(E, &R);
+		
+	/* Set Q = Infinity */
+	ep_point_zero(E, Q);
+
+	while(klen--){
+		mask = HIBITMASK;
+		for(i=BITS_PER_DIGIT-1;i>=0;i--){
+			ep_point_double(E, &R, Q);
+			if(k[klen] & mask){
+				ep_point_add(E, Q, &R, P);
+			}
+			else{
+				mpSetEqual(Q->x, R.x, E->len);
+				mpSetEqual(Q->y, R.y, E->len);
+			}		
+			mask >>= 1;
+		}
+	}
+	
+	ep_point_member_free(&R);
+
+	return 0;
+}
+
+int ep_projective_point_mul(Ep_Curve *E, Ep_Projective_Point* Q, \
+		                         Ep_Projective_Point *P, DIGIT_T *k, UINT klen)
+{
+	return 0;
+}
+
+int ep_point_gen(Ep_Curve *E, Ep_Point *P)
+{
+	DIGIT_T *u = NULL;
+	DIGIT_T *t = NULL;
+	DIGIT_T *Q = NULL;
+	DIGIT_T *V = NULL;
+	DIGIT_T *u1 = NULL;
+	UINT S;
+	
+	/* allocate temporary memory */
+	u = mpMalloc(E->len);
+	t = mpMalloc(E->len);
+	u1 = mpMalloc(E->len);
+	Q = mpMalloc(E->len);
+	V = mpMalloc(E->len);
+	
+	while(1){
+		/* generate x-coordinate at random */
+		mpMakeRandom(u, E->len);
+		mpModulo(P->x, u, E->len, E->p, E->len);
+					
+		/* compute u = Xp^3 + a*Xp + b mod p */
+		mpModSquare(u1, P->x, E->p, E->len);
+		mpModMult(u, u1, P->x, E->p, E->len);		/* u = (X_P)^3 mod p */
+		mpModMult(t, P->x, E->a, E->p, E->len);		/* t = a*X_P mod p */
+		mpModAdd(u1, u, t, E->p, E->len);		/* u1 = u + t mod p */
+		mpModAdd(u, u1, E->b, E->p, E->len);		/* u = u1 + b mod p */
+		
+		/* Compute square root of u */
+		mpModSquareRootPre(&S, Q, V, E->p, E->len);
+		mpModInv(u1, u, E->p, E->len);
+	
+		if(mpModSquareRoot(t, u, E->p, S, Q, V, u1, E->len)==0)
+			break;
+	}
+	
+	if(mpIsZero(t, E->len))	{
+		mpSetZero(P->y, E->len);
+		goto free_n_bye;
+	}
+	
+	/* Generate a random bit to choose y-coordinate */
+	u[0] = spPseudoRand(0, MAX_DIGIT);
+	if(ISEVEN(u[0]))
+		mpSetEqual(P->y, t, E->len);
+	else
+		mpModSubtract(P->y, E->p, t, E->p, E->len);
+			
+	/* free used memory */
+free_n_bye:
+	free(u);
+	free(t);
+	free(Q);
+	free(V);
+	free(u1);
+	
+	return 0;
+}
+
+/* Utility Functions */
+int ep_load_curve(const char *fname, Ep_Curve *E)
+{
+	FILE *f;
+	char s[EP_NPARAM][EP_MAX_LINE_LEN];
+	UINT nread;
+	UINT i;
+	
+	if((f=fopen(fname, "r")) == NULL)
+		return -1;
+	
+	/* reading data */
+	memset(s, 0x00, EP_NPARAM*EP_MAX_LINE_LEN);
+	for(i=0;i<EP_NPARAM;i++){
+		if(feof(f)){
+			fclose(f);
+			return -1;
+		}
+		fgets(s[i], EP_MAX_LINE_LEN, f);
+		
+		/* be careful with dos/win32 newline+linefeed */	
+		s[i][strlen(s[i])-1] = '\0';
+	}
+	fclose(f);
+	
+	/* Collecting data */
+	E->len = (UINT)atoi(s[1]);
+	if((E->p=(DIGIT_T*)mpHex2Bin(s[2], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	if((E->a=(DIGIT_T*)mpHex2Bin(s[3], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	if((E->b=(DIGIT_T*)mpHex2Bin(s[4], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	if((E->G.x=(DIGIT_T*)mpHex2Bin(s[5], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	if((E->G.y=(DIGIT_T*)mpHex2Bin(s[6], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	E->rlen = (UINT)atoi(s[7]);
+	if((E->r=(DIGIT_T*)mpHex2Bin(s[8], NBYTE(E->rlen), &nread))==NULL)
+		return -1;
+	E->h = (DIGIT_T)atoi(s[9]);
+	
+	return 0;
+}
+
+
+int ep_save_curve(const char *fname, Ep_Curve *E)
+{
+	FILE *f;
+	
+	if((f=fopen(fname, "w")) == NULL)
+		return -1;
+	
+	fprintf(f,"------------------------BEGIN ELLIPTIC CURVE PARAMETERS-------------------------\n");
+	fprintf(f,"%d\n", E->len);
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->p, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->a, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->b, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->G.x, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->G.y, NBYTE(E->len)));
+	fprintf(f,"%d\n", E->rlen);
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)E->r, NBYTE(E->rlen)));
+	fprintf(f,"%lu\n", E->h);
+	fprintf(f,"-----------------------END OF ELLIPTIC CURVE PARAMETERS-------------------------\n");
+	
+	fclose(f);
+	
+	return 0;
+}
+
+int ep_load_point(const char *fname, Ep_Curve *E, Ep_Point *P)
+{
+	FILE *f;
+	char s[4][EP_MAX_LINE_LEN];
+	UINT nread;
+	UINT i;
+	
+	if((f=fopen(fname, "r")) == NULL)
+		return -1;
+	
+	/* reading data */
+	memset(s, 0x00, 4*EP_MAX_LINE_LEN);
+	for(i=0;i<4;i++){
+		if(feof(f)){
+			fclose(f);
+			return -1;
+		}
+		fgets(s[i], EP_MAX_LINE_LEN, f);
+		s[i][strlen(s[i])-1] = '\0';
+	}
+	fclose(f);
+	
+	/* Collecting data */
+	if((P->x=(DIGIT_T*)mpHex2Bin(s[3], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	if((P->y=(DIGIT_T*)mpHex2Bin(s[4], NBYTE(E->len), &nread))==NULL)
+		return -1;
+	
+	return 0;
+}
+
+int ep_save_point(const char *fname, Ep_Curve *E, Ep_Point *P)
+{
+	FILE *f;
+	
+	if((f=fopen(fname, "w")) == NULL)
+		return -1;
+	
+	fprintf(f,"-----------------------BEGIN ELLIPTIC CURVE POINT COORDINATES-------------------------\n");
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)P->x, NBYTE(E->len)));
+	fprintf(f,"%s\n", mpBin2Hex((BYTE *)P->y, NBYTE(E->len)));
+	fprintf(f,"-----------------------END OF ELLIPTIC CURVE POINT COORDINATES------------------------\n");
+	
+	fclose(f);
+	
+	return 0;
+}
+
+int ep_is_on_curve(Ep_Curve *E, Ep_Point *P)
+{
+	/* check whether a point lie on a curve */
+	DIGIT_T *t = NULL;
+	DIGIT_T *r = NULL;
+	DIGIT_T *u = NULL;
+	DIGIT_T *v = NULL;
+	DIGIT_T *w = NULL;
+	int ret = 0;
+		
+	/* Check that whether P = O */
+	if(mpIsZero(P->x, E->len) && mpIsZero(P->y, E->len))
+		return 1;
+	
+	
+	t = mpMalloc(E->len);
+	r = mpMalloc(E->len);
+	u = mpMalloc(E->len);
+	v = mpMalloc(E->len);
+	w = mpMalloc(E->len);
+	
+	mpModSquare(t, P->x, E->p, E->len);
+	mpModMult(u, t, P->x, E->p, E->len);	/* u = x^3 mod p */
+	
+	mpModSquare(v, P->y, E->p, E->len);	/* v = y^2 mod p */
+	
+	mpModMult(t, P->x, E->a, E->p, E->len);	/* t = a*x mod p */
+	
+	mpModAdd(r, t, E->b, E->p, E->len);	/* r = t + b mod p */
+	
+	mpModAdd(w, u, r, E->p, E->len);	/* w = u + r mod p */
+	
+	if(mpCompare(v, w, E->len)==0)
+		ret = 1;
+	
+	mpFree(t);
+	mpFree(r);
+	mpFree(u);
+	mpFree(v);
+	mpFree(w);
+	
+	return ret;
+}
+
+Ep_Curve *ep_curve_init(DIGIT_T *p, UINT plen, DIGIT_T *a, DIGIT_T *b, DIGIT_T *r, UINT rlen, Ep_Point *G)
+{
+	/* allocate memory for Ep_Curve struct including its members */
+	/* curve is : y^2 = x^3 + ax + b (mod p) with G is generator */
+	Ep_Curve *E;
+	
+	if((E = (Ep_Curve *)malloc(sizeof(Ep_Curve))) == NULL)
+		return NULL;
+	E->len = plen;
+	E->rlen = rlen;
+	
+	if((E->p = mpMalloc(plen)) == NULL){
+		free(E);
+		return NULL;
+	}
+	
+	if((E->a = mpMalloc(plen)) == NULL){
+		free(E);
+		free(p);
+		return NULL;
+	}
+	
+	if((E->b = mpMalloc(plen)) == NULL){
+		free(E);
+		free(p);
+		free(a);
+		return NULL;
+	}
+
+	if((E->r = mpMalloc(rlen)) == NULL){
+		free(E);
+		free(p);
+		free(a);
+		free(b);
+		return NULL;
+	}
+
+	if(ep_point_member_init(E, &E->G) !=0 ){
+		free(E);
+		free(p);
+		free(a);
+		free(b);
+		free(r);
+		return NULL;
+	}
+	
+	mpSetEqual(E->p, p, plen);
+	mpSetEqual(E->a, a, plen);
+	mpSetEqual(E->b, b, plen);
+	mpSetEqual(E->r, r, rlen);
+	ep_point_copy(E, &E->G, G);
+
+	return E;
+}
+
+void ep_curve_free(Ep_Curve *E)
+{
+	/* free memory allocated to Ep_Curve struct including its members */
+	mpFree(E->p);
+	mpFree(E->a);
+	mpFree(E->b);
+	mpFree(E->r);
+	ep_point_member_free(&E->G);
+	free(E);
+}
+
+Ep_Curve *ep_curve_init2(void)
+{
+	/* allocate memory for Ep_Curve struct only */
+	return (Ep_Curve *)malloc(sizeof(Ep_Curve));
+}
+
+void ep_curve_member_free(Ep_Curve *E)
+{
+	/* free memory allocated to Ep_Curve's members only */
+	mpFree(E->p);
+	mpFree(E->a);
+	mpFree(E->b);
+	mpFree(E->r);
+	ep_point_free(&E->G);
+}
+
+int ep_type1_curve_gen(Ep_Curve *E, UINT n)
+{
+	/* the following code follows IBCS#1 version 2.002 by Xavier Boyen */
+	UINT plen = n/2, qlen = n/32 + 128;
+	
+	DIGIT_T *p = NULL;
+	DIGIT_T *q = NULL;
+	DIGIT_T *r = NULL;
+	UINT rlen, rdlen;
+	DIGIT_T *t = NULL;
+	DIGIT_T *t1 = NULL;
+	UINT i; 
+	DIGIT_T mask;
+	Ep_Point *P = NULL;
+	UINT ret;
+	
+	/* digit length of prime p */
+	E->len = NDIGIT(plen);
+
+	/* generate qlen-bit Solinas prime q */
+	q = mpMalloc(E->len);	
+	if((ret=mpSolinasPrime(q, E->len, qlen)) == 0){
+		/* failed to find Solinas prime */
+		free(q);
+		return 0;
+	}
+	
+	/* curve is y^2 = x^3 + 1 : a = 0 and b = 1 */	
+	E->a = mpMalloc(E->len);
+	mpSetZero(E->a, E->len);	
+	E->b = mpMalloc(E->len);
+	mpSetDigit(E->b, 1, E->len); 
+	
+	/* E->r now stores order q of subgroup of E/F_p */	
+	E->rlen = NDIGIT(qlen); 
+	E->r = q;	
+	E->h = ret;	
+	
+	/* generate p = 12rq - 1, where r is randomly chosen => make p mod 12 = 11 */
+	p = mpMalloc(E->len);
+	t = mpMalloc(E->len);
+	t1 = mpMalloc(E->len);
+	r = mpMalloc(E->len);	
+	
+	/* use same notation as in ibcs#1 v2.002, dont confuse with E->r and E->rlen */
+	rlen = plen - qlen - 4;
+	
+	/* 12 takes 4 bit, so rlen = plen - qlen - 4, then convert to # of digits */
+	rdlen = (rlen % BITS_PER_DIGIT) ? (rlen / BITS_PER_DIGIT) + 1 : (rlen / BITS_PER_DIGIT);
+
+try_other_r:
+	mpSetZero(r, E->len);
+	mpMakeRandom(r, rdlen);
+	
+	/* now make r actually only rlen-bit */
+	for(i = 0, mask = 0x00; i<(rlen % BITS_PER_DIGIT); i++, mask = (mask << 1) | 0x00000001);
+	r[rdlen-1] &= mask ? mask : MAX_DIGIT;
+	
+	mpShortMult(t1, r, 12, E->len);	/* t1 = 12r */	
+	mpMultiply(t, q, t1, E->len);   /* t2 = 12rq = t1*q */ 		
+	mpShortSub(p, t, 1, E->len);    /* p = 12rq - 1 = t2 - 1*/
+	
+	/* test if p is a prime number using Miller-Rabin test, if not try different r */
+	if(!mpIsPrime(p, E->len, N_TEST_PRIME))
+		goto try_other_r;
+	
+	E->p = p;
+
+	/* compute base point of order q, G = [12r]P where P is randomly chosen */
+	ep_point_member_init(E, &E->G);
+	P = ep_point_init(E);
+	ep_point_gen(E, P);
+
+	ep_point_mul(E, &E->G, P, t1, E->len);
+	
+	/* free memory */
+	ep_point_free(P);
+	mpFree(t);
+	mpFree(t1);
+	mpFree(r);
+
+	return ret;
+}
+
+int ep_type1_curve_validate(Ep_Curve *E)
+{
+	DIGIT_T eleven;	
+	DIGIT_T *t1 = NULL;
+	DIGIT_T *t2 = NULL;
+	Ep_Point *P;
+	int ret;
+		
+	/* first check if p and r are prime */	
+	if(!mpIsPrime(E->p, E->len, N_TEST_PRIME)){
+		mcrypto_msg("p is not prime\n");
+		return 0;
+	}
+
+	if(!mpIsPrime(E->r, E->rlen, N_TEST_PRIME)){
+		mcrypto_msg("q is not prime\n");
+		return 0; 
+	}
+ 
+	/* check if p mod 12 = 11? */	
+	if((eleven = mpShortMod(E->p, 12, E->len)) != 11){
+		mcrypto_msg("p mod 12 is not 11\n");		
+		return 0;
+	}
+		
+	/* check if G lies on curve */
+	if(!ep_is_on_curve(E, &E->G)){
+		mcrypto_msg("G is not on curve\n");
+		return 0;
+	}
+
+	/* check if r | p+1 */
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->rlen);
+	mpShortAdd(t1, E->p, 1, E->len);
+	mpModulo(t2, t1, E->len, E->r, E->rlen);
+	if(!mpIsZero(t2, E->rlen)){
+		mpFree(t1);
+		mpFree(t2);
+		mcrypto_msg("r does not divide p+1\n");
+		return 0;
+	}
+	
+	/* check if (r+1)G = G */
+	P = ep_point_init(E);
+	mpShortAdd(t1, E->r, 1, E->rlen);
+	ep_point_mul(E, P, &E->G, t1, E->rlen);
+	ret = mpEqual(P->x, E->G.x, E->rlen) && mpEqual(P->y, E->G.y, E->rlen);
+		
+	mpFree(t1);
+	mpFree(t2);		
+	ep_point_free(P);
+	
+	return ret;
+}
+
+int ep_eval_vertical1(Ep_Curve *E, GF_ELE r, Ep_Point *A, Ep2_Point *B)
+{
+	/* evaluate the divisor of the vertical line which goes through A at B */
+	/* always assume that r is two-digit, r_1|r_0 ~ r(x) = r_1*x+r_0 */
+	
+	/* r = x_B - x_A */	
+	mpSetEqual(r[1], B->x[1], E->len);
+	mpModSubtract(r[0], B->x[0], A->x, E->p, E->len); 
+
+	return 0;
+}
+
+int ep_eval_vertical2(Ep_Curve *E, GF_ELE r, Ep_Projective_Point *A, Ep2_Point *B)
+{
+	Ep_Point *T = ep_point_init(E);
+	
+	ep_projective_to_affine(E, T, A);
+	ep_eval_vertical1(E, r, T, B);
+
+	ep_point_free(T);
+
+	return 0;
+}
+
+int ep_eval_tangent1(Ep_Curve *E, GF_ELE r, Ep_Point *A, Ep2_Point *B)
+{
+	/* evaluate the divisor of the tangent line to A, at B */	
+	/* always assume that r is two-digit, r_1|r_0 ~ r(x) = r_1*x+r_0 */	
+	DIGIT_T *a = NULL;
+	DIGIT_T *b = NULL;		
+	DIGIT_T *c = NULL;	
+	DIGIT_T *t1 = NULL;	
+	DIGIT_T *t2 = NULL;	
+	DIGIT_T *t3 = NULL;
+
+	/* evaluate the divisor of the tangent line to A, at B */
+	if(ep_point_is_zero(E, A)){
+		/* r(x) = 1 */
+		mpSetZero(r[1], E->len);
+		mpSetDigit(r[0], 1, E->len);
+		return 0;
+	}
+	
+	if(mpIsZero(A->y, E->len))
+		return ep_eval_vertical1(E, r, A, B);
+
+	a = mpMalloc(E->len);
+	b = mpMalloc(E->len);
+	c = mpMalloc(E->len);
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->len);
+	t3 = mpMalloc(E->len);
+
+	mpModSquare(t1, A->x, E->p, E->len);	/* t1 = (x_A)^2 */
+	mpShortSub(t2, E->p, 3, E->len);	/* t2 = -3 */
+	mpModMult(a, t1, t2, E->p, E->len);	/* a = t1*t2 */
+
+	mpShortModMult(b, A->y, 2, E->p, E->len);	/* b = 2*y_A */
+	
+	mpSubtract(t1, E->p, b, E->len);	/* t1 = -b */	
+	mpModMult(t2, t1, A->y, E->p, E->len);	/* t2 = t1*y_A */
+
+	mpSubtract(t1, E->p, a, E->len);	/* t1 = -a */
+	mpModMult(t3, t1, A->x, E->p, E->len);	/* t3 = t1*x_A */
+	
+	mpModAdd(c, t2, t3, E->p, E->len);	/* c = t2+t3 */
+
+	/* compute r = a*x_B + b*y_B + c */
+	mpModMult(t1, a, B->x[1], E->p, E->len);
+	mpModMult(t2, b, B->y[1], E->p, E->len);
+	mpModAdd(r[1], t1, t2, E->p, E->len);
+
+	mpModMult(t1, a, B->x[0], E->p, E->len);
+	mpModMult(t2, b, B->y[0], E->p, E->len);
+	mpModAdd(t3, t1, t2, E->p, E->len);
+	mpModAdd(r[0], t3, c, E->p, E->len);
+
+	/* free memory */
+	mpFree(t1);
+	mpFree(t2);
+	mpFree(t3);
+	mpFree(a);
+	mpFree(b);
+	mpFree(c);
+	
+	return 0;
+}
+
+int ep_eval_tangent2(Ep_Curve *E, GF_ELE r, Ep_Projective_Point *A, Ep2_Point *B)
+{
+	Ep_Point *T = ep_point_init(E);
+	
+	ep_projective_to_affine(E, T, A);
+	ep_eval_tangent1(E, r, T, B);
+
+	ep_point_free(T);
+
+	return 0;
+}
+
+int ep_eval_line(Ep_Curve *E, GF_ELE r, Ep_Point *A1, Ep_Point *A2, Ep2_Point *B)
+{
+	/* evaluate the divisor of the line goes through A1-A2, at B */
+	/* this is another helper function for computing Tate's pairing */
+	/* always assume that r is two-digit, r_1|r_0 ~ r(x) = r_1*x+r_0 */
+	DIGIT_T *a = NULL;
+	DIGIT_T *b = NULL;		
+	DIGIT_T *c = NULL;	
+	DIGIT_T *t1 = NULL;	
+	DIGIT_T *t2 = NULL;	
+	DIGIT_T *t3 = NULL;
+	
+	/* check special cases */	
+	if(ep_point_is_zero(E, A1))
+		return ep_eval_vertical1(E, r, A2, B);
+		
+	if(ep_point_is_zero(E, A2))
+		return ep_eval_vertical1(E, r, A1, B);
+
+	if(ep_point_is_inverse(E, A1, A2))
+		return ep_eval_vertical1(E, r, A1, B);
+
+	if(ep_point_is_equal(E, A1, A2))
+		return ep_eval_tangent1(E, r, A1, B);
+	
+	a = mpMalloc(E->len);
+	b = mpMalloc(E->len);
+	c = mpMalloc(E->len);
+	t1 = mpMalloc(E->len);
+	t2 = mpMalloc(E->len);
+	t3 = mpMalloc(E->len);
+
+	mpModSubtract(a, A1->y, A2->y, E->p, E->len);	/* a = y_A1 - y_A2 */
+
+	mpModSubtract(b, A2->x, A1->x, E->p, E->len);	/* b = x_A2 - x_A1 */
+
+	mpSubtract(t1, E->p, b, E->len);	/* t1 = -b */	
+	mpModMult(t2, t1, A1->y, E->p, E->len);	/* t2 = t1*y_A1 */	
+	mpSubtract(t1, E->p, a, E->len);	/* t1 = -a */
+	mpModMult(t3, t1, A1->x, E->p, E->len);	/* t3 = t1*x_A1 */
+	
+	mpModAdd(c, t2, t3, E->p, E->len);	/* c = t2+t3 */
+
+	/* compute r = a*x_B + b*y_B + c */
+	mpModMult(t1, a, B->x[1], E->p, E->len);
+	mpModMult(t2, b, B->y[1], E->p, E->len);
+	mpModAdd(r[1], t1, t2, E->p, E->len);
+
+	mpModMult(t1, a, B->x[0], E->p, E->len);
+	mpModMult(t2, b, B->y[0], E->p, E->len);
+	mpModAdd(t3, t1, t2, E->p, E->len);
+	mpModAdd(r[0], t3, c, E->p, E->len);
+
+	/* free memory */
+	mpFree(t1);
+	mpFree(t2);
+	mpFree(t3);
+	mpFree(a);
+	mpFree(b);
+	mpFree(c);
+
+	return 0;
+}
+
+int tate_pairing_init(Tate_Pairing_Info *tate, UINT n)
+{
+	if((tate->E = (Ep_Curve *)malloc(sizeof(Ep_Curve))) == NULL)
+		return -1;
+
+	if(ep_type1_curve_gen(tate->E, n) == 0){
+		free(tate->E);
+		return -1;
+	} 
+	
+	tate->a = n/32 + 127;
+	tate->b = tate->E->h;
+	
+	/* compute final exponentiation exponent eta */
+	tate->eta_len = 2*tate->E->len - tate->E->rlen;
+	if((tate->eta = mpMalloc(tate->eta_len)) == NULL){
+		ep_curve_free(tate->E);
+		return -1;
+	}
+
+	DIGIT_T *t1 = mpMalloc(2*tate->E->len);
+	DIGIT_T *t2 = mpMalloc(2*tate->E->len);
+	mpSquare(t1, tate->E->p, tate->E->len);		/* t1 = p^2 */
+	mpShortSub(t2, t1, 1, tate->E->len);		/* t2 = t1- 1 */
+	mpDivide(t1, tate->eta, t2, 2*tate->E->len, tate->E->r, tate->E->rlen);		/* eta = t2 / q */
+	mpFree(t1);
+	mpFree(t2);
+	
+	if((tate->gfp2 = gf_init(2, tate->E->p, tate->E->len)) == NULL){
+		ep_curve_free(tate->E);
+		return -1;
+	}
+	
+	/* n(x) = x^2 + 1 */
+	mpSetDigit(tate->gfp2->n[0], 1, tate->gfp2->plen);
+	mpSetDigit(tate->gfp2->n[1], 0, tate->gfp2->plen);
+	mpSetDigit(tate->gfp2->n[2], 1, tate->gfp2->plen);
+
+	return 0;
+}
+
+int tate_pairing_init2(Tate_Pairing_Info *tate, const char *curve_fname)
+{
+	Ep_Curve *E;
+
+	if((E = ep_curve_init2()) == NULL)
+		return -1;
+
+	if(ep_load_curve(curve_fname, E) == -1){
+		free(E);
+		return -1;
+	}
+	
+	/* verify that E is type-1 curve intended for Tate pairing computation in IBCS#1 by Xavier Boyen */
+	if(!ep_type1_curve_validate(E)){
+		ep_curve_free(E);
+		return -1;
+	}
+
+	tate->E = E;
+
+	/* rediscover a and b */
+	tate->a = mpBitLength(E->r, E->rlen) - 1;
+	tate->b = E->h;
+
+	tate->eta_len = 2*tate->E->len - tate->E->rlen;
+	if((tate->eta = mpMalloc(tate->eta_len)) == NULL){
+		ep_curve_free(tate->E);
+		return -1;
+	}
+
+	DIGIT_T *t1 = mpMalloc(2*tate->E->len);
+	DIGIT_T *t2 = mpMalloc(2*tate->E->len);
+	mpSquare(t1, tate->E->p, tate->E->len);		/* t1 = p^2 */
+	mpShortSub(t2, t1, 1, tate->E->len);		/* t2 = t1- 1 */
+	mpDivide(t1, tate->eta, t2, 2*tate->E->len, tate->E->r, tate->E->rlen);		/* eta = t2 / q */
+	mpFree(t1);
+	mpFree(t2);
+
+	if((tate->gfp2 = gf_init(2, tate->E->p, tate->E->len)) == NULL){
+		ep_curve_free(tate->E);
+		return -1;
+	}
+	
+	/* n(x) = x^2 + 1 */
+	mpSetDigit(tate->gfp2->n[0], 1, tate->gfp2->plen);
+	mpSetDigit(tate->gfp2->n[1], 0, tate->gfp2->plen);
+	mpSetDigit(tate->gfp2->n[2], 1, tate->gfp2->plen);
+
+	return 0;
+}
+
+int tate_pairing_eval(Tate_Pairing_Info *tate, GF_ELE res, Ep_Point *A, Ep2_Point *B)
+{
+	/* compute tate's pairing, ref: IBCS#1 ver. 2.002 by Xavier Boyen */ 
+	GF_ELE v_num; 
+	GF_ELE v_den;
+	GF_ELE t_num;
+	GF_ELE t_den;
+	Ep_Projective_Point *V;
+	Ep_Point *V_a;
+	Ep_Point *V_b;
+
+	register int n;
+
+	GF_ELE temp;
+	Ep_Projective_Point *T;
+	Ep_Point *R;
+
+	/* temporary variables */
+	temp = gf_ele_init(tate->gfp2, tate->gfp2->k);	
+	T = ep_projective_point_init(tate->E);
+	R = ep_point_init(tate->E);
+
+	/* step1. intialization */
+	v_num = gf_ele_init(tate->gfp2, tate->gfp2->k); gf_ele_unit(tate->gfp2, v_num, tate->gfp2->k);
+	v_den = gf_ele_init(tate->gfp2, tate->gfp2->k); gf_ele_unit(tate->gfp2, v_den, tate->gfp2->k);
+	t_num = gf_ele_init(tate->gfp2, tate->gfp2->k); gf_ele_unit(tate->gfp2, t_num, tate->gfp2->k);
+	t_den = gf_ele_init(tate->gfp2, tate->gfp2->k); gf_ele_unit(tate->gfp2, t_den, tate->gfp2->k);
+
+	V = ep_projective_point_init(tate->E);
+	ep_affine_to_projective(tate->E, V, A);
+
+	V_a = ep_point_init(tate->E);
+	V_b = ep_point_init(tate->E);
+
+	/* step 2. calculate 2^b contribution */
+	for(n=0; n<tate->b; n++){
+		gf_ele_sqr(tate->gfp2, t_num, t_num, tate->gfp2->k);	/* t_num = (t_num)^2 in F_p^2 */
+		gf_ele_sqr(tate->gfp2, t_den, t_den, tate->gfp2->k);	/* t_num = (t_num)^2 in F_p^2 */
+		
+		ep_eval_tangent2(tate->E, temp, V, B);
+		gf_ele_mul(tate->gfp2, t_num, t_num, temp, tate->gfp2->k);	/* t_num = t_num * EvalTangent(B, V) */
+
+		ep_projective_point_double(tate->E, T, V);
+		ep_projective_point_copy(tate->E, V, T);	/* V = [2]V */
+		
+		ep_eval_vertical2(tate->E, temp, V, B);
+		gf_ele_mul(tate->gfp2, t_den, t_den, temp, tate->gfp2->k);	/* t_den = t_den * EvalVertical(B, V) */
+	}
+
+	ep_projective_to_affine(tate->E, V_b, V);	
+
+	gf_ele_mul(tate->gfp2, v_num, v_num, t_num, tate->gfp2->k);	/* v_num = v_num * t_num */
+	gf_ele_mul(tate->gfp2, v_den, v_den, t_den, tate->gfp2->k);	/* v_den = v_den * t_den */
+	
+	/* step 3. calculate 2^a contribution */	
+	for(n=tate->b; n<tate->a; n++){
+		gf_ele_sqr(tate->gfp2, t_num, t_num, tate->gfp2->k);	/* t_num = (t_num)^2 in F_p^2 */
+		gf_ele_sqr(tate->gfp2, t_den, t_den, tate->gfp2->k);	/* t_num = (t_num)^2 in F_p^2 */
+		
+		ep_eval_tangent2(tate->E, temp, V, B);
+		gf_ele_mul(tate->gfp2, t_num, t_num, temp, tate->gfp2->k);	/* t_num = t_num * EvalTangent(B, V) */
+
+		ep_projective_point_double(tate->E, T, V);
+		ep_projective_point_copy(tate->E, V, T);	/* V = [2]V */
+		
+		ep_eval_vertical2(tate->E, temp, V, B);
+		gf_ele_mul(tate->gfp2, t_den, t_den, temp, tate->gfp2->k);	/* t_den = t_den * EvalVertical(B, V) */
+	}
+
+	ep_projective_to_affine(tate->E, V_a, V);	
+
+	gf_ele_mul(tate->gfp2, v_num, v_num, t_num, tate->gfp2->k);	/* v_num = v_num * t_num */
+	gf_ele_mul(tate->gfp2, v_den, v_den, t_den, tate->gfp2->k);	/* v_den = v_den * t_den */
+
+	/* step 4. Correction for 2^b */
+	ep_eval_line(tate->E, temp, V_a, V_b, B);
+	gf_ele_mul(tate->gfp2, v_num, v_num, temp, tate->gfp2->k);		/* v_num = v_num * EvalLine(B, Va, Vb) */
+
+	ep_point_add(tate->E, R, V_a, V_b);
+	ep_eval_vertical1(tate->E, temp, R, B);
+	gf_ele_mul(tate->gfp2, v_den, v_den, temp, tate->gfp2->k);		/* v_den = v_den * EvalVertical(B, Va + Vb) */
+
+	/* step 5. Correcting exponent - no need */
+	
+
+	/* step 6. final exponentiation */
+	gf_ele_inverse(tate->gfp2, temp, v_den);
+	gf_ele_mul(tate->gfp2, temp, temp, v_num, tate->gfp2->k);
+	gf_ele_exp(tate->gfp2, res, temp, tate->eta, tate->eta_len);		/* res = (v_num / v_den)^{eta} */
+
+	/* free memory */
+	gf_ele_free(temp, tate->gfp2->k);	
+	ep_projective_point_free(T);
+	ep_point_free(R);
+
+	return 0;
+}
+
+int tate_pairing(Tate_Pairing_Info *tate, GF_ELE e, Ep_Point *A, Ep_Point *B)
+{
+	Ep2_Point TB;
+
+	TB.x = gf_ele_init(tate->gfp2, tate->gfp2->k);
+	TB.y = gf_ele_init(tate->gfp2, tate->gfp2->k);
+
+	/* compute TB = phi(B) */
+
+	/* compute modified tate's pairing */
+	tate_pairing_eval(tate, e, A, &TB);
+
+	/* free memory */
+	gf_ele_free(TB.x, tate->gfp2->k);
+	gf_ele_free(TB.y, tate->gfp2->k);
+
+	return 0;
+}
+
+int tate_pairing_ratio()
+{
+	return 0;
+}
diff --git a/src/libm/elliptic-ffp.h b/src/libm/elliptic-ffp.h
new file mode 100644
index 000000000000..f9a0debb6dbc
--- /dev/null
+++ b/src/libm/elliptic-ffp.h
@@ -0,0 +1,232 @@ 
+/*-----------------------------------------------------------*/
+/* Elliptic Curve Over Prime Field Implementation            */
+/* Author: Dang Nguyen Duc                                   */
+/* Date  : 2002/11/16                                        */
+/* Ref	 : IEEE P1363 Public Key Cryptography Specifications */
+/* Todo  : Make all init struct functions to return pointer  */ 
+/*-----------------------------------------------------------*/
+
+#ifndef _ELLIPTIC_FFP_H
+#define _ELLIPTIC_FFP_H
+
+#include "bigdigits.h"
+#include "galois.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+	DIGIT_T		*x;	/* X coordinate */
+	DIGIT_T		*y;	/* Y coordinate */
+} Ep_Point;
+/* (X = 0, Y = 0) represents point at infinity */
+
+typedef struct {
+	DIGIT_T		*X;	/* X coordinate : x = X/Z^2 */
+	DIGIT_T		*Y;	/* Y coordinate : y = Y/Z^3 */
+	DIGIT_T		*Z;	/* Z coordinate */	
+} Ep_Projective_Point;
+/* (X = 0, Y = 1, Z = 0) is the point at infinity */
+
+/* Weierstrass Equation (affine coordinate) : y^2 = x^3 + ax + b (mod p) */
+/*                  (projective coordinate) : Y^2Z = X^3 + aXZ^4 + bZ^6 */	
+typedef struct {
+	UINT 		len;	/* Length of p in DWORD */
+	DIGIT_T		*p;	/* Underlying field is Z/Zp */
+	DIGIT_T		*a;	/* Coefficient a, usually -3 or p-3 */
+	DIGIT_T		*b;	/* Coefficient b */
+	Ep_Point	G;	/* The base point */
+				/* in case of type-1 curve, base point of subgroup of prime order r | p+1 and p mod 12 = 11 */
+	UINT		rlen;	/* Lenght of r in DWORD */
+	DIGIT_T		*r;	/* Order of the base point */
+	DIGIT_T		h;	/* h*r is order of the group, b (as in Solinas prime 2^a+2^b+1) in case type-1 curve */
+} Ep_Curve;
+
+#define EP_NPARAM	   9 + 2	/* Number of lines in domain parameter file */
+#define EP_MAX_LINE_LEN	   256+1+1	/* Max length of a line in domain parameter file */
+
+typedef struct {
+	UINT a;
+	UINT b;			/* Solinas prime is 2^a + 2^b + 1 */
+	DIGIT_T *eta;		/* exponent eta = (p^2-1)/q is used when computing final exponentiation of Tate pairing */
+	UINT eta_len;		/* digit length of eta */
+	Ep_Curve *E;		/* Type-1 elliptic curve of interest */
+	GF_T	 *gfp2;		/* extension field GF(p^2) */	
+} Tate_Pairing_Info;		
+
+typedef struct {
+	GF_ELE x;
+	GF_ELE y;
+} Ep2_Point;			/* Point coordinates on extension field F_{p^2} */
+				/* This one is indended for Tate pairing computation */
+
+/* Function Prototype */
+Ep_Point* ep_point_init(Ep_Curve *E);
+	/* Allocate memory for a Point using Affine coordinate */
+
+int ep_point_member_init(Ep_Curve*E, Ep_Point *P);
+	/* Allocate memory for Ep_Point's members */
+
+void ep_point_free(Ep_Point *P);
+	/* free memory allocaeted for Ep_Point struct including its members */
+
+void ep_point_member_free(Ep_Point *P);
+	/* free memory allocate for Ep_Point's members only */
+
+Ep_Projective_Point *ep_projective_point_init(Ep_Curve *E);
+	/* Allocate Memory for a Point using Projective coordinate */
+
+int ep_projective_point_member_init(Ep_Curve*E, Ep_Projective_Point *P);
+	/* Allocate memory for Ep_Projective_Point's members */
+
+void ep_projective_point_free(Ep_Projective_Point *P);
+	/* free memory allocaeted for Ep_Point struct including its members */
+
+void ep_projective_point_member_free(Ep_Projective_Point *P);
+	/* free memory allocate for Ep_Point's members only */
+
+int ep_affine_to_projective(Ep_Curve *E, Ep_Projective_Point *P, Ep_Point *Q);
+	/* Convert affine to projective coordinate */
+
+int ep_projective_to_affine(Ep_Curve *E, Ep_Point *P, Ep_Projective_Point *Q);
+	/* Convert projective to affine coordinate */
+
+int ep_point_copy(Ep_Curve *E, Ep_Point *P, Ep_Point *Q);
+	/* Make P = Q */
+
+int ep_projective_point_copy(Ep_Curve *E, Ep_Projective_Point *P, Ep_Projective_Point *Q);
+	/* P = Q in projective coordinate */
+
+int ep_point_zero(Ep_Curve *E, Ep_Point *P);
+	/* Make P = infinity */
+
+int ep_projective_point_zero(Ep_Curve *E, Ep_Projective_Point *P);
+	/* Make P = infinity in projective coordinate */
+
+int ep_point_inv(Ep_Curve *E, Ep_Point *Q, Ep_Point *P);
+	/* Point Inversion Q = [-1]P */
+
+int ep_point_is_zero(Ep_Curve *E, Ep_Point *P);
+	/* return true if P is inf point */
+
+int ep_projective_point_is_zero(Ep_Curve *E, Ep_Projective_Point *P);
+	/* return true if P is inf point in projective coordinate */
+
+int ep_point_is_equal(Ep_Curve *E, Ep_Point *P, Ep_Point *Q);
+	/* return true if P = Q */
+
+int ep_point_is_inverse(Ep_Curve *E, Ep_Point *P, Ep_Point *Q);
+	/* return true if P = -Q */
+
+int ep_point_add(Ep_Curve *E, Ep_Point *R, Ep_Point *P, Ep_Point *Q);
+	/* Point Addition R = P + Q using affine coordinate */
+
+int ep_projective_point_add(Ep_Curve *E, Ep_Projective_Point* R, \
+		                         Ep_Projective_Point *Q, \
+					 Ep_Projective_Point *P);
+	/* Point Addition R = P + Q using projective coordinate */
+
+int ep_mixed_point_add(Ep_Curve *E, Ep_Projective_Point* R, \
+		                    Ep_Projective_Point *Q, \
+				    Ep_Point *P);
+	/* Point Addition R = P + Q using both projective (Q) and affine (P) coordinate */
+
+int ep_point_sub(Ep_Curve *E, Ep_Point *R, Ep_Point *P, Ep_Point *Q);
+	/* Point Subtraction R = P - Q */
+	
+int ep_point_double(Ep_Curve *E, Ep_Point* Q, Ep_Point *P);
+	/* Point Doubling, Q = [2]P */
+
+int ep_projective_point_double(Ep_Curve *E, Ep_Projective_Point* Q, Ep_Projective_Point *P);
+	/* Point Doubling, Q = [2]P in projective coordinate */
+	
+int ep_point_mul(Ep_Curve *E, Ep_Point *Q, Ep_Point *P, DIGIT_T *k, UINT klen);
+	/* Point Multiplication using affine coordinate */
+
+int ep_projective_point_mul(Ep_Curve *E, Ep_Projective_Point* Q, \
+		                         Ep_Projective_Point *P, DIGIT_T *k, UINT klen);
+	/* Point Multiplication Q = [k]P using projective coordinate */
+
+int ep_point_gen(Ep_Curve *E, Ep_Point *P);
+	/* Random Point Generation */
+
+int ep_point_order(Ep_Curve *E, Ep_Point *P, DIGIT_T *k);
+	/* Compute order of P - todo */
+
+Ep_Curve *ep_curve_init(DIGIT_T *p, UINT plen, DIGIT_T *a, DIGIT_T *b, DIGIT_T *r, UINT rlen, Ep_Point *G);
+	/* allocate memory for Ep_Curve struct including its members */
+
+void ep_curve_free(Ep_Curve *E);
+	/* free memory allocated to Ep_Curve struct including its members */
+
+Ep_Curve *ep_curve_init2(void);
+	/* allocate memory for Ep_Curve struct only */
+
+void ep_curve_member_free(Ep_Curve *E);
+	/* free memory allocated to Ep_Curve's members only */
+
+int ep_curve_gen(Ep_Curve *E);
+	/* Verifiable Pseudorandom Elliptic Curve Generation - todo */
+
+int ep_type1_curve_gen(Ep_Curve *E, UINT n);
+	/* Type-1 curve generation - y^2 = x^3 + 1 (mod p) s.t. p mod 12 = 11 */
+	/* Curve's order is p+1, q is order of subgroup of E/F_p */
+	/* Subgroup of interest is E/F_(p^2) which is isomorphic to F_p[x]/(x^2+1) */
+	/* n - security strength measured in RSA's key length, e.g., 1024 */
+
+int ep_type1_curve_validate(Ep_Curve *E);
+	/* doesnt hurt to validate curve generated by ep_type1_curve_gen */
+
+int ep_eval_vertical1(Ep_Curve *E, GF_ELE r, Ep_Point *A, Ep2_Point *B);
+	/* evaluate the divisor of the vertical line which goes through A at B */
+	/* this is a helper function for computing Tate's pairing */
+
+int ep_eval_vertical2(Ep_Curve *E, GF_ELE r, Ep_Projective_Point *A, Ep2_Point *B);
+	/* ep_eval_vertical for A in projective coordinate */
+
+int ep_eval_tangent1(Ep_Curve *E, GF_ELE r, Ep_Point *A, Ep2_Point *B);
+	/* evaluate the divisor of the tangent line to A, at B */
+	/* this is another helper function for computing Tate's pairing */
+
+int ep_eval_tangent2(Ep_Curve *E, GF_ELE r, Ep_Projective_Point *A, Ep2_Point *B);
+	/* same version but for A in projective coordinate */
+
+int ep_eval_line1(Ep_Curve *E, GF_ELE r, Ep_Point *A1, Ep_Point *A2, Ep2_Point *B);
+	/* evaluate the divisor of the line goes through A1-A2, at B */
+	/* this is another helper function for computing Tate's pairing */
+
+int tate_pairing_init(Tate_Pairing_Info *tate, UINT n);
+	/* preparing Tate_Pairing_Info structure */
+	/* n is security strenth measured in RSA's key length */
+
+int tate_pairing_init2(Tate_Pairing_Info *tate, const char *curve_fname);
+	/* preparing Tate_Pairing_Info structure from elliptic curve domain file */
+
+int tate_pairing_eval(Tate_Pairing_Info *tate, GF_ELE res, Ep_Point *A, Ep2_Point *B);
+	/* compute tate's pairing */ 
+
+int tate_pairing(Tate_Pairing_Info *tate, GF_ELE e, Ep_Point *A, Ep_Point *B);
+	/* compute modified tate's pairing */
+
+/* Utility Function */
+int ep_load_curve(const char *fname, Ep_Curve *E);
+	/* Load Elliptic Curve Domain Parameters From File */
+
+int ep_save_curve(const char *fname, Ep_Curve *E);
+	/* Save Elliptic Curve Domain Parameters To File */
+
+int ep_load_point(const char *fname, Ep_Curve *E, Ep_Point *P);
+	/* Load A Point Coordinates From File */
+
+int ep_save_point(const char *fname, Ep_Curve *E, Ep_Point *P);
+	/* Save A Point Coordinates To File */
+
+int ep_is_on_curve(Ep_Curve *E, Ep_Point *P);
+	/* Check whether P lies on E */
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libm/ff2n.c b/src/libm/ff2n.c
new file mode 100644
index 000000000000..09a677507de2
--- /dev/null
+++ b/src/libm/ff2n.c
@@ -0,0 +1,810 @@ 
+/*-----------------------------------------------------------------------*/
+/* Binary Field Implementation - ff2n.c (Polynomial Basis)               */
+/* Author : Dang Nguyen Duc, nguyenduc@icu.ac.kr  	                 */
+/* Date : 11/17/2001                                                     */ 
+/* Note : All algorithms used in this program are considered as classical*/ 
+/*        algorithms for polynomial arithmetic. All of them are refered  */	
+/*        to "Handbook of Applied Cryptography" by Alfred Menezes        */
+/* Version : 0.1a 						         */	
+/* Change  :							         */	
+/* To Do   :                                                             */
+/*-----------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include "ff2n.h"
+
+/* Squaring Precomputation */
+static const unsigned short T[256] = {
+    	0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041,
+    	0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105,
+    	0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151,
+    	0x0154, 0x0155, 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+    	0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501,
+    	0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545,
+    	0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011,
+    	0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+    	0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141,
+    	0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405,
+    	0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451,
+    	0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+    	0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001,
+    	0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045,
+    	0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111,
+    	0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+    	0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441,
+    	0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, 0x4505,
+    	0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551,
+    	0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+    	0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101,
+    	0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, 0x5145,
+    	0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411,
+    	0x5414, 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+    	0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541,
+    	0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 };
+    	
+/* Utility function */
+int ff2n_swap(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE)
+{
+	/* a(x) <--> b(x) */
+	FF2N_ELT temp;
+		
+	while(COEFF_SIZE--){
+		temp = a_coeff[COEFF_SIZE];
+		a_coeff[COEFF_SIZE] = b_coeff[COEFF_SIZE];
+		b_coeff[COEFF_SIZE] = temp;
+	}
+	
+	return 0;
+}
+
+int ff2n_is_unit(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	/* return 1 if a(x) = 1, otherwise return 0 */
+	register UINT i;
+	
+	for(i=1;i<COEFF_SIZE;i++)
+		if(a_coeff[i])
+			return 0;
+	
+	return (a_coeff[0] == 1);
+}
+
+int ff2n_is_zero(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	/* return 1 if a(x) = 0, otherwise return 0 */
+	register UINT i;
+	
+	for(i=0;i<COEFF_SIZE;i++)
+		if(a_coeff[i])
+			return 0;
+	
+	return 1;
+}
+
+int ff2n_is_equal(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE)
+{
+	/* return 1 if a(x) = b(x), otherwise return 0 */
+	register UINT i;
+	
+	for(i=0;i<COEFF_SIZE;i++)
+		if(a_coeff[i] != b_coeff[i])
+			return 0;
+	
+	return 1;
+}
+
+FF2N_ELT ff2n_ranfunc(FF2N_ELT min, FF2N_ELT max)
+{
+	static unsigned seeded = 0;
+	register UINT i;
+	double f;
+
+	if (!seeded){
+		/* seed with system time */
+		srand((unsigned)time(NULL));
+		
+		i = rand() & 0xFF;
+		while (i--)
+			rand();
+		seeded = 1;
+	}
+	f = (double)rand() / RAND_MAX * max;
+	return (min + (UINT)f);
+}
+
+/* main functions */
+/*---------------------------------------------------------------------*/
+/* ff2n_get_bit : Get k-th coefficient				       */
+/* input  : a(x), k						       */
+/* ouput  : a(k)						       */
+/*---------------------------------------------------------------------*/
+int ff2n_get_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE)
+{
+	register UINT i, j;
+	register FF2N_ELT mask = WORD_LOW_BITMASK;
+	
+	i = k / BITS_PER_WORD;
+	j = k % BITS_PER_WORD;
+	
+	mask = mask << j;
+	
+	if(a_coeff[i] & mask)
+		return 1;
+
+	return 0;
+}
+/*---------------------------------------------------------------------*/
+/* ff2n_set_bit : set k-th coefficient				       */
+/* input  : a(x), k						       */
+/* ouput  : a(x) such that a_k = 1				       */
+/*---------------------------------------------------------------------*/
+int ff2n_set_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE)
+{
+	register UINT i, j;
+	register FF2N_ELT mask = WORD_LOW_BITMASK;
+	
+	i = k / BITS_PER_WORD;
+	j = k % BITS_PER_WORD;
+	
+	mask = mask << j;
+	
+	a_coeff[i] |= mask;
+			
+	return 0;
+}
+/*---------------------------------------------------------------------*/
+/* ff2n_clear_bit: Clear k-th coefficient			       */
+/* input   : a(x), k						       */
+/* ouput   : a(x) such that a_k = 0				       */
+/*---------------------------------------------------------------------*/
+int ff2n_clear_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE)
+{
+	register UINT i, j;
+	register FF2N_ELT mask = WORD_LOW_BITMASK;
+	
+	i = k / BITS_PER_WORD;
+	j = k % BITS_PER_WORD;
+	
+	mask = mask << j;
+	mask = ~mask;
+	
+	a_coeff[i] &= mask;
+			
+	return 0;
+}  		
+/*---------------------------------------------------------------------*/
+/* ff2n_kMul   : left shift memory k bits or a(x) = a(x) * x^k         */  
+/* input  : b(x)                                                       */
+/* output : a(x) = b(x) * x^k                                          */
+/*---------------------------------------------------------------------*/
+int ff2n_kMul(FF2N_ELT a_coeff[], UINT a_COEFF_SIZE, FF2N_ELT b_coeff[], UINT b_COEFF_SIZE, UINT k)
+{
+	register int i;
+	register UINT l;
+	register UINT temp_k = k;
+	register FF2N_ELT mask = WORD_HI_BITMASK;  
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+	register UINT carry = 0;
+	register UINT nextcarry = 0;
+
+	ff2n_set_equal(temp, b_coeff, b_COEFF_SIZE);
+	ff2n_set_zero(a_coeff, a_COEFF_SIZE);
+	ff2n_set_equal(a_coeff, temp, b_COEFF_SIZE);
+	
+	if(k == 0)
+		return 0;
+	
+	/* a WORD-LONG left shift */
+	l = 0;
+	while(temp_k / BITS_PER_WORD){
+		for(i=a_COEFF_SIZE-1;i>l;i--){
+			a_coeff[i] = a_coeff[i-1];
+			a_coeff[i-1] = 0;
+		}
+		l++;
+		temp_k -= BITS_PER_WORD;
+	}
+	if(temp_k == 0)
+		return 0; /* no more to shift */
+	/* less than a WORD-LONG left shift */
+	l = BITS_PER_WORD - temp_k;
+	
+	for(i=1;i<k;i++) /* Construct mask */
+		mask = (mask >> 1) | WORD_HI_BITMASK;
+		
+	for(i=k/BITS_PER_WORD;i<a_COEFF_SIZE;i++){
+		nextcarry = (a_coeff[i] & mask) >> l;
+		a_coeff[i] <<= temp_k;
+		a_coeff[i] |= carry;
+		carry = nextcarry;
+
+	}
+	
+	return 0;
+}
+/*---------------------------------------------------------------------*/
+/* ff2n_kDiv    : Divided by x^k or right shift k bits                 */  
+/* input   : b(x)                                                      */
+/* output  : a(x) = b(x) / x^k                                         */
+/*---------------------------------------------------------------------*/
+int  ff2n_kDiv(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE,  UINT k)
+{
+	register int i;
+	register UINT l;
+	register UINT temp_k = k;
+	register FF2N_ELT mask = WORD_LOW_BITMASK;
+	register UINT carry = 0;
+	register UINT nextcarry = 0;
+
+	if(a_coeff != b_coeff)
+		ff2n_set_equal(a_coeff, b_coeff, COEFF_SIZE);
+		
+	if(k == 0)
+		return 0;
+		
+	/* a WORD-LONG left shift */
+	l = 1;
+	while(temp_k / BITS_PER_WORD){
+		for(i=0;i<COEFF_SIZE-l; i++) {
+			a_coeff[i] = a_coeff[i + 1];
+			a_coeff[i + 1] = 0;
+		}
+		temp_k -= BITS_PER_WORD;
+		l++;
+	}
+	if(!temp_k)
+		return 0; /* no more to shift */
+	/* less than a WORD-LONG left shift */
+	l = BITS_PER_WORD - temp_k;
+	
+	/* Construct mask */
+	mask = WORD_LOW_BITMASK;
+	for (i = 1; i < l; i++)
+		mask = (mask << 1) | WORD_LOW_BITMASK;
+		
+	for(i=COEFF_SIZE - k/BITS_PER_WORD - 1;i>=0;i--){
+		nextcarry = a_coeff[i] & mask;
+		a_coeff[i] >>= temp_k;
+		a_coeff[i] |= carry;
+		carry = nextcarry;
+
+	}
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_set_zero : make a zero polynomial		                */
+/*----------------------------------------------------------------------*/
+int ff2n_set_zero(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	register int i;
+	
+	for(i=0; i<COEFF_SIZE; i++)
+		a_coeff[i] = 0;
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_set_unit : make a unit polynomial		                */
+/*----------------------------------------------------------------------*/
+int ff2n_set_unit(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	register int i;
+	
+	for(i=1; i<COEFF_SIZE; i++)
+		a_coeff[i] = 0;
+
+	a_coeff[0] = 1;	
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_set_equal : Make two polynomial the same  		        */
+/*----------------------------------------------------------------------*/
+int ff2n_set_equal(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE)
+{
+	register int i;
+	
+	for(i=0; i<COEFF_SIZE; i++)
+		a_coeff[i] = b_coeff[i];
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_poly_deg : ff2n_poly_degree of polynomial                       */
+/* input   : a(x)					                */
+/* output  : ff2n_poly_degree of a(x)				        */
+/*----------------------------------------------------------------------*/
+int ff2n_poly_deg(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	register int i;
+	register int j;
+	register UINT mask;
+	
+	for(i=COEFF_SIZE-1;i>=0;i--)
+		for(j=BITS_PER_WORD-1, mask = WORD_HI_BITMASK; j>=0; j--, mask >>= 1)
+			if((a_coeff[i] & mask) > 0)
+				return (i*BITS_PER_WORD + j);		
+	return 0;
+}	
+/*----------------------------------------------------------------------*/
+/* ff2n_add  : addition in GF(2^n)                                      */
+/* input  : a(x), b(x)                                                  */
+/* output : a(x) + b(x)                                              	*/
+/*----------------------------------------------------------------------*/
+int ff2n_add(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE)
+{
+	register UINT i;
+	
+	/* addition */
+	for(i=0; i<COEFF_SIZE; i++)
+		c_coeff[i] = a_coeff[i] ^ b_coeff[i];
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_sub  : subtraction in GF(2^n)                                   */
+/* input  : a(x), b(x)                                                  */
+/* output : a(x) - b(x)                                         	*/
+/*----------------------------------------------------------------------*/
+int ff2n_sub(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE)
+{
+	 register UINT i;
+		
+	/* subtraction */
+	for(i=0; i<COEFF_SIZE; i++)
+		c_coeff[i] = a_coeff[i] ^ b_coeff[i];
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_reduce : polynomial reduction	 				*/
+/* input   : a(x), n(x) - irreducible polynomial 			*/
+/* output  : a(x) mod n(x)						*/
+/*----------------------------------------------------------------------*/
+int ff2n_reduce(FF2N_ELT a_coeff[], UINT a_COEFF_SIZE, FF2N_ELT n_coeff[], UINT n_COEFF_SIZE)
+{
+	register int d;
+	register UINT ndeg;
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+				
+	/* initialization */
+	ff2n_set_zero(temp, MAX_COEFF_SIZE);
+	ndeg = ff2n_poly_deg(n_coeff, n_COEFF_SIZE);
+	
+	while((d = (ff2n_poly_deg(a_coeff, a_COEFF_SIZE) - ndeg)) >= 0) {
+		/* temp(x) = n(x) * x^d */
+		ff2n_kMul(temp, a_COEFF_SIZE, n_coeff, n_COEFF_SIZE, d);	
+		
+		/* a(x) = a(x) - temp(x) */
+		ff2n_sub(a_coeff, a_coeff, temp, a_COEFF_SIZE);		
+	}
+	
+	return 0;
+}
+
+/*----------------------------------------------------------------------*/
+/* ff2n_reduce163 : polynomial reduction specialized for GF(2^163)	*/
+/* input       : a(x), n(x) - irreducible polynomial 			*/
+/* output      : a(x) mod n(x)						*/
+/*----------------------------------------------------------------------*/
+int ff2n_reduce163(FF2N_ELT a_coeff[])
+{
+	/* n(x) must be x^163 + x^7 + x^6 + x^3 + 1 */
+	register UINT i;
+	register FF2N_ELT T;
+	
+	for(i=10;i>=6;i--) {
+		T = a_coeff[i];
+		a_coeff[i-6] ^= (T << 29);
+		a_coeff[i-5] ^= (T <<  4) ^ (T <<  3) ^ T ^ (T >>3);
+		a_coeff[i-4] ^= (T >> 28) ^ (T >> 29);
+	}	
+	T = a_coeff[5] & 0xFFFFFFF8;
+	a_coeff[0] ^= (T << 4) ^ (T << 3) ^ T ^ (T >> 3);
+	a_coeff[1] ^= (T >> 28) ^ (T >> 29);
+	a_coeff[5] &= 0x00000007;
+		
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_mul  : standard multiplication by shift-and-add method          */
+/* input  : a(x), b(x), n(x)                                            */
+/* output : a(x) * b(x) mod n(x)                                        */
+/*----------------------------------------------------------------------*/ 
+int ff2n_mul(FF2N_ELT p_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+	register UINT  i, j;
+	register FF2N_ELT mask;
+	UINT ndeg;
+	
+	ndeg = ff2n_poly_deg(n_coeff, COEFF_SIZE);
+	ff2n_set_equal(temp, b_coeff, COEFF_SIZE);
+	
+	/* if a_0 = 0 then p(x) = b(x) otherwise p(x) = 0 */
+	if(a_coeff[0] & WORD_LOW_BITMASK)
+		ff2n_set_equal(p_coeff, b_coeff, COEFF_SIZE);
+	else
+		ff2n_set_zero(p_coeff, COEFF_SIZE);
+	
+	/* main loop */
+	for(i=0;i<COEFF_SIZE;i++)		
+		for(j=0, mask = WORD_LOW_BITMASK; j<BITS_PER_WORD; j++, mask <<= 1)
+			if(i || j){	/* avoid a_0 */
+				
+				/* temp(x) = b(x)*x mod n(x) */
+				ff2n_kMul(temp, COEFF_SIZE, temp, COEFF_SIZE, 1);
+				if(ff2n_poly_deg(temp, COEFF_SIZE) == ndeg)
+					ff2n_add(temp, temp, n_coeff, COEFF_SIZE);
+					
+				/* if a_i = 1 then p(x) = p(x) + temp(x) */
+				if(a_coeff[i] & mask)
+					ff2n_add(p_coeff, p_coeff, temp, COEFF_SIZE);
+		
+			}	
+	
+	return 0;
+}
+/*----------------------------------------------------------------------------*/
+/* ff2n_rl_comb : multiplication using Right-to-Left Comb method              */
+/* input    : a(x), b(x), n(x)                                                */
+/* output   : a(x) * b(x) mod n(x)                                            */
+/*----------------------------------------------------------------------------*/ 
+int ff2n_rl_comb(FF2N_ELT p_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	/* Still has some bug */
+	FF2N_ELT temp[2*MAX_COEFF_SIZE];
+	FF2N_ELT B[2*MAX_COEFF_SIZE];
+	register UINT i, j, k;
+	register FF2N_ELT mask;
+	
+	ff2n_set_zero(temp, 2*COEFF_SIZE);
+	ff2n_set_zero(B, 2*COEFF_SIZE);
+	ff2n_set_equal(B, b_coeff, COEFF_SIZE);
+	
+	for(k=0;k<BITS_PER_WORD;k++) {
+		mask = WORD_LOW_BITMASK << k;
+		for(j=0;j<COEFF_SIZE;j++)
+			if(a_coeff[j] & mask)
+				for(i=j;i<2*COEFF_SIZE-1;i++)
+					temp[i] = temp[i] ^ B[i-j];
+		if(k!=BITS_PER_WORD-1)
+			ff2n_kMul(B, 2*COEFF_SIZE, B, 2*COEFF_SIZE, 1); 
+	}
+	
+	ff2n_reduce(temp, 2*COEFF_SIZE, n_coeff, COEFF_SIZE);
+	ff2n_set_equal(p_coeff, temp, COEFF_SIZE);
+	
+	return 0;
+}
+/*----------------------------------------------------------------------------*/
+/* ff2n_sqr  : squaring                                                       */
+/* input : a(x), n(x)                                                         */
+/* output: b(x) = a(x)^2 mod n(x)                                             */
+/*----------------------------------------------------------------------------*/
+int ff2n_sqr(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	UINT i, j, k;
+	FF2N_ELT temp[2*MAX_COEFF_SIZE];
+	
+	ff2n_set_zero(temp, 2*MAX_COEFF_SIZE);
+	
+	/* set temp(2*i) = a(i) */
+	for(i=0;i<COEFF_SIZE;i++)
+		for(j=0;j<BITS_PER_WORD;j++) {
+			k = i*BITS_PER_WORD + j;
+			if(ff2n_get_bit(a_coeff, k, COEFF_SIZE))
+				ff2n_set_bit(temp, 2*k, COEFF_SIZE);
+		}
+	ff2n_reduce(temp, 2*COEFF_SIZE, n_coeff, COEFF_SIZE);
+	ff2n_set_equal(b_coeff, temp, COEFF_SIZE);
+		
+	return 0;
+}   
+/*----------------------------------------------------------------------------*/
+/* ff2n_sqr2: squaring with precomputation                                    */
+/* input : a(x), n(x)                                                         */
+/* output: b(x) = a(x)^2 mod n(x)                                             */
+/*----------------------------------------------------------------------------*/
+int ff2n_sqr2(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	register UINT i;
+	register UINT u0, u1, u2, u3;
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+	
+	ff2n_set_zero(temp, MAX_COEFF_SIZE);
+	
+	for(i=0;i<COEFF_SIZE;i++) {
+		u0 = (a_coeff[i] & 0x000000ff);
+		u1 = (a_coeff[i] & 0x0000ff00) >> 8;
+		u2 = (a_coeff[i] & 0x00ff0000) >> 16;
+		u3 = (a_coeff[i] & 0xff000000) >> 24;
+		
+		temp[i<<1] = (T[u1] << 16) | T[u0];
+		temp[(i<<1)+1] = (T[u3] << 16) | T[u2]; 		
+	}	
+	
+	ff2n_reduce(temp, 2*COEFF_SIZE, n_coeff, COEFF_SIZE);
+	ff2n_set_equal(b_coeff, temp, COEFF_SIZE);
+	
+	return 0;
+}   
+
+/*----------------------------------------------------------------------*/
+/* ff2n_inverse: Inversion                                   		*/
+/* input    : a(x)                                                      */
+/* output   : b(x) s.t a(x)*b(x) = 1 mod n(x)                           */
+/*----------------------------------------------------------------------*/
+int ff2n_inverse(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	/* Extended Euclidean Algorithm */
+	FF2N_ELT c_coeff[MAX_COEFF_SIZE];
+	FF2N_ELT u_coeff[MAX_COEFF_SIZE];
+	FF2N_ELT v_coeff[MAX_COEFF_SIZE];
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+
+	register int j;
+	
+	/* b(x) = 1 */
+	ff2n_set_unit(b_coeff, COEFF_SIZE);
+	/* c(x) = 0 */
+	ff2n_set_zero(c_coeff, MAX_COEFF_SIZE);
+	/* u(x) = a(x) */
+	ff2n_set_equal(u_coeff, a_coeff, COEFF_SIZE);
+	/* v(x) = n(x) */
+	ff2n_set_equal(v_coeff, n_coeff, COEFF_SIZE);
+	
+	while((j = ff2n_poly_deg(u_coeff, COEFF_SIZE)) != 0) {
+		j -= ff2n_poly_deg(v_coeff, COEFF_SIZE);
+		if(j < 0) {
+			/* u(x) <--> v(x) */
+			ff2n_swap(u_coeff, v_coeff, COEFF_SIZE);
+			/* b(x) <--> c(x) */
+			ff2n_swap(b_coeff, c_coeff, COEFF_SIZE);
+			
+			j = -j;
+		}
+		
+		/* u(x) = u(x) - v(x)*x^j */
+		ff2n_kMul(temp, COEFF_SIZE,  v_coeff, COEFF_SIZE, j);
+		ff2n_sub(u_coeff, u_coeff, temp, COEFF_SIZE);
+		
+		/* b(x) = b(x) - c(x)*x^j */
+		ff2n_kMul(temp, MAX_COEFF_SIZE, c_coeff, COEFF_SIZE, j);
+		ff2n_sub(b_coeff, b_coeff, temp, COEFF_SIZE);
+	}
+
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_inverse2: Inversion                                   	   	*/
+/* input    : a(x)                                                      */
+/* output   : b(x) s.t a(x)*b(x) = 1 mod n(x)                           */
+/*----------------------------------------------------------------------*/
+int ff2n_inverse2(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	/* dont use this yets, it still has some bug */
+	/* Almost Inverse Algorithm */
+	FF2N_ELT c_coeff[MAX_COEFF_SIZE];
+	FF2N_ELT u_coeff[MAX_COEFF_SIZE];
+	FF2N_ELT v_coeff[MAX_COEFF_SIZE];
+	
+	/* b(x) = 1 */
+	ff2n_set_unit(b_coeff, COEFF_SIZE);
+	/* c(x) = 0 */
+	ff2n_set_zero(c_coeff, COEFF_SIZE);
+	/* u(x) = a(x) */
+	ff2n_set_equal(u_coeff, a_coeff, COEFF_SIZE);
+	/* v(x) = n(x) */
+	ff2n_set_equal(v_coeff, n_coeff, COEFF_SIZE);
+	
+	while(1) {
+		while((u_coeff[0] & WORD_LOW_BITMASK) == 0){ /* x divides u(x) */
+		
+			ff2n_kDiv(u_coeff, u_coeff, COEFF_SIZE, 1);
+			if((b_coeff[0] & WORD_LOW_BITMASK) == 0) /* x divides b(x) */
+				ff2n_kDiv(b_coeff, b_coeff, COEFF_SIZE, 1);
+			else {
+				ff2n_add(b_coeff, b_coeff, n_coeff, COEFF_SIZE);
+				ff2n_kDiv(b_coeff, b_coeff, COEFF_SIZE, 1);
+			}
+		}
+
+		if(ff2n_is_unit(u_coeff, COEFF_SIZE)) /* u(x) = 1 */
+			return 0;
+		if(ff2n_poly_deg(u_coeff, COEFF_SIZE) < ff2n_poly_deg(v_coeff, COEFF_SIZE)){
+			/* u(x) <---> v(x) */
+			ff2n_swap(u_coeff, v_coeff, COEFF_SIZE);
+			/* b(x) <---> c(x) */
+			ff2n_swap(b_coeff, c_coeff, COEFF_SIZE);
+		}
+		/* u(x) = u(x) + v(x) */
+		ff2n_add(u_coeff, u_coeff, v_coeff, COEFF_SIZE);
+		/* b(x) = b(x) + c(x) */
+		ff2n_add(b_coeff, b_coeff, c_coeff, COEFF_SIZE);
+	}
+	
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_div: Division                                                   */
+/* input   : a(x), b(x)                                                 */
+/* output  : a(x)*inv(b(x)) mod n(x)                                    */
+/*----------------------------------------------------------------------*/
+int ff2n_div(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+
+	ff2n_inverse(temp, b_coeff, n_coeff, COEFF_SIZE);
+	ff2n_mul(c_coeff, a_coeff, temp, n_coeff, COEFF_SIZE);
+
+	return 0;
+}
+/*----------------------------------------------------------------------*/
+/* ff2n_exp : Exponentiation 		                                */
+/* input : a(x), k                                                      */
+/* output: a(x)^k mod n(x)                                              */
+/*----------------------------------------------------------------------*/
+int ff2n_exp(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], DIGIT_T k[], UINT k_size, FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	/* left-to-right binary method */	
+	register int i, j;
+	register DIGIT_T mask;
+	
+	/* b(x) = 1 */
+	ff2n_set_unit(b_coeff, COEFF_SIZE);
+	
+	for(i=k_size-1;i>=0;i--)
+		for(mask = HIBITMASK, j=BITS_PER_DIGIT-1; j>=0; mask >>= 1, j--){
+			/* b(x) = b(x)^2 */
+			ff2n_sqr2(b_coeff, b_coeff, n_coeff, COEFF_SIZE);
+			
+			if(k[i] & mask)
+				/* b(x) = b(x)*a(x) */
+				ff2n_mul(b_coeff, a_coeff, b_coeff, n_coeff, COEFF_SIZE); 
+		}
+
+	return 0;
+}
+/*-------------------------------------------------------------------------*/
+/* ff2n_random_poly : Random Element Generator				   */
+/* input  : none							   */
+/* ouput  : a finite field element at random				   */ 	
+/*-------------------------------------------------------------------------*/
+int ff2n_random_poly(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+#if STRONG_RANDOM
+	prng((BYTE *)a_coeff, FF2N_NBYTE(COEFF_SIZE));
+#else
+	register UINT i;
+	
+	for(i=0;i<COEFF_SIZE-1;i++)
+		a_coeff[i] = ranfunc(0, WORD_MAXVAL); 
+#endif
+	return 0;
+}
+/*-----------------------------------------------------------------------*/
+/* ff2n_print : Print a polynomial's coefficients to screen              */
+/*-----------------------------------------------------------------------*/
+void ff2n_print(FF2N_ELT a_coeff[], UINT COEFF_SIZE)
+{
+	register UINT i = 0;
+	register UINT len = COEFF_SIZE;
+	
+	while (len--){
+		if ((i % 8) == 0 && i)
+			printf("\n");
+		printf("%08lx ", a_coeff[len]);
+		i++;
+	}
+	printf("\n");
+
+}
+/*-----------------------------------------------------------------------*/
+/* ff2n_str2poly : Convert a hexa-string to a polynomial's coefficients  */
+/*-----------------------------------------------------------------------*/
+static BYTE hex2byte(char c)
+{
+	BYTE b;
+	
+	switch(c) {
+	case '0': 	b = 0; break;
+	case '1':	b = 1; break;
+	case '2':	b = 2; break;
+	case '3':	b = 3; break;
+	case '4':	b = 4; break;
+	case '5':	b = 5; break;
+	case '6':	b = 6; break;
+	case '7':	b = 7; break;
+	case '8':	b = 8; break;
+	case '9':	b = 9; break;
+	case 'A': 	
+	case 'a':	b = 10; break;
+	case 'B':	
+	case 'b':	b = 11; break;
+	case 'C':	
+	case 'c':	b = 12; break;
+	case 'D':	
+	case 'd':	b = 13; break;
+	case 'E':	
+	case 'e':	b = 14; break;
+	case 'F': 	
+	case 'f':	b = 15; break;
+	default: b = 0;
+	}
+	
+	return b;
+}
+
+FF2N_ELT *ff2n_str2poly(UINT COEFF_SIZE, char *s)
+{
+	BYTE *p;
+	int i = 0;
+	int slen;
+	
+	/* Hexa string should be 8-digit blocks */
+	if((slen=strlen(s)) % (BITS_PER_WORD / 4))
+		return NULL;
+		
+	p = (BYTE *)malloc(COEFF_SIZE*BITS_PER_WORD/8);
+	memset(p, 0x00, COEFF_SIZE*BITS_PER_WORD/8);
+	
+	while(i<slen){
+		/* read 2 characters each = 1 byte */
+		p[i/2] = hex2byte(s[slen-i-1]) + (hex2byte(s[slen-i-2]) << 4);
+		i+=2;
+	}
+	
+	return (FF2N_ELT *)p;
+}
+
+/*-----------------------------------------------------------------------*/
+/* ff2n_quad_eqn : solve quadretic equation. IEEE 1363 - A.4.6  	 */
+/* Added by vdliem							 */
+/*-----------------------------------------------------------------------*/
+int ff2n_quad_eqn(FF2N_ELT H[], FF2N_ELT alpha[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	FF2N_ELT temp1[MAX_COEFF_SIZE];
+	FF2N_ELT temp2[MAX_COEFF_SIZE];
+	register UINT i;
+	ff2n_set_equal(temp1,alpha, COEFF_SIZE);
+	for (i=1;i<=(ff2n_poly_deg(n_coeff,COEFF_SIZE)-1)/2;i++)
+	{
+		ff2n_sqr2(temp2, temp1, n_coeff, COEFF_SIZE);
+		ff2n_sqr2(temp1, temp2, n_coeff, COEFF_SIZE);
+		ff2n_add(temp1, temp1, alpha, COEFF_SIZE);
+	}
+	
+	ff2n_set_equal(H,temp1,COEFF_SIZE);
+	return 0;
+
+}
+
+/*-----------------------------------------------------------------------*/
+/* ff2n_sqrt: square root = repeated square n-1                 	 */
+/* Added by vdliem							 */
+/*-----------------------------------------------------------------------*/
+int ff2n_sqrt(FF2N_ELT a[], FF2N_ELT b[], FF2N_ELT n_coeff[], UINT COEFF_SIZE)
+{
+	FF2N_ELT temp[MAX_COEFF_SIZE];
+	register UINT j;
+	int deg_b;
+	
+	ff2n_set_zero(temp, COEFF_SIZE);
+	if (ff2n_is_zero(b, COEFF_SIZE)){
+		ff2n_set_zero(a, COEFF_SIZE);
+		return 0;
+	}
+	deg_b=ff2n_poly_deg(b,COEFF_SIZE);
+	ff2n_set_equal(temp,b,COEFF_SIZE);
+	for (j=1; j<ff2n_poly_deg(n_coeff, COEFF_SIZE);j++) 
+		/*repeated square for deg(n_coeff)-1 times */
+       		ff2n_sqr2(temp,temp,n_coeff,COEFF_SIZE);
+	ff2n_set_equal(a,temp,COEFF_SIZE);
+    return 0;
+
+}
+/*-----------------------------------------------------------------------*/
diff --git a/src/libm/ff2n.h b/src/libm/ff2n.h
new file mode 100644
index 000000000000..c515ddf88e35
--- /dev/null
+++ b/src/libm/ff2n.h
@@ -0,0 +1,127 @@ 
+/*------------------------------------------------------*/
+/* Finite Field Implemetation Header file - ff2n.h      */
+/* Author : Dang Nguyen Duc - nguyenduc@icu.ac.kr       */
+/* Date   : 11/17/2001                                  */        
+/*------------------------------------------------------*/              
+#ifndef _FF2N_H_
+#define _FF2N_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bigdigits.h"
+
+typedef	unsigned long FF2N_ELT;	/* coefficient datatype */
+
+/* added by Liem */
+typedef FF2N_ELT *ff2n_p;
+typedef FF2N_ELT ff2n_t;
+
+#define WORD_MAXVAL 0xffffffff
+#define WORD_HI_BITMASK 0x80000000
+#define WORD_LOW_BITMASK 0x00000001
+#define BITS_PER_WORD	32
+#define MAX_COEFF_SIZE	64 + 1
+#define FF2N_NBYTE(len)	len*BITS_PER_WORD / 8
+
+/* Some Utility function */
+int ff2n_swap(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE);
+	/* Swap a(x) <---> b(x) */
+
+int ff2n_is_unit(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Return 1 if a(x) = 1 */ 
+	
+int ff2n_is_zero(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Return 1 if a(x) = 0 */ 
+	
+int ff2n_is_equal(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE);
+	/* Return 1 if a(x) = b(x) */ 
+
+int ff2n_get_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE);
+	/* Return k-th coefficient of a(x) */
+	
+int ff2n_set_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE);
+	/* Set k-th coefficient of a(x) to 1 */
+	
+int ff2n_clear_bit(FF2N_ELT a_coeff[], UINT k, UINT COEFF_SIZE);
+	/* Set k-th coefficient of a(x) to 0 */
+	
+int ff2n_kMul(FF2N_ELT a_coeff[], UINT a_COEFF_SIZE, FF2N_ELT b_coeff[], UINT b_COEFF_SIZE, UINT k);
+	/* a(x) = a(x) * x^k */
+
+int ff2n_kDiv(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE,  UINT k);
+	/* a(x) = a(x) / x^k */
+	
+int ff2n_set_zero(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Set a(x) = 0 */
+	
+int ff2n_set_unit(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Set a(x) = 1 */
+	
+int ff2n_set_equal(FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE);
+	/* Make a(x) = b(x) */
+	
+int ff2n_poly_deg(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Return degree of a(x) */
+
+int ff2n_add(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE);
+	/* Compute c(x) = a(x) + b(x) */
+	
+int ff2n_sub(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], UINT COEFF_SIZE);
+	/* Compute c(x) = a(x) - b(x) */
+
+int ff2n_reduce(FF2N_ELT a_coeff[], UINT a_COEFF_SIZE, FF2N_ELT n_coeff[], UINT n_COEFF_SIZE);
+	/* Compute a(x) = a(x) mod n(x) */
+
+int ff2n_reduce163(FF2N_ELT a_coeff[]);
+	/* Special Reduction Algorithm for GF(2^163) */
+
+int ff2n_mul(FF2N_ELT p_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial multiplication using Shift and Add: p(x) = a(x)*b(x) mod n(x) */
+
+int ff2n_rl_comb(FF2N_ELT p_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial multiplication - Right to Left Comb: p(x) = a(x)*b(x) mod n(x) */
+
+int ff2n_inverse(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial Inversion using Extended Euclidean Algorithm: b(x) = a(x)^-1 mod n(x) */
+
+int ff2n_inverse2(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial Inversion - Almost Inverse Algorithm: b(x) = a(x)^-1 mod n(x) */
+
+int ff2n_div(FF2N_ELT c_coeff[], FF2N_ELT a_coeff[], FF2N_ELT b_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial Division: c(x) = a(x) / b(x) mod n(x) */
+
+int ff2n_exp(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], DIGIT_T k[], UINT k_size, FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial exponentiation: b(x) = a(x)^k mod n(x) */
+
+int ff2n_sqr(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial squaring: b(x) = a(x)^2 mod n(x) */
+
+int ff2n_sqr2(FF2N_ELT b_coeff[], FF2N_ELT a_coeff[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+	/* Polynomial squaring with precomputation: b(x) = a(x)^2 mod n(x) */
+
+FF2N_ELT ff2n_ranfunc(FF2N_ELT min, FF2N_ELT max);
+	/* helper for ff2n_random_poly */
+
+int ff2n_random_poly(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Polynomial squaring - precomputation */
+	
+FF2N_ELT* ff2n_str2poly(UINT COEFF_SIZE, char *str);
+	/* Hexa-string to polynomial's coefficients */
+
+void ff2n_print(FF2N_ELT a_coeff[], UINT COEFF_SIZE);
+	/* Print polynomial's coefficients */
+
+/* Added by vdliem						*/
+int ff2n_quad_eqn(FF2N_ELT H[], FF2N_ELT alpha[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+    /*Solve quadretic equation*/
+
+int ff2n_sqrt(FF2N_ELT a[], FF2N_ELT b[], FF2N_ELT n_coeff[], UINT COEFF_SIZE);
+    /*Compute square root*/	
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libm/galois.c b/src/libm/galois.c
new file mode 100644
index 000000000000..6485f8c4ec44
--- /dev/null
+++ b/src/libm/galois.c
@@ -0,0 +1,497 @@ 
+/*-----------------------------------------------------------*/
+/* General Galois field implementation GF(p^n) for large p   */
+/* Author: Dang Nguyen Duc                                   */
+/* Date  : 2007/02/03                                        */
+/*-----------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bigdigits.h"
+#include "galois.h"
+
+GF_T *gf_init(UINT k, DIGIT_T *p, UINT plen)
+{
+	/* the field is GF(p^k) */
+	GF_T *gf = (GF_T *)malloc(sizeof(GF_T));
+	
+	if(gf!=NULL){
+		gf->plen = plen;
+		gf->p = mpMalloc(plen);
+		mpSetEqual(gf->p, p, plen);
+		gf->k = k;
+		gf->n = gf_ele_init(gf, gf->k+1);
+	}
+
+	return gf;
+}
+
+void gf_free(GF_T *gf)
+{
+	/* free memory allocated to GF_T struct including its members */
+	gf_ele_free(gf->n, gf->k+1);
+	mpFree(gf->p);
+	free(gf);
+}
+
+void gf_member_free(GF_T *gf)
+{
+	/* free memory allocated to GF_T struct's members only */
+	gf_ele_free(gf->n, gf->k+1);
+	mpFree(gf->p);
+}
+
+GF_ELE gf_ele_init(GF_T *gf, UINT len)
+{
+	GF_ELE a;
+	register int i;
+
+	/* allocate memory for k coefficients of a(x) */
+	a = (GF_ELE)malloc(len*sizeof(GF_ELE));
+
+	/* allocate memory for each cooeffcient */
+	for(i=0;i<len;i++)
+		a[i] = (DIGIT_T *)malloc(NBYTE(gf->plen));
+	
+	return a;
+}
+
+void gf_ele_free(GF_ELE a, UINT len)
+{
+	register int i;
+	
+	for(i=0;i<len;i++)
+		free(a[i]);
+	free(a);
+}
+
+int gf_ele_zero(GF_T *gf, GF_ELE a, UINT len)
+{
+	register int i;
+
+	for(i=0;i<len;i++)
+		mpSetZero(a[i], gf->plen);
+
+	return 0;
+}
+
+int gf_ele_is_zero(GF_T *gf, GF_ELE a, UINT len)
+{
+	register int i;
+
+	for(i=0; i<len; i++)
+		if(!mpIsZero(a[i], gf->plen))
+			return 0;
+
+	return 1;
+}
+
+int gf_ele_unit(GF_T *gf, GF_ELE a, UINT len)
+{
+	register int i;
+
+	for(i=len-1; i>0; i--)
+		mpSetZero(a[i], gf->plen);
+
+	mpSetDigit(a[0], 1, gf->plen);
+	
+	return 0;
+}
+
+int gf_ele_is_unit(GF_T *gf, GF_ELE a, UINT len)
+{
+	
+	register int i;
+
+	for(i=1; i<len; i++)
+		if(!mpIsZero(a[i], gf->plen))
+			return 0;
+
+	return (mpIsOne(a[0], gf->plen));	
+}
+
+int gf_ele_equal(GF_T *gf, GF_ELE a, GF_ELE b, UINT len)
+{
+	register int i;
+	
+	for(i=0; i<len; i++)
+		mpSetEqual(a[i], b[i], gf->plen);
+
+	return 0;
+}
+
+int gf_ele_is_equal(GF_T *gf, GF_ELE a, GF_ELE b, UINT len)
+{
+	register int i;
+	
+	for(i=0; i<len; i++)
+		if(!mpEqual(a[i], b[i], gf->plen))
+			return 0;
+	return 1;
+}
+
+int gf_ele_random(GF_T *gf, GF_ELE a, UINT len)
+{
+	register int i;
+	DIGIT_T *t = (DIGIT_T *)malloc(NBYTE(gf->plen));
+
+	for(i=0;i<len;i++){
+		mpMakeRandom(t, gf->plen);
+		mpModulo(a[i], t, gf->plen, gf->p, gf->plen);
+	}
+	
+	free(t);
+
+	return 0;		
+}
+
+int gf_ele_add(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len)
+{
+	register int i;
+
+	for(i=0; i<len; i++)
+		mpModAdd(a[i], b[i], c[i], gf->p, gf->plen);
+
+	return 0;
+}
+
+int gf_ele_sub(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len)
+{
+	register int i;
+
+	for(i=0; i<len; i++)
+		mpModSubtract(a[i], b[i], c[i], gf->p, gf->plen);
+
+	return 0;
+}
+
+UINT gf_poly_deg(GF_T *gf, GF_ELE a, UINT alen)
+{
+	register int i;
+	
+	for(i=alen-1;i>0;i--)
+		if(!mpIsZero(a[i], gf->plen))
+			return (UINT)i;
+
+	return 0;
+}
+
+int gf_ele_div(GF_T *gf, GF_ELE q, UINT qlen, GF_ELE r, UINT rlen, GF_ELE a, UINT alen, GF_ELE b, UINT blen)
+{
+	register int i;
+	GF_ELE t;
+	GF_ELE r1;
+	int d;
+	UINT rdeg;
+	UINT adeg;
+	UINT bdeg;
+	DIGIT_T *u;
+	DIGIT_T *v;
+
+	gf_ele_zero(gf, q, qlen);	
+	gf_ele_zero(gf, r, rlen);	
+
+	/* check if b(x) = 0 => oops division by zero */
+	if(gf_ele_is_zero(gf, b, blen))
+		return -1;	
+	
+	/* if degree[a(x)] < degree[b(x)] => no devision needed */
+	if((adeg=gf_poly_deg(gf, a, alen)) < (bdeg=gf_poly_deg(gf, b, blen))) {	
+		if(rlen >= adeg) {		
+			gf_ele_equal(gf, r, a, adeg);
+			return 0;
+		}
+		return -1; /* not enough memory for r(x) */
+	}	
+	
+	/* temp memory */	
+	t = gf_ele_init(gf, alen);
+	r1 = gf_ele_init(gf, alen);
+	u = (DIGIT_T *)malloc(NBYTE(gf->plen));
+	v = (DIGIT_T *)malloc(NBYTE(gf->plen));
+	
+	/* make r1(x) = a(x) */
+	gf_ele_equal(gf, r1, a, alen);
+
+	while(1) {
+		
+		/* compute degree of r1(x) */
+		rdeg = gf_poly_deg(gf, r1, alen);
+	
+		/* if r1(x)'s degree is less than b(x)'s degree, nothing more to be done */
+		/* also if r1(x) = 0, stop dividing */
+		if(((d = rdeg - bdeg) < 0) || gf_ele_is_zero(gf, r1, alen))
+			break;
+		
+		mpModInv(u, b[bdeg], gf->p, gf->plen);
+		mpModMult(v, u, r1[rdeg], gf->p, gf->plen);
+		
+		/* q(x) = q(x) + v*x^d */
+		mpSetEqual(q[d], v, gf->plen);
+
+		/* r1(x) = r1(x) - v*x^d*b(x) */
+		gf_ele_zero(gf, t, alen);
+		for(i=0; i<=bdeg; i++){
+			mpSetEqual(t[i+d], b[i], gf->plen);
+			mpModMult(t[i+d], t[i+d], v, gf->p, gf->plen);
+		}
+		gf_ele_sub(gf, r1, r1, t, rdeg+1);		 
+	}		 
+	
+	/* set r(x) = r1(x) */
+	if(rlen+1 < rdeg){
+		/* not enough memory for r(x), free memory and exit */	
+		gf_ele_free(t, blen);
+		gf_ele_free(r1, blen);
+		
+		return -1;
+	}
+	gf_ele_equal(gf, r, r1, rdeg+1);
+	
+	/* free memory */
+	gf_ele_free(t, blen);
+	gf_ele_free(r1, blen);
+	free(u);
+	free(v);	
+	
+	return 0;
+}
+
+int gf_ele_reduce(GF_T *gf, GF_ELE a, GF_ELE b, UINT blen)
+{
+	/* hic, enough time for trivial	division only */
+	/* anyway, be noted that n_k coeffcient of n(x) is 1 ~ n(x) is monic */
+	GF_ELE t;
+	GF_ELE r;
+	UINT rdeg;
+	register int i;
+	int d;
+		
+	t = gf_ele_init(gf, blen);
+	
+	r = gf_ele_init(gf, blen);
+	
+	/* make r(x) = b(x) */
+	gf_ele_equal(gf, r, b, blen);
+
+	while(1) {
+		
+		/* compute degree of r(x) */
+		rdeg = gf_poly_deg(gf, r, blen);
+		
+		/* if r(x)'s degree is less than k, nothing more to be done */
+		if((d = rdeg - gf->k) < 0)
+			break;
+		
+		/* otherwise, reduce rdeg. First, t(x) = r_{rdeg}*x^{rdeg-k}*n(x) */
+		gf_ele_zero(gf, t, blen);
+		for(i=0; i<=gf->k; i++){
+			mpSetEqual(t[i+d], gf->n[i], gf->plen);
+			mpModMult(t[i+d], t[i+d], r[rdeg], gf->p, gf->plen);
+		}
+		
+		/* Now kill off x^{rdeg} by r(x) = r(x) - t(x) */
+		gf_ele_sub(gf, r, r, t, rdeg+1);
+			 
+	}		 
+	
+	/* set a(x) = r(x)  */
+	gf_ele_equal(gf, a, r, gf->k);
+
+	/* free memory */
+	gf_ele_free(t, blen);
+	gf_ele_free(r, blen);
+	
+	return 0;
+}
+
+int gf_ele_mul(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len)
+{
+	/* just use trivial multiplication */
+	GF_ELE t1;
+	GF_ELE t2;
+		
+	register int i;
+	register int j;
+	
+	t1 = gf_ele_init(gf, 2*len);
+	t2 = gf_ele_init(gf, 2*len);
+	
+	/* t1(x) = 0 */
+	gf_ele_zero(gf, t1, 2*len);
+	
+
+	for(i=0; i<len; i++){
+		/* t2(x) = b_i*x^i*c(x) */
+		gf_ele_zero(gf, t2, 2*len);		
+		for(j=0; j<len; j++)
+			mpModMult(t2[j+i], c[j], b[i], gf->p, gf->plen);
+		
+		/* t1(x) = t1(x) + t2(x) */
+		gf_ele_add(gf, t1, t1, t2, 2*len);
+	}
+	
+	/* reduce modulo n(x) */
+	gf_ele_reduce(gf, a, t1, 2*len);
+
+	gf_ele_free(t1, 2*len);
+	gf_ele_free(t2, 2*len);
+	
+	return 0;
+}
+
+int gf_ele_sqr(GF_T *gf, GF_ELE a, GF_ELE b, UINT blen)
+{
+	/* no fancy algorithm, no precomputation, just call gf_ele_mul here */	
+	return gf_ele_mul(gf, a, b, b, blen);
+}
+
+int gf_ele_inverse(GF_T *gf, GF_ELE a, GF_ELE b)
+{
+#if 0 
+	/* Use Extended Euclidean Algorithm */
+	GF_ELE	r1;	
+	GF_ELE 	r2;
+	GF_ELE	t1;
+	GF_ELE	t2;
+	GF_ELE  r;
+	GF_ELE  q;
+	GF_ELE	t;
+	DIGIT_T *h;
+	register int i;
+	UINT rdeg;
+	
+	r1 = gf_ele_init(gf, gf->k+1);
+	r2 = gf_ele_init(gf, gf->k+1);
+	t1 = gf_ele_init(gf, gf->k+1);
+	t2 = gf_ele_init(gf, gf->k+1);
+	r = gf_ele_init(gf, gf->k+1);
+	q = gf_ele_init(gf, gf->k+1);
+	t = gf_ele_init(gf, gf->k+1);
+	h = (DIGIT_T *)malloc(NBYTE(gf->plen));
+	
+	/* h = -1 mod p */
+	mpShortSub(h, gf->p, 1, gf->plen);
+
+	/* r1(x) = n(x) */
+	gf_ele_equal(gf, r1, gf->n, gf->k+1);
+
+	/* r2(x) = b(x) */
+	gf_ele_equal(gf, r2, b, gf->k);
+	mpSetZero(r2[gf->k], gf->plen);
+
+	/* t1(x) = 0 */
+	gf_ele_zero(gf, t1, gf->k+1);
+
+	/* t2(x) = 1 */
+	gf_ele_unit(gf, t2, gf->k+1);
+	
+	while(1){
+		/* loop until gcd, which is 1, is reached */
+		rdeg = gf_poly_deg(gf, r2, gf->k+1);
+				
+		if(gf_ele_is_unit(gf, r2, gf->k+1))
+			break;
+
+		/* compute r(x) = r1(x) mod r2(x) */
+		/*     and q(x) =  r1(x) / r2(x) */
+		if(gf_ele_div(gf, q, gf->k+1, r, gf->k+1, r1, gf->k+1, r2, gf->k+1) == -1){
+			printf("Something wrong!\n");
+		}
+	
+		/* for next round, r2(x) = r(x) and r1(x) = r2(x) */ 
+		gf_ele_equal(gf, r1, r2, gf->k+1);		
+		gf_ele_equal(gf, r2, r, gf->k+1);
+
+		/* t(x) = -q(x)*t2(x) + t1(x) */
+		for(i=0; i<gf->k+1; i++)
+			mpModMult(q[i], q[i], h, gf->p, gf->plen);
+		
+		gf_ele_mul(gf, r, q, t2, gf->k+1);	
+		gf_ele_add(gf, t, r, t1, gf->k+1);	
+		
+		/* until finished, inverse a(x) = t(x) */
+		gf_ele_equal(gf, a, t, gf->k); 
+
+		/* for next round: t2(x) = t(x) and t1(x) = t2(x) */		
+		gf_ele_equal(gf, t1, t2, gf->k+1);		
+		gf_ele_equal(gf, t2, t, gf->k+1);
+	}
+	
+	gf_ele_free(r1, gf->k+1);
+	gf_ele_free(r2, gf->k+1);
+	gf_ele_free(t1, gf->k+1);
+	gf_ele_free(t2, gf->k+1);
+	gf_ele_free(r, gf->k+1);
+	gf_ele_free(q, gf->k+1);
+	gf_ele_free(t, gf->k+1);
+#endif
+	/* or just use fermat's theorem, a(x) = b(x)^{p^2-2} mod n(x) */
+	DIGIT_T *q;	
+	
+	q = (DIGIT_T *)malloc(2*NBYTE(gf->plen));
+	mpSquare(q, gf->p, gf->plen);
+	mpShortSub(q, q, 2, 2*gf->plen);
+	
+	gf_ele_exp(gf, a, b, q, 2*gf->plen);
+	
+	free(q);
+
+	return 0;
+}
+
+int gf_ele_exp(GF_T *gf, GF_ELE a, GF_ELE b, DIGIT_T *e, UINT elen)
+{
+	/* binary left-to-right method */	
+	register int i, j;
+	register DIGIT_T mask;
+	
+	/* a(x) = 1 */
+	gf_ele_unit(gf, a, gf->k);
+	
+	for(i=elen-1; i>=0;i--)		
+		for(j=BITS_PER_DIGIT-1, mask = HIBITMASK; j>=0; j--, mask >>= 1){
+			/* a(x) = a(x)^2 */
+			gf_ele_sqr(gf, a, a, gf->k);
+
+			/* if j-th bit in the i-th digit is 1, a(x) = b(x)*a(x) */
+			if(e[i] & mask)				
+				gf_ele_mul(gf, a, a, b, gf->k);	
+		}
+
+	return 0;
+}
+
+void gf_ele_print(GF_T *gf, const char *desc, GF_ELE a, UINT len)
+{
+	register int i;
+
+	printf("[%s]\n", desc);
+	for(i=0;i<len;i++)	
+		mpPrintNL(a[i], gf->plen); 
+}
+
+#define GF_N_STRESS_TEST 1000
+int gf_stress_test(GF_T *gf, GF_ELE a, GF_ELE a2)
+{
+	/* prove that gf_ele_sqr behaves consistently */
+	GF_ELE ele[GF_N_STRESS_TEST];
+	int i, j;
+
+	for(i=0; i<GF_N_STRESS_TEST; i++)
+		ele[i] = gf_ele_init(gf, gf->k);
+	
+	for(i=0; i<GF_N_STRESS_TEST; i++){
+		gf_ele_sqr(gf, ele[i], a, gf->k);
+		if(!gf_ele_is_equal(gf, ele[i], a2, gf->k)){
+			for(j=0; j<GF_N_STRESS_TEST; j++)
+				gf_ele_free(ele[j], gf->k);
+			return 0;
+		}
+	}
+	
+	for(j=0; j<GF_N_STRESS_TEST; j++)
+		gf_ele_free(ele[j], gf->k);
+
+	return 1;	
+}
diff --git a/src/libm/galois.h b/src/libm/galois.h
new file mode 100644
index 000000000000..24bfbaa74825
--- /dev/null
+++ b/src/libm/galois.h
@@ -0,0 +1,101 @@ 
+/*-----------------------------------------------------------*/
+/* General Galois field implementation using polynomia basis */
+/* This applies for field GF(p^k) with large prime p         */
+/* Author: Dang Nguyen Duc                                   */
+/* Date  : 2007/02/03                                        */
+/*-----------------------------------------------------------*/
+
+#ifndef _GALOIS_H
+#define _GALOIS_H
+
+#include "bigdigits.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GF_ELE	DIGIT_T** 	/* one field element is a polynomial in F_p[x]/n(x) */
+
+typedef struct {
+	DIGIT_T		*p;	/* field characteristic */
+	UINT		plen;	/* length of p in digit */	
+	UINT		k;	/* extension degree - small please :) */
+	GF_ELE		n;	/* irreducible polynomial in F_p[x] of order k */
+} GF_T;
+
+/* function prototypes */
+GF_T *gf_init(UINT k, DIGIT_T *p, UINT plen);
+	/* allocate memory for GF_T struct including its members */
+
+void gf_free(GF_T *gf);
+	/* free memory allocated to GF_T struct including its members */
+
+void gf_member_free(GF_T *gf);
+	/* free memory allocated to GF_T struct's members only */
+
+GF_ELE gf_ele_init(GF_T *gf, UINT len);
+	/* intialize a field element */
+
+void gf_ele_free(GF_ELE a, UINT len);
+	/* free memory allocated to a(x) */
+
+int gf_ele_zero(GF_T *gf, GF_ELE a, UINT len);
+	/* make a(x) = 0 */
+
+int gf_ele_is_zero(GF_T *gf, GF_ELE a, UINT len);
+	/* return true if a(x) = 0 */
+
+int gf_ele_unit(GF_T *gf, GF_ELE a, UINT len);
+	/* make a(x) = 1 */
+
+int gf_ele_is_unit(GF_T *gf, GF_ELE a, UINT len);
+	/* return true if a(x) = 1 */
+
+int gf_ele_equal(GF_T *gf, GF_ELE a, GF_ELE b, UINT len);
+	/* make a(x) = b(x) */
+
+int gf_ele_is_equal(GF_T *gf, GF_ELE a, GF_ELE b, UINT len);
+	/* return true if a(x) = b(x) */
+
+int gf_ele_random(GF_T *gf, GF_ELE a, UINT len);
+	/* generate a random polynomial in GF(p^k) */
+
+int gf_ele_add(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len);
+	/* compute a(x) = b(x) + c(x) */
+
+int gf_ele_sub(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len);
+	/* compute a(x) = b(x) - c(x) */
+
+UINT gf_poly_deg(GF_T *gf, GF_ELE a, UINT alen);
+	/* return degree of polynomial a(x) */
+
+int gf_ele_reduce(GF_T *gf, GF_ELE a, GF_ELE b, UINT blen);
+	/* compute a(x) = b(x) mod n(x) - n(x) is part gf */
+
+int gf_ele_mul(GF_T *gf, GF_ELE a, GF_ELE b, GF_ELE c, UINT len);
+	/* compute a(x) = b(x)*c(x) mod n(x) */
+
+int gf_ele_sqr(GF_T *gf, GF_ELE a, GF_ELE b, UINT blen);
+	/* compute a(x) = b(x)^2 mod n(x) */
+
+int gf_ele_div(GF_T *gf, GF_ELE q, UINT qlen, GF_ELE r, UINT rlen, GF_ELE a, UINT alen, GF_ELE b, UINT blen);
+	/* polynomial division, compute r(x) and q(x) such that a(x) = b(x)*q(x) + r(x) */
+	/* degree[r(x)] < degree[b(x)] */
+
+int gf_ele_inverse(GF_T *gf, GF_ELE a, GF_ELE b);
+	/* compute multiplicative inverse a(x) = b(x)^{-1} mod n(x) */
+	/* restriction: on degree of b(x) < degree of n(x) */
+
+int gf_ele_exp(GF_T *gf, GF_ELE a, GF_ELE b, DIGIT_T *e, UINT elen);
+	/* compute a(x) = b(x)^e mod n(x) */
+
+void gf_ele_print(GF_T *gf, const char *desc, GF_ELE a, UINT len);
+	/* print out a field element with description */
+
+int gf_stress_test(GF_T *gf, GF_ELE a, GF_ELE a2);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libm/hash.c b/src/libm/hash.c
new file mode 100644
index 000000000000..d28bbb6f5f45
--- /dev/null
+++ b/src/libm/hash.c
@@ -0,0 +1,114 @@ 
+/* Hash wrapper functions */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mcrypto.h"
+#include "bigdigits.h"
+#include "hash.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha2.h"
+
+void GenSeed(BYTE *p, UINT len)
+{
+	prng(p, len);
+}
+
+UINT HashLenQuery(UINT hid)
+{
+	UINT hlen;	/* in byte */
+	
+	switch(hid) {
+	case HASH_MD5:		hlen = 16; break;
+	case HASH_SHA1:		hlen = 20; break;
+	case HASH_SHA256:	hlen = 32; break;
+	case HASH_SHA384:	hlen = 48; break;
+	case HASH_SHA512:	hlen = 64; break;
+	default: hlen = 0;
+	}
+ 	
+ 	return hlen;
+}
+
+int MD5Hash(BYTE *data, UINT len, BYTE *hash)
+{
+	/* To do: length of input checking */
+	MD5_CTX md5context;
+	
+	MD5Init(&md5context);
+	MD5Update(&md5context, data, len);
+	MD5Final(&md5context);
+	
+	memcpy(hash, md5context.digest, 16);
+	
+	return 0;
+}
+
+int SHA1Hash(BYTE *data, UINT len, BYTE *hash)
+{
+	/* To do: length of input checking */
+	SHA1_CTX sha1context;
+	
+	SHA1Init(&sha1context);
+	SHA1Update(&sha1context, data, len);
+	SHA1Final(hash, &sha1context);
+	
+	return 0;
+}
+
+int SHA256Hash(BYTE *data, UINT len, BYTE *hash)
+{
+	/* To do: length of input checking */
+	sha256_ctx sha256context;
+	
+	sha256_begin(&sha256context);
+	sha256_hash(data, len, &sha256context);
+	sha256_end(hash, &sha256context);
+	
+	return 0;
+}
+
+int SHA384Hash(BYTE *data, UINT len, BYTE *hash)
+{
+	/* To do: length of input checking */
+	sha384_ctx sha384context;
+	
+	sha384_begin(&sha384context);
+	sha384_hash(data, len, &sha384context);
+	sha384_end(hash, &sha384context);
+	
+	return 0;
+}
+
+int SHA512Hash(BYTE *data, UINT len, BYTE *hash)
+{
+	/* To do: length of input checking */
+	sha512_ctx sha512context;
+	
+	sha512_begin(&sha512context);
+	sha512_hash(data, len, &sha512context);
+	sha512_end(hash, &sha512context);
+	
+	return 0;
+}
+
+int Hash(UINT hid, BYTE *data, UINT len, BYTE *hash)
+{
+	/* Compute hash value of data */
+	switch(hid) {
+	case HASH_MD5:	  return MD5Hash(data, len, hash); 
+	case HASH_SHA1:	  return SHA1Hash(data, len, hash); 
+	case HASH_SHA256: return SHA256Hash(data, len, hash);
+	case HASH_SHA384: return SHA384Hash(data, len, hash);
+	case HASH_SHA512: return SHA512Hash(data, len, hash);
+	default: return -1;	/* unknown hash algorithm */
+	}
+	
+	return 0;
+}
+
+int Hash2BigInt(UINT hid, BYTE* data, UINT len, DIGIT_T *p)
+{
+	/* have to allocate memory for p yourself */
+	return Hash(hid, data, len, (BYTE *)p);
+}
diff --git a/src/libm/hash.h b/src/libm/hash.h
new file mode 100644
index 000000000000..80babc34d40f
--- /dev/null
+++ b/src/libm/hash.h
@@ -0,0 +1,49 @@ 
+/* Hash wrapper header file */
+#ifndef _HASH_H_
+#define _HASH_H_
+
+#include "bigdigits.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Message-digest algorithms. */
+#define HASH_MD5	1
+#define HASH_SHA1	2
+#define HASH_SHA256	3 
+#define HASH_SHA384	4
+#define HASH_SHA512	5
+
+void GenSeed(BYTE *p, UINT len);
+	/* Generate a len-byte pseudorandom number for hash seed */
+
+int MD5Hash(BYTE *data, UINT len, BYTE *hash);
+	/* MD5 Hash Function Call Interface */
+	
+int SHA1Hash(BYTE *data, UINT len, BYTE *hash);
+	/* SHA1 Hash Function Call Interface */
+
+int SHA256Hash(BYTE *data, UINT len, BYTE *hash);
+	/* SHA256 Hash Function Call Interface */
+	
+int SHA384Hash(BYTE *data, UINT len, BYTE *hash);
+	/* SHA384 Hash Function Call Interface */
+
+int SHA512Hash(BYTE *data, UINT len, BYTE *hash);
+	/* SHA512 Hash Function Call Interface */
+
+int Hash(UINT hid, BYTE *data, UINT len, BYTE *hash);
+	/* Generic Hash Function Call Interface */
+
+UINT HashLenQuery(UINT hid);
+	/* Query Output Length of a Hash Function Specified by hid */
+
+int Hash2BigInt(UINT hid, BYTE* data, UINT len, DIGIT_T *p);
+	/* Hash directly to big integer */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _HASH_H_ */
diff --git a/src/libm/mcrypto.h b/src/libm/mcrypto.h
new file mode 100644
index 000000000000..2beaa99cfc09
--- /dev/null
+++ b/src/libm/mcrypto.h
@@ -0,0 +1,34 @@ 
+/* libmcrypto - math crypto library - header file */
+#ifndef _MCRYPTO_H_
+#define _MCRYPTO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* data type macros */
+#define UINT 	unsigned int
+#define BYTE	unsigned char
+#define DWORD 	unsigned long
+
+/* define all return codes here */
+
+/* some C preprocessors to customize the lib operation */
+#define STRONG_RANDOM	1	/* use cryptographic prng rather than rand() function */
+#define LINUX_URANDOM	1	/* use linux's /dev/urandom for cryptographic prng */
+#define N_TEST_PRIME 200	/* The number of rounds for Miller-Rabin primality test */
+
+int prng(BYTE* buf, int buf_size);
+	/* generate pseudo-random numbers using linux's /dev/urandom */
+
+void mcrypto_msg(const char *s);
+	/* enable MCRYPTO_DEBUG to dump simple debug message to stdout */
+
+void mcrypto_dump(char *desc, BYTE *p, UINT len);
+	/* more detail debug information */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libm/md5.c b/src/libm/md5.c
new file mode 100644
index 000000000000..93150f9cde3b
--- /dev/null
+++ b/src/libm/md5.c
@@ -0,0 +1,296 @@ 
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version                   **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using MD5Init        **
+ **    (2) Call MD5Update on mdContext and M                          **
+ **    (3) Call MD5Final on mdContext                                 **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+  }
+
+/* The routine MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+  mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = (UINT4)0x67452301;
+  mdContext->buf[1] = (UINT4)0xefcdab89;
+  mdContext->buf[2] = (UINT4)0x98badcfe;
+  mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((UINT4)inLen << 3);
+  mdContext->i[1] += ((UINT4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+                (((UINT4)mdContext->in[ii+2]) << 16) |
+                (((UINT4)mdContext->in[ii+1]) << 8) |
+                ((UINT4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5Final (mdContext)
+MD5_CTX *mdContext;
+{
+  UINT4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+            (((UINT4)mdContext->in[ii+2]) << 16) |
+            (((UINT4)mdContext->in[ii+1]) << 8) |
+            ((UINT4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+  UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13,  606105819); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */
+  FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */
+  FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */
+  FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */
+  FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */
+  FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */
+  FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */
+  GG ( c, d, a, b, in[11], S23,  643717713); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */
+  GG ( d, a, b, c, in[10], S22,   38016083); /* 22 */
+  GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21,  568446438); /* 25 */
+  GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */
+  GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */
+  GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */
+  HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */
+  HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */
+  HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */
+  HH ( a, b, c, d, in[13], S31,  681279174); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34,   76029189); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */
+  HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */
+  HH ( c, d, a, b, in[15], S33,  530742520); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */
+  II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */
+  II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */
+  II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */
+  II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */
+  II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */
+  II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */
+  II ( c, d, a, b, in[ 2], S43,  718787259); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c                                                      **
+ ******************************** (cut) ********************************
+ */
diff --git a/src/libm/md5.h b/src/libm/md5.h
new file mode 100644
index 000000000000..8a23a20293b4
--- /dev/null
+++ b/src/libm/md5.h
@@ -0,0 +1,57 @@ 
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#ifndef _MD5_H
+#define _MD5_H
+/* typedef a 32-bit type */
+typedef unsigned long UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */
+  UINT4 buf[4];                                    /* scratch buffer */
+  unsigned char in[64];                              /* input buffer */
+  unsigned char digest[16];     /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init ();
+void MD5Update ();
+void MD5Final ();
+
+#endif
diff --git a/src/libm/mpAND.c b/src/libm/mpAND.c
new file mode 100644
index 000000000000..1a04c7368015
--- /dev/null
+++ b/src/libm/mpAND.c
@@ -0,0 +1,9 @@ 
+/* mpAND.c: multi-precision bitwise AND */
+
+#include "bigdigits.h"
+
+void mpAND(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits)	
+{
+	while(ndigits--)
+		a[ndigits] = x[ndigits] & y[ndigits];
+}
diff --git a/src/libm/mpAdd.c b/src/libm/mpAdd.c
new file mode 100644
index 000000000000..b5624cf3250c
--- /dev/null
+++ b/src/libm/mpAdd.c
@@ -0,0 +1,41 @@ 
+/* mpAdd.c */
+
+#include <assert.h>
+#include "bigdigits.h"
+
+DIGIT_T mpAdd(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits)
+{
+	/*	Calculates w = u + v
+		where w, u, v are multiprecision integers of ndigits each
+		Returns carry if overflow. Carry = 0 or 1.
+
+		Ref: Knuth Vol 2 Ch 4.3.1 p 266 Algorithm A.
+	*/
+
+	DIGIT_T k;
+	UINT j;
+	
+	assert(w != v);
+
+	/* Step A1. Initialise */
+	k = 0;
+
+	for (j = 0; j < ndigits; j++) {
+		/*	Step A2. Add digits w_j = (u_j + v_j + k)
+			Set k = 1 if carry (overflow) occurs
+		*/
+		w[j] = u[j] + k;
+		if (w[j] < k)
+			k = 1;
+		else
+			k = 0;
+		
+		w[j] += v[j];
+		if (w[j] < v[j])
+			k++;
+
+	}	/* Step A3. Loop on j */
+
+	return k;	/* w_n = k */
+}
+
diff --git a/src/libm/mpBitLength.c b/src/libm/mpBitLength.c
new file mode 100644
index 000000000000..0400796ed1a9
--- /dev/null
+++ b/src/libm/mpBitLength.c
@@ -0,0 +1,24 @@ 
+/* mpBitLength - return bit length of a big integer */
+#include "bigdigits.h"
+
+UINT mpBitLength(const DIGIT_T d[], UINT ndigits)
+{
+	UINT n, i, bits;
+	DIGIT_T mask;
+
+	if (!d || ndigits == 0)
+		return 0;
+
+	n = mpSizeof(d, ndigits);
+	if (0 == n) return 0;
+
+	for (i = 0, mask = HIBITMASK; mask > 0; mask >>= 1, i++)
+	{
+		if (d[n-1] & mask)
+			break;
+	}
+
+	bits = n * BITS_PER_DIGIT - i;
+
+	return bits;
+}
diff --git a/src/libm/mpCompare.c b/src/libm/mpCompare.c
new file mode 100644
index 000000000000..4e26c2960e61
--- /dev/null
+++ b/src/libm/mpCompare.c
@@ -0,0 +1,21 @@ 
+/* mpCompare.c */
+
+#include "bigdigits.h"
+
+int mpCompare(const DIGIT_T a[], const DIGIT_T b[], UINT ndigits)
+{
+	/*	Returns sign of (a - b)
+	*/
+
+	if (ndigits == 0) return 0;
+
+	while (ndigits--){
+		if (a[ndigits] > b[ndigits])
+			return 1;	/* GT */
+		if (a[ndigits] < b[ndigits])
+			return -1;	/* LT */
+	}
+
+	return 0;	/* EQ */
+}
+
diff --git a/src/libm/mpComplement.c b/src/libm/mpComplement.c
new file mode 100644
index 000000000000..233200b908d9
--- /dev/null
+++ b/src/libm/mpComplement.c
@@ -0,0 +1,9 @@ 
+/* mpComplement.c: multi-precicion bitwise complement */
+
+#include "bigdigits.h"
+
+void mpComplement(DIGIT_T a[], const DIGIT_T b[], UINT ndigits)
+{
+	while(ndigits--)
+		 a[ndigits] = ~b[ndigits];
+}
diff --git a/src/libm/mpDivide.c b/src/libm/mpDivide.c
new file mode 100644
index 000000000000..53c4209bd3ed
--- /dev/null
+++ b/src/libm/mpDivide.c
@@ -0,0 +1,202 @@ 
+/* mpDivide.c */
+
+#include "bigdigits.h"
+
+static DIGIT_T mpMultSub(DIGIT_T wn, DIGIT_T w[], const DIGIT_T v[], DIGIT_T q, UINT n);
+
+static int QhatTooBig(DIGIT_T qhat, DIGIT_T rhat, DIGIT_T vn2, DIGIT_T ujn2);
+
+int mpDivide(DIGIT_T q[], DIGIT_T r[], const DIGIT_T u[], UINT udigits, const DIGIT_T v[], UINT vdigits)
+{	/*	Computes quotient q = u / v and remainder r = u mod v
+		where q, r, u are multiple precision digits
+		all of udigits and the divisor v is vdigits.
+
+		Ref: Knuth Vol 2 Ch 4.3.1 p 272 Algorithm D.
+
+		Do without extra storage space, i.e. use r[] for
+		normalised u[], unnormalise v[] at end, and cope with
+		extra digit Uj+n added to u after normalisation.
+
+		WARNING: this trashes q and r first, so cannot do
+		u = u / v or v = u mod v.
+	*/
+	UINT shift;
+	int n, m, j;
+	DIGIT_T bitmask, overflow;
+	DIGIT_T qhat, rhat, t[2];
+	DIGIT_T *uu, *ww;
+	int qhatOK, cmp;
+
+	/* Clear q and r */
+	mpSetZero(q, udigits);
+	mpSetZero(r, udigits);
+
+	/* Work out exact sizes of u and v */
+	n = (int)mpSizeof(v, vdigits);
+	m = (int)mpSizeof(u, udigits);
+	m -= n;
+
+	/* Catch special cases */
+	if (n == 0)
+		return -1;	/* Error: divide by zero */
+
+	if (n == 1){	
+		/* Use short division instead */
+		r[0] = mpShortDiv(q, u, v[0], udigits);
+		return 0;
+	}
+
+	if (m < 0){	
+		/* v > u, so just set q = 0 and r = u */
+		mpSetEqual(r, u, udigits);
+		return 0;
+	}
+
+	if (m == 0){	
+		/* u and v are the same length */
+		cmp = mpCompare(u, v, (UINT)n);
+		if (cmp < 0){	
+			/* v > u, as above */
+			mpSetEqual(r, u, udigits);
+			return 0;
+		}
+		else if (cmp == 0){	
+			/* v == u, so set q = 1 and r = 0 */
+			mpSetDigit(q, 1, udigits);
+			return 0;
+		}
+	}
+
+	/*	In Knuth notation, we have:
+		Given
+		u = (Um+n-1 ... U1U0)
+		v = (Vn-1 ... V1V0)
+		Compute
+		q = u/v = (QmQm-1 ... Q0)
+		r = u mod v = (Rn-1 ... R1R0)
+	*/
+
+	/*	Step D1. Normalise */
+	/*	Requires high bit of Vn-1
+		to be set, so find most signif. bit then shift left,
+		i.e. d = 2^shift, u' = u * d, v' = v * d.
+	*/
+	bitmask = HIBITMASK;
+	for (shift = 0; shift < BITS_PER_DIGIT; shift++){
+		if (v[n-1] & bitmask)
+			break;
+		bitmask >>= 1;
+	}
+
+	/* Normalise v in situ - NB only shift non-zero digits */
+	overflow = mpShiftLeft(v, v, shift, n);
+
+	/* Copy normalised dividend u*d into r */
+	overflow = mpShiftLeft(r, u, shift, n + m);
+	uu = r;	/* Use ptr to keep notation constant */
+
+	t[0] = overflow;	/* New digit Um+n */
+
+	/* Step D2. Initialise j. Set j = m */
+	for (j = m; j >= 0; j--){
+		/* Step D3. Calculate Qhat = (b.Uj+n + Uj+n-1)/Vn-1 */
+		qhatOK = 0;
+		t[1] = t[0];	/* This is Uj+n */
+		t[0] = uu[j+n-1];
+		overflow = spDivide(&qhat, &rhat, t, v[n-1]);
+
+		/* Test Qhat */
+		if (overflow){	
+			/* Qhat = b */
+			qhat = MAX_DIGIT;
+			rhat = uu[j+n-1];
+			rhat += v[n-1];
+			if (rhat < v[n-1])	/* Overflow */
+				qhatOK = 1;
+		}
+		if (!qhatOK && QhatTooBig(qhat, rhat, v[n-2], uu[j+n-2])){	
+			/* Qhat.Vn-2 > b.Rhat + Uj+n-2 */
+			qhat--;
+			rhat += v[n-1];
+			if (!(rhat < v[n-1]))
+				if (QhatTooBig(qhat, rhat, v[n-2], uu[j+n-2]))
+					qhat--;
+		}
+
+
+		/* Step D4. Multiply and subtract */
+		ww = &uu[j];
+		overflow = mpMultSub(t[1], ww, v, qhat, (UINT)n);
+
+		/* Step D5. Test remainder. Set Qj = Qhat */
+		q[j] = qhat;
+		if (overflow){	
+			/* Step D6. Add back if D4 was negative */
+			q[j]--;
+			overflow = mpAdd(ww, ww, v, (UINT)n);
+		}
+
+		t[0] = uu[j+n-1];	/* Uj+n on next round */
+
+	}	/* Step D7. Loop on j */
+
+	/* Clear high digits in uu */
+	for (j = n; j < m+n; j++)
+		uu[j] = 0;
+
+	/* Step D8. Unnormalise. */
+
+	mpShiftRight(r, r, shift, n);
+	mpShiftRight(v, v, shift, n);
+
+	return 0;
+}
+
+static DIGIT_T mpMultSub(DIGIT_T wn, DIGIT_T w[], const DIGIT_T v[], DIGIT_T q, UINT n)
+{	/*	Compute w = w - qv
+		where w = (WnW[n-1]...W[0])
+		return modified Wn.
+	*/
+	DIGIT_T k, t[2];
+	UINT i;
+
+	if (q == 0)	/* No change */
+		return wn;
+
+	k = 0;
+
+	for (i = 0; i < n; i++){
+		spMultiply(t, q, v[i]);
+		w[i] -= k;
+		if (w[i] > MAX_DIGIT - k)
+			k = 1;
+		else
+			k = 0;
+		w[i] -= t[0];
+		if (w[i] > MAX_DIGIT - t[0])
+			k++;
+		k += t[1];
+	}
+
+	/* Cope with Wn not stored in array w[0..n-1] */
+	wn -= k;
+
+	return wn;
+}
+
+static int QhatTooBig(DIGIT_T qhat, DIGIT_T rhat, DIGIT_T vn2, DIGIT_T ujn2)
+{	/*	Returns true if Qhat is too big
+		i.e. if (Qhat * Vn-2) > (b.Rhat + Uj+n-2)
+	*/
+	DIGIT_T t[2];
+
+	spMultiply(t, qhat, vn2);
+	if (t[1] < rhat)
+		return 0;
+	else if (t[1] > rhat)
+		return 1;
+	else if (t[0] > ujn2)
+		return 1;
+
+	return 0;
+}
diff --git a/src/libm/mpEqual.c b/src/libm/mpEqual.c
new file mode 100644
index 000000000000..9f6a36b1effc
--- /dev/null
+++ b/src/libm/mpEqual.c
@@ -0,0 +1,19 @@ 
+/* mpEqual.c */
+
+#include "bigdigits.h"
+
+int mpEqual(const DIGIT_T a[], const DIGIT_T b[], UINT ndigits)
+{
+	/*	Returns true if a == b, else false
+	*/
+
+	if (ndigits == 0) return -1;
+
+	while (ndigits--){
+		if (a[ndigits] != b[ndigits])
+			return 0;	/* False */
+	}
+
+	return (!0);	/* True */
+}
+
diff --git a/src/libm/mpGcd.c b/src/libm/mpGcd.c
new file mode 100644
index 000000000000..345a1dadcc72
--- /dev/null
+++ b/src/libm/mpGcd.c
@@ -0,0 +1,26 @@ 
+/* mpGcd.c */
+
+#include "bigdigits.h"
+
+int mpGcd(DIGIT_T g[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits)
+{	
+	/* Computes g = gcd(x, y) */
+	/* Ref: Schneier  */
+
+	/*	NB This function requires temp storage 
+	*/
+	DIGIT_T yy[MAX_DIG_LEN], xx[MAX_DIG_LEN];
+	
+	mpSetEqual(xx, x, ndigits);
+	mpSetEqual(yy, y, ndigits);
+
+	mpSetEqual(g, yy, ndigits);		/* g = y */
+	
+	while (!mpIsZero(xx, ndigits)){	
+		mpSetEqual(g, xx, ndigits);	/* g = x */
+		mpModulo(xx, yy, ndigits, xx, ndigits);	/* x = y mod x */
+		mpSetEqual(yy, g, ndigits);	/* y = g; */
+	}
+
+	return 0;	/* gcd is in g */
+}
diff --git a/src/libm/mpHalfDiv.c b/src/libm/mpHalfDiv.c
new file mode 100644
index 000000000000..abf37d69a457
--- /dev/null
+++ b/src/libm/mpHalfDiv.c
@@ -0,0 +1,99 @@ 
+/* mpHalfDiv.c */
+
+#include "bigdigits.h"
+
+/* Two alternative methods - Knuth and Zimmerman */
+DIGIT_T mpHalfDivK(DIGIT_T q[], const DIGIT_T u[], HALF_DIGIT_T v, UINT ndigits);
+DIGIT_T mpHalfDivZ(DIGIT_T q[], const DIGIT_T a[], HALF_DIGIT_T d, UINT ndigits);
+
+DIGIT_T mpHalfDiv(DIGIT_T q[], const DIGIT_T u[], HALF_DIGIT_T v, UINT ndigits)
+{
+	return mpHalfDivK(q, u, v, ndigits);
+}
+
+DIGIT_T mpHalfDivK(DIGIT_T q[], const DIGIT_T u[], HALF_DIGIT_T v, UINT ndigits)
+{
+	/*	Calculates quotient q = u div v
+		Returns remainder r = u mod v
+		where q, u are multiprecision integers of ndigits each
+		and d, v are single precision digits
+		
+		d must be <= MAX_HALF_DIGIT
+
+		Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625
+	*/
+	UINT j;
+	DIGIT_T t, r, qHigh, qLow;
+
+	if (ndigits == 0) return 0;
+	if (v == 0)	return 0;	/* Divide by zero error */
+
+	/* Step S1. */
+	r = 0;
+	j = ndigits;
+	while (j--) {
+		/* Step S2. */
+		t = TOHIGH(r) | HIHALF(u[j]);
+		qHigh = t / v;
+		r = t - qHigh * v;
+
+		t = TOHIGH(r) | LOHALF(u[j]);
+		qLow = t / v;
+		r = t - qLow * v;
+
+		q[j] = TOHIGH(qHigh) | qLow;
+	}
+
+	return r;
+}
+
+DIGIT_T mpHalfDivZ(DIGIT_T q[], const DIGIT_T a[], HALF_DIGIT_T d, UINT ndigits)
+{
+	/*	Calculates quotient q = a div d
+		Returns remainder r = a mod d
+		where q, a are multiprecision integers of ndigits each
+		and d, r are single precision digits
+		using bit-by-bit method from left to right.
+
+		d must be <= MAX_HALF_DIGIT
+
+		Ref: Principles in PGP by Phil Zimmermann
+	*/
+
+	DIGIT_T mask = HIBITMASK;
+	DIGIT_T r = 0;
+	UINT i;
+
+	if (ndigits == 0) return 0;
+
+	/* Initialise quotient */
+	for (i = 0; i < ndigits; i++)
+		q[i] = 0;
+	
+	while (ndigits)
+	{	/* Work from left to right */
+
+		r <<= 1;	/* Multiply remainder by 2 */
+
+		/* Look at current bit */
+		if (a[ndigits-1] & mask)
+			r++;
+		if (r >= d)
+		{
+			r -= d;
+			q[ndigits-1] |= mask;
+		}
+
+		/* Move to next bit */
+		if (mask == 1)
+		{
+			mask = HIBITMASK;
+			ndigits--;
+		}
+		else
+			mask >>= 1;
+	}
+	
+	return r;
+}
+
diff --git a/src/libm/mpHalfMod.c b/src/libm/mpHalfMod.c
new file mode 100644
index 000000000000..2e2dc8ad9b98
--- /dev/null
+++ b/src/libm/mpHalfMod.c
@@ -0,0 +1,46 @@ 
+/* mpHalfMod.c */
+
+
+#include "bigdigits.h"
+
+DIGIT_T mpHalfMod(const DIGIT_T a[], HALF_DIGIT_T d, UINT ndigits)
+{
+	/*	Calculates r = a mod d
+		where a is a multiprecision integer of ndigits
+		and r, d are single precision digits
+		using bit-by-bit method from left to right.
+
+		Ref: Derived from principles in PGP by Phil Zimmermann
+		Note: This method will only work until r <<= 1 overflows.
+		i.e. for d < HIBITMASK, but we keep HALF_DIGIT
+		limit for safety 
+		(and also because we don't have a 31/32nds_digit).
+	*/
+
+	DIGIT_T mask = HIBITMASK;
+	DIGIT_T r = 0;
+
+	if (ndigits == 0) return 0;
+
+	while (ndigits){	
+		/* Work from left to right */
+		r <<= 1;	/* Multiply remainder by 2 */
+
+		/* Look at current bit */
+		if (a[ndigits-1] & mask)
+			r++;
+		if (r >= d)
+			r -= d;
+
+		/* Move to next bit */
+		if (mask == 1){
+			mask = HIBITMASK;
+			ndigits--;
+		}
+		else
+			mask >>= 1;
+	}
+	
+	return r;
+}
+
diff --git a/src/libm/mpIsOne.c b/src/libm/mpIsOne.c
new file mode 100644
index 000000000000..c785c1b780d2
--- /dev/null
+++ b/src/libm/mpIsOne.c
@@ -0,0 +1,18 @@ 
+/* mpIsOne.c */
+
+#include "bigdigits.h"
+
+int mpIsOne(const DIGIT_T a[], UINT ndigits)
+{
+	UINT i;
+	if (ndigits == 0) 
+		return -1;
+
+	for (i = 1; i < ndigits; i++){
+		if (a[i] != 0)
+			return 0;	/* False */
+	}
+
+	return (a[0]==1);
+}
+
diff --git a/src/libm/mpIsPrime.c b/src/libm/mpIsPrime.c
new file mode 100644
index 000000000000..ae235d01616e
--- /dev/null
+++ b/src/libm/mpIsPrime.c
@@ -0,0 +1,124 @@ 
+/* mpIsPrime.c */
+
+#include "bigdigits.h"
+
+static DIGIT_T SMALL_PRIMES[] = {
+	3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 
+	47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 
+	103, 107, 109, 113,
+	127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+	179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
+	233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+	283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
+	353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+	419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
+	467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
+	547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
+	607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
+	661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
+	739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
+	811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
+	877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
+	947, 953, 967, 971, 977, 983, 991, 997,
+};
+
+#define N_SMALL_PRIMES (sizeof(SMALL_PRIMES)/sizeof(DIGIT_T))
+
+int mpIsPrime(const DIGIT_T w[], UINT ndigits, UINT t)
+{	
+	/*	Returns true if w is a probable prime 
+		Carries out t iterations
+		(Use t = 50 for DSS Standard) */
+	/*	Uses Rabin-Miller Probabilistic Primality Test,
+		Ref: FIPS-186-2 Appendix 2.
+		Also Schneier 2nd ed p 260 & Knuth Vol 2, p 379.
+	*/
+
+	/* Temp big digits */
+	DIGIT_T m[MAX_DIG_LEN], a[MAX_DIG_LEN], b[MAX_DIG_LEN];
+	DIGIT_T z[MAX_DIG_LEN], w1[MAX_DIG_LEN];
+	DIGIT_T j[MAX_DIG_LEN];
+	UINT i;
+	int failed, isprime;
+
+	/* Check the obvious */
+	if (mpISEVEN(w, ndigits))
+		return 0;
+
+	/* First check for small primes, unless we could be one ourself */
+	if (mpShortCmp(w, SMALL_PRIMES[N_SMALL_PRIMES-1], ndigits) > 0) {
+		for (i = 0; i < N_SMALL_PRIMES; i++) {
+			if (mpShortMod(w, SMALL_PRIMES[i], ndigits) == 0)
+			return 0; /* Failed */
+		}
+	}
+	else {	
+		/* w is a small number, so check directly */
+		for (i = 0; i < N_SMALL_PRIMES; i++) {
+			if (mpShortCmp(w, SMALL_PRIMES[i], ndigits) == 0)
+				return 1;	/* w is a small prime */
+		}
+		return 0;	/* w is not a small prime */
+	}
+
+	/*	Now do Rabin-Miller  */
+	/*	Step 2. Find a and m where w = 1 + (2^a)m
+		m is odd and 2^a is largest power of 2 dividing w - 1 */
+	mpShortSub(w1, w, 1, ndigits);		/* Store w1 = w - 1 */
+	mpSetEqual(m, w1, ndigits);		/* Set m = w - 1 */
+	
+	/* for (a = 0; iseven(m); a++) */
+	for (mpSetZero(a, ndigits); mpISEVEN(m, ndigits); mpShortAdd(a, a, 1, ndigits))
+		/* Divide by 2 until m is odd */
+		mpShiftRight(m, m, 1, ndigits);
+	
+
+	/* assert((1 << a) * m + 1 == w); */
+
+	isprime = 1;
+	for (i = 0; i < t; i++) {
+		failed = 1;	/* Assume fail unless passed in loop */
+		/* Step 3. Generate random integer 1 < b < w */
+		mpSetZero(b, ndigits);
+		do {
+			b[0] = spPseudoRand(2, MAX_DIGIT);
+		} while (mpCompare(b, w, ndigits) >= 0);
+
+		/* assert(1 < b && b < w); */
+
+		/* Step 4. Set j = 0 and z = b^m mod w */
+		mpSetZero(j, ndigits);
+		mpModExp(z, b, m, w, ndigits);
+		do {
+			/* Step 5. If j = 0 and z = 1, or if z = w - 1 */
+			/* i.e. if ((j == 0 && z == 1) || (z == w - 1)) */
+			if ((mpIsZero(j, ndigits) && mpShortCmp(z, 1, ndigits) == 0) || (mpCompare(z, w1, ndigits) == 0)) {	
+				/* Passes on this loop  - go to Step 9 */
+				failed = 0;
+				break;
+			}
+
+			/* Step 6. If j > 0 and z = 1 */
+			if (!mpIsZero(j, ndigits) && (mpShortCmp(z, 1, ndigits) == 0)) {	
+				/* Fails - go to Step 8 */
+				failed = 1;
+				break;
+			}
+
+			/* Step 7. j = j + 1. If j < a set z = z^2 mod w */
+			mpShortAdd(j, j, 1, ndigits);
+			if (mpCompare(j, a, ndigits) < 0)
+				mpModMult(z, z, z, w, ndigits);
+			/* Loop: if j < a go to Step 5 */
+		} while (mpCompare(j, a, ndigits) < 0);
+
+		if (failed) {	
+			/* Step 8. Not a prime - stop */
+			isprime = 0;
+			break;
+		}
+	}	/* Step 9. Go to Step 3 until i >= n */
+	/* Else, if i = n, w is probably prime => success */
+
+	return isprime;
+}
diff --git a/src/libm/mpIsZero.c b/src/libm/mpIsZero.c
new file mode 100644
index 000000000000..647a7b313ab5
--- /dev/null
+++ b/src/libm/mpIsZero.c
@@ -0,0 +1,19 @@ 
+/* mpIsZero.c */
+
+#include "bigdigits.h"
+
+int mpIsZero(const DIGIT_T a[], UINT ndigits)
+{
+	UINT i;
+	if (ndigits == 0) 
+		return -1;
+
+	/* Start at lsb */	
+	for (i = 0; i < ndigits; i++){
+		if (a[i] != 0)
+			return 0;	/* False */
+	}
+
+	return (!0);	/* True */
+}
+
diff --git a/src/libm/mpJacobi.c b/src/libm/mpJacobi.c
new file mode 100644
index 000000000000..5b99fe88fe50
--- /dev/null
+++ b/src/libm/mpJacobi.c
@@ -0,0 +1,44 @@ 
+/* Jacobi Symbol Computation */ 
+#include "bigdigits.h"
+
+int mpJacobi(int *val, const DIGIT_T a[], const DIGIT_T m[], UINT len)
+{
+	/* Compute Jacobi symbol val = (a/m) */
+	
+	int j = 1;
+	DIGIT_T temp_a[MAX_DIG_LEN], temp_m[MAX_DIG_LEN];
+	
+	/* return error if n is not odd */
+	if(mpISEVEN(m, len))
+		return -1;
+	
+	mpSetEqual(temp_a, a, len);
+	mpSetEqual(temp_m, m, len);
+	
+	while(!mpIsZero(temp_a, len)){
+		while(mpISEVEN(temp_a, len)){
+			/* a = a / 2 */
+			mpShiftRight(temp_a, temp_a, 1, len); 
+			
+			/* if (m mod 8 = 3) or (m mod 8 = 5) */
+			if((mpShortMod(temp_m, 8, len) == 3) || (mpShortMod(temp_m, 8, len) == 5))
+				j = -j;
+		}
+		/* a <--> m */
+		mpSwap(temp_a, temp_m, len);
+		
+		/* if (a mod 4 = 3) and (m mod 4 = 3) */
+		if((mpShortMod(temp_a, 4, len) == 3) && (mpShortMod(temp_m, 4, len) == 3))
+			j = -j;
+		
+		/* a = a mod m */
+		mpModulo(temp_a, temp_a, len, temp_m, len);
+	}
+	/* if m = 1 */
+	if(mpShortCmp(temp_m, 1, len)==0)
+		*val = j;
+	else
+		*val = 0;
+	
+	return 0;
+}
diff --git a/src/libm/mpLegendre.c b/src/libm/mpLegendre.c
new file mode 100644
index 000000000000..baaa799832ab
--- /dev/null
+++ b/src/libm/mpLegendre.c
@@ -0,0 +1,8 @@ 
+/* Legendre Symbol Computation */ 
+
+#include "bigdigits.h"
+
+int mpLegendre(int *val, const DIGIT_T a[], const DIGIT_T p[], UINT len)
+{
+	return mpJacobi(val, a, p, len);
+}
diff --git a/src/libm/mpModAdd.c b/src/libm/mpModAdd.c
new file mode 100644
index 000000000000..bd21fef2566d
--- /dev/null
+++ b/src/libm/mpModAdd.c
@@ -0,0 +1,32 @@ 
+/* mpModAdd.c */
+
+#include "bigdigits.h"
+
+int mpModAdd(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], const DIGIT_T m[], UINT ndigits)
+{
+	/*	Computes product w = u + v mod m
+		where w, u, v, m are multiprecision integers of ndigits each
+	*/
+	
+	DIGIT_T w1[MAX_DIG_LEN+1];
+	DIGIT_T u1[MAX_DIG_LEN+1];
+	DIGIT_T v1[MAX_DIG_LEN+1];
+	DIGIT_T m1[MAX_DIG_LEN+1];
+	
+	mpSetEqual(u1, u, ndigits);
+	u1[ndigits] = 0;
+	
+	mpSetEqual(v1, v, ndigits);
+	v1[ndigits] = 0;
+	
+	mpSetEqual(m1, m, ndigits);
+	m1[ndigits] = 0;
+	
+	mpAdd(w1, u1, v1, ndigits+1);
+		
+	mpModulo(u1, w1, ndigits+1, m1, ndigits+1);
+	
+	mpSetEqual(w, u1, ndigits);
+	
+	return 0;	
+}
diff --git a/src/libm/mpModExp.c b/src/libm/mpModExp.c
new file mode 100644
index 000000000000..cf134a424b0c
--- /dev/null
+++ b/src/libm/mpModExp.c
@@ -0,0 +1,40 @@ 
+/* mpModExp.c */
+
+#include "bigdigits.h"
+
+
+int mpModExp(DIGIT_T y[], const DIGIT_T x[], const DIGIT_T e[], const DIGIT_T m[], UINT ndigits)
+{	/*	Computes y = x^e mod m */
+	/*	Binary left-to-right method
+	*/
+	DIGIT_T mask;
+	UINT n;
+	
+	if (ndigits == 0) return -1;
+
+	/* Find second-most significant bit in e */
+	n = mpSizeof(e, ndigits);
+	for (mask = HIBITMASK; mask > 0; mask >>= 1){
+		if (e[n-1] & mask)
+			break;
+	}
+	mpNEXTBITMASK(mask, n);
+
+	/* Set y = x */
+	mpSetEqual(y, x, ndigits);
+
+	/* For bit j = k-2 downto 0 step -1 */
+	while (n){
+		mpModMult(y, y, y, m, ndigits);		/* Square */
+		if (e[n-1] & mask)
+			mpModMult(y, y, x, m, ndigits);	/* Multiply */
+		
+		/* Move to next bit */
+		mpNEXTBITMASK(mask, n);
+	}
+
+	return 0;
+}
+
+
+
diff --git a/src/libm/mpModInv.c b/src/libm/mpModInv.c
new file mode 100644
index 000000000000..659f5023e1aa
--- /dev/null
+++ b/src/libm/mpModInv.c
@@ -0,0 +1,49 @@ 
+/* mpModInv.c */
+
+#include "bigdigits.h"
+
+int mpModInv(DIGIT_T inv[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits)
+{	/*	Computes inv = u^(-1) mod v */
+	/*	Ref: Knuth Algorithm X Vol 2 p 342
+		ignoring u2, v2, t2
+		and avoiding negative numbers.
+	*/
+	/* Allocate temp variables */
+	DIGIT_T u1[MAX_DIG_LEN], u3[MAX_DIG_LEN], v1[MAX_DIG_LEN], v3[MAX_DIG_LEN];
+	DIGIT_T t1[MAX_DIG_LEN], t3[MAX_DIG_LEN], q[MAX_DIG_LEN];
+	DIGIT_T w[2*MAX_DIG_LEN];
+	/* TODO: CHECK LENGTHS HERE */
+	int bIterations;
+
+	/* Step X1. Initialise */
+	mpSetDigit(u1, 1, ndigits);		/* u1 = 1 */
+	mpSetEqual(u3, u, ndigits);		/* u3 = u */
+	mpSetZero(v1, ndigits);			/* v1 = 0 */
+	mpSetEqual(v3, v, ndigits);		/* v3 = v */
+
+	bIterations = 1;	/* Remember odd/even iterations */
+	while (!mpIsZero(v3, ndigits))		/* Step X2. Loop while v3 != 0 */
+	{					/* Step X3. Divide and "Subtract" */
+		mpDivide(q, t3, u3, ndigits, v3, ndigits);
+						/* q = u3 / v3, t3 = u3 % v3 */
+		mpMultiply(w, q, v1, ndigits);	/* w = q * v1 */
+		mpAdd(t1, u1, w, ndigits);		/* t1 = u1 + w */
+
+		/* Swap u1 = v1; v1 = t1; u3 = v3; v3 = t3 */
+		mpSetEqual(u1, v1, ndigits);
+		mpSetEqual(v1, t1, ndigits);
+		mpSetEqual(u3, v3, ndigits);
+		mpSetEqual(v3, t3, ndigits);
+
+		bIterations = -bIterations;
+	}
+
+	if (bIterations < 0)
+		mpSubtract(inv, v, u1, ndigits);	/* inv = v - u1 */
+	else
+		mpSetEqual(inv, u1, ndigits);		/* inv = u1 */
+
+	
+	return 0;
+}
+
diff --git a/src/libm/mpModMult.c b/src/libm/mpModMult.c
new file mode 100644
index 000000000000..0c48c98baa4b
--- /dev/null
+++ b/src/libm/mpModMult.c
@@ -0,0 +1,20 @@ 
+/* mpModMult.c */
+
+#include "bigdigits.h"
+
+int mpModMult(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], const DIGIT_T m[], UINT ndigits)
+{	
+	/*	Computes a = (x * y) mod m */
+	
+	/* Double-length temp variable */
+	DIGIT_T p[MAX_DIG_LEN * 2];
+
+	/* Calc p[2n] = x * y */
+	mpMultiply(p, x, y, ndigits);
+
+	/* Then modulo */
+	mpModulo(a, p, ndigits * 2, m, ndigits);
+
+	return 0;
+}
+
diff --git a/src/libm/mpModSquare.c b/src/libm/mpModSquare.c
new file mode 100644
index 000000000000..1cc37e45177f
--- /dev/null
+++ b/src/libm/mpModSquare.c
@@ -0,0 +1,18 @@ 
+/* Modulo Squaring */
+
+#include "bigdigits.h"
+
+int mpModSquare(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T p[], UINT ndigits)
+{
+	/* Computes w = u^2 mod p */
+	
+	DIGIT_T t[MAX_DIG_LEN * 2];
+
+	/* Calc t[2n] = u^2 */
+	mpSquare(t, u, ndigits);
+
+	/* Then modulo */
+	mpModulo(w, t, ndigits * 2, p, ndigits);
+
+	return 0;
+}
diff --git a/src/libm/mpModSquareRoot.c b/src/libm/mpModSquareRoot.c
new file mode 100644
index 000000000000..ea41ade2b0f4
--- /dev/null
+++ b/src/libm/mpModSquareRoot.c
@@ -0,0 +1,96 @@ 
+/* Compute Modulo Square Root */
+
+#include "bigdigits.h"
+
+int mpModSquareRootPre(UINT *S, DIGIT_T Q[], DIGIT_T V[], const DIGIT_T p[], UINT len)
+{
+	/* Precomputation for computing square root */
+	DIGIT_T W[MAX_DIG_LEN];
+	int val = 0;
+	
+	/* find S and Q such that P - 1 = Q*2^S, Q is odd */
+	mpShortSub(Q, p, 1, len);
+	*S = 0;
+	while(mpISEVEN(Q, len)){
+		mpShiftRight(Q, Q, 1, len);
+		(*S)++;
+	}
+	
+	/* find a quadratic nonresidue W mod p and compute V = W^Q mod p */
+	mpMakeRandom(W, len);
+	while(val!=-1){
+		mpShortAdd(W, W, 1, len);
+		
+		/* Test Legendre Symbol */
+		if(mpLegendre(&val, W, p, len)!=0)
+			return -1;	/* error */	
+	}
+	
+	mpModExp(V, W, Q, p, len);
+	
+	return 0;
+}
+
+
+int mpModSquareRoot(DIGIT_T x[], const DIGIT_T a[], const DIGIT_T p[], UINT S, const DIGIT_T Q[], const DIGIT_T V[], const DIGIT_T a1[], UINT len)
+{
+	/* Shanks-Tonelli Algorithm */
+	int i;
+	UINT T;
+	DIGIT_T e[MAX_DIG_LEN];
+	DIGIT_T w[MAX_DIG_LEN];
+
+	/* Check Legendre symbol (a/p) first */
+	if(mpLegendre(&i, a, p, len) != 0)
+		return -2; /* error */
+	
+	if(i != 1)	/* a has no square root */
+		return -1;
+	
+	/* Compute square root modulo p of a using Shanks-Tonelli algorithm */
+	
+	/* x = a^[(Q+1)/2] mod p - first approximation */
+	mpShortAdd(e, Q, 1, len);
+	mpShiftRight(e, e, 1, len);
+		
+	mpModExp(x, a, e, p, len);
+	
+	if(S==1)
+		/* Done, a^[(Q+1)/2] mod p is square root modulo p of a */	
+		return 0;
+	
+	while(1)
+	{
+		/* w = x^2*a1 mod p */
+		mpModSquare(e, x, p, len);
+		mpModMult(w, e, a1, p, len);
+		
+		if(mpShortCmp(w, 1 , len) == 0)
+			/* Done since x^2*a^-1 = 1 mod p */
+			return 0;
+				
+		/* Looking for better approximation of x */
+		T = 0;
+		while(mpShortCmp(w, 1 , len))
+		{
+			/* w = w^2 mod p */
+			mpSetEqual(e, w, len);
+			mpModSquare(w, e, p, len);
+			
+			T++;
+		}
+		
+		/* Compute new approximation x' = x*V^[2^(S-T-1)] */
+		mpSetEqual(e, V, len);
+		for(i=0;i<S-T-1;i++)
+		{
+			mpModSquare(w, e, p, len);
+			mpSetEqual(e, w, len);
+		}
+		
+		mpModMult(e, w, x, p, len);
+		mpSetEqual(x, e, len);
+	}
+		
+	return 0;
+}
diff --git a/src/libm/mpModSubtract.c b/src/libm/mpModSubtract.c
new file mode 100644
index 000000000000..01ca9238926e
--- /dev/null
+++ b/src/libm/mpModSubtract.c
@@ -0,0 +1,38 @@ 
+/* mpModSubtract.c */
+
+#include "bigdigits.h"
+
+int mpModSubtract(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], const DIGIT_T m[], UINT ndigits)
+{
+	/*	Computes product w = u - v mod m
+		where w, u, v, m are multiprecision integers of ndigits each
+	*/
+	
+	DIGIT_T w1[MAX_DIG_LEN+1];
+	DIGIT_T u1[MAX_DIG_LEN+1];
+	DIGIT_T v1[MAX_DIG_LEN+1];
+	DIGIT_T m1[MAX_DIG_LEN+1];
+	
+	mpSetEqual(u1, u, ndigits);
+	u1[ndigits] = 0;
+	
+	mpSetEqual(v1, v, ndigits);
+	v1[ndigits] = 0;
+	
+	mpSetEqual(m1, m, ndigits);
+	m1[ndigits] = 0;
+	
+	while(mpCompare(u1, v1, ndigits+1) < 0){ /* u1 < v1 */
+		/* u1 = u1 + m1 */
+		mpAdd(u1, u1, m1, ndigits+1);
+	}
+	
+	mpSubtract(w1, u1, v1, ndigits+1);
+	
+	mpModulo(u1, w1, ndigits+1, m1, ndigits+1);
+	
+	mpSetEqual(w, u1, ndigits);
+	
+	return 0;
+	
+}
diff --git a/src/libm/mpModulo.c b/src/libm/mpModulo.c
new file mode 100644
index 000000000000..c929dd5a2c02
--- /dev/null
+++ b/src/libm/mpModulo.c
@@ -0,0 +1,34 @@ 
+/* mpModulo.c */
+
+#include "bigdigits.h"
+
+int mpModulo(DIGIT_T r[], const DIGIT_T u[], UINT udigits, const DIGIT_T v[], UINT vdigits)
+{
+#ifdef MCRYPTO_TRIVIAL_DIVISION	
+	/*	Calculates r = u mod v
+		where r, v are multiprecision integers of length vdigits
+		and u is a multiprecision integer of length udigits.
+		r may overlap v.
+
+		Note that r here is only vdigits long, 
+		whereas in mpDivide it is udigits long.
+
+		Use remainder from mpDivide function.
+	*/
+
+	/* Double-length temp variable for divide fn */
+	DIGIT_T qq[MAX_DIG_LEN * 2];
+	/* Use a double-length temp for r to allow overlap of r and v */
+	DIGIT_T rr[MAX_DIG_LEN * 2];
+
+	/* rr[2n] = u[2n] mod v[n] */
+	mpDivide(qq, rr, u, udigits, v, vdigits);
+
+	mpSetEqual(r, rr, vdigits);
+#elif defined(MCRYPTO_BARRET)
+	/* use Barret reduction method */
+
+#endif
+	return 0;
+}
+
diff --git a/src/libm/mpMultiply.c b/src/libm/mpMultiply.c
new file mode 100644
index 000000000000..faf4a75ccd7f
--- /dev/null
+++ b/src/libm/mpMultiply.c
@@ -0,0 +1,55 @@ 
+/* mpMultiply.c */
+#include <assert.h>
+#include "bigdigits.h"
+
+int mpMultiply(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits)
+{
+#ifdef MCRYPTO_SCHOOL_BOOK	
+	/*	Computes product w = u * v
+		where u, v are multiprecision integers of ndigits each
+		and w is a multiprecision integer of 2*ndigits
+
+		Ref: Knuth Vol 2 Ch 4.3.1 p 268 Algorithm M.
+	*/
+
+	DIGIT_T k, t[2];
+	UINT i, j, m, n;
+	
+	assert(w != u && w != v);
+	m = n = ndigits;
+
+	/* Step M1. Initialise */
+	mpSetZero(w, 2*ndigits);
+	
+	for (j = 0; j < n; j++) {
+		/* Step M2. Zero multiplier? */
+		if (v[j] == 0)
+			w[j + m] = 0;
+		else{
+			/* Step M3. Initialise i */
+			k = 0;
+			for (i = 0; i < m; i++){
+				/* Step M4. Multiply and add */
+				/* t = u_i * v_j + w_(i+j) + k */
+				spMultiply(t, u[i], v[j]);
+
+				t[0] += k;
+				if (t[0] < k)
+					t[1]++;
+				t[0] += w[i+j];
+				if (t[0] < w[i+j])
+					t[1]++;
+
+				w[i+j] = t[0];
+				k = t[1];
+			}	
+			/* Step M5. Loop on i, set w_(j+m) = k */
+			w[j+m] = k;
+		}
+	}	/* Step M6. Loop on j */
+#elif defined(MCRYPTO_FFT_MUL)
+ 
+#endif
+	return 0;
+}
+
diff --git a/src/libm/mpOR.c b/src/libm/mpOR.c
new file mode 100644
index 000000000000..71ace1e43d50
--- /dev/null
+++ b/src/libm/mpOR.c
@@ -0,0 +1,9 @@ 
+/* mpOR : multi-precision bitwise OR */
+
+#include "bigdigits.h"
+
+void mpOR(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits)	
+{
+	while(ndigits--)
+		 a[ndigits] = x[ndigits] | y[ndigits];
+}
diff --git a/src/libm/mpSetDigit.c b/src/libm/mpSetDigit.c
new file mode 100644
index 000000000000..7c2b03e210bb
--- /dev/null
+++ b/src/libm/mpSetDigit.c
@@ -0,0 +1,15 @@ 
+/* mpSetDigit.c */
+
+#include "bigdigits.h"
+
+void mpSetDigit(DIGIT_T a[], DIGIT_T d, UINT ndigits)
+{	
+	/* Sets a = d where d is a single digit */
+	UINT i;
+	
+	for (i = 1; i < ndigits; i++)
+	{
+		a[i] = 0;
+	}
+	a[0] = d;
+}
diff --git a/src/libm/mpSetEqual.c b/src/libm/mpSetEqual.c
new file mode 100644
index 000000000000..bdfb1c00f5df
--- /dev/null
+++ b/src/libm/mpSetEqual.c
@@ -0,0 +1,11 @@ 
+/* mpSetEqual.c */
+
+#include "bigdigits.h"
+
+void mpSetEqual(DIGIT_T a[], const DIGIT_T b[], UINT ndigits)
+{	
+	/* Sets a = b */
+		
+	while(ndigits--)
+		a[ndigits] = b[ndigits];
+}
diff --git a/src/libm/mpSetZero.c b/src/libm/mpSetZero.c
new file mode 100644
index 000000000000..ca4a64c05ee2
--- /dev/null
+++ b/src/libm/mpSetZero.c
@@ -0,0 +1,11 @@ 
+/* mpSetZero.c */
+
+#include "bigdigits.h"
+
+void mpSetZero(DIGIT_T a[], UINT ndigits)
+{	
+	/* Sets a = 0 */
+	while(ndigits--)	
+		a[ndigits] = 0;
+	
+}
diff --git a/src/libm/mpShiftLeft.c b/src/libm/mpShiftLeft.c
new file mode 100644
index 000000000000..7bd0867f558f
--- /dev/null
+++ b/src/libm/mpShiftLeft.c
@@ -0,0 +1,43 @@ 
+/* mpShiftLeft.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShiftLeft(DIGIT_T a[], const DIGIT_T b[], UINT shift, UINT ndigits)
+{	
+	UINT i, y, nw, bits;
+	DIGIT_T mask, carry, nextcarry;
+
+	/* Do we shift whole digits? */
+	if (shift >= BITS_PER_DIGIT){
+		nw = shift / BITS_PER_DIGIT;
+		i = ndigits;
+		while (i--){
+			if (i >= nw)
+				a[i] = b[i-nw];
+			else
+				a[i] = 0;
+		}
+		/* Call again to shift bits inside digits */
+		bits = shift % BITS_PER_DIGIT;
+		carry = b[ndigits-nw] << bits;
+		if (bits) 
+			carry |= mpShiftLeft(a, a, bits, ndigits);
+		return carry;
+	}
+	else{
+		bits = shift;
+	}
+
+	/* Construct mask = high bits set */
+	mask = ~(~(DIGIT_T)0 >> bits);
+	
+	y = BITS_PER_DIGIT - bits;
+	carry = 0;
+	for (i = 0; i < ndigits; i++){
+		nextcarry = (b[i] & mask) >> y;
+		a[i] = b[i] << bits | carry;
+		carry = nextcarry;
+	}
+
+	return carry;
+}
diff --git a/src/libm/mpShiftRight.c b/src/libm/mpShiftRight.c
new file mode 100644
index 000000000000..05421d37e23d
--- /dev/null
+++ b/src/libm/mpShiftRight.c
@@ -0,0 +1,45 @@ 
+/* mpShiftRight.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShiftRight(DIGIT_T a[], const DIGIT_T b[], UINT shift, UINT ndigits)
+{	
+	UINT i, y, nw, bits;
+	DIGIT_T mask, carry, nextcarry;
+
+	/* Do we shift whole digits? */
+	if (shift >= BITS_PER_DIGIT)
+	{
+		nw = shift / BITS_PER_DIGIT;
+		for (i = 0; i < ndigits; i++){
+			if ((i+nw) < ndigits)
+				a[i] = b[i+nw];
+			else
+				a[i] = 0;
+		}
+		/* Call again to shift bits inside digits */
+		bits = shift % BITS_PER_DIGIT;
+		carry = b[nw-1] >> bits;
+		if (bits) 
+			carry |= mpShiftRight(a, a, bits, ndigits);
+		return carry;
+	}
+	else{
+		bits = shift;
+	}
+
+	/* Construct mask to set low bits */
+	/* (thanks to Jesse Chisholm for suggesting this improved technique) */
+	mask = ~(~(DIGIT_T)0 << bits);
+	
+	y = BITS_PER_DIGIT - bits;
+	carry = 0;
+	i = ndigits;
+	while (i--){
+		nextcarry = (b[i] & mask) << y;
+		a[i] = b[i] >> bits | carry;
+		carry = nextcarry;
+	}
+
+	return carry;
+}
diff --git a/src/libm/mpShortAdd.c b/src/libm/mpShortAdd.c
new file mode 100644
index 000000000000..b4c9d9e589c7
--- /dev/null
+++ b/src/libm/mpShortAdd.c
@@ -0,0 +1,38 @@ 
+/* mpShortAdd.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShortAdd(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, UINT ndigits)
+{
+	/*	Calculates w = u + v
+		where w, u are multiprecision integers of ndigits each
+		and v is a single precision digit.
+		Returns carry if overflow.
+
+		Ref: Derived from Knuth Algorithm A.
+	*/
+
+	DIGIT_T k;
+	UINT j;
+
+	k = 0;
+
+	/* Add v to first digit of u */
+	w[0] = u[0] + v;
+	if (w[0] < v)
+		k = 1;
+	else
+		k = 0;
+
+	/* Add carry to subsequent digits */
+	for (j = 1; j < ndigits; j++){
+		w[j] = u[j] + k;
+		if (w[j] < k)
+			k = 1;
+		else
+			k = 0;
+	}
+
+	return k;
+}
+
diff --git a/src/libm/mpShortCmp.c b/src/libm/mpShortCmp.c
new file mode 100644
index 000000000000..e71de20333b5
--- /dev/null
+++ b/src/libm/mpShortCmp.c
@@ -0,0 +1,25 @@ 
+/* mpShortCmp.c */
+
+#include "bigdigits.h"
+
+int mpShortCmp(const DIGIT_T a[], DIGIT_T b, UINT ndigits)
+{
+	/* Returns sign of (a - b) where b is a single digit */
+
+	UINT i;
+
+	if (ndigits == 0) return 0;
+
+	for (i = 1; i < ndigits; i++){
+		if (a[i] != 0)
+			return 1;	/* GT */
+	}
+
+	if (a[0] < b)
+		return -1;		/* LT */
+	else if (a[0] > b)
+		return 1;		/* GT */
+
+	return 0;	/* EQ */
+}
+
diff --git a/src/libm/mpShortDiv.c b/src/libm/mpShortDiv.c
new file mode 100644
index 000000000000..f59824506c66
--- /dev/null
+++ b/src/libm/mpShortDiv.c
@@ -0,0 +1,55 @@ 
+/* mpShortDiv.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShortDiv(DIGIT_T q[], const DIGIT_T u[], DIGIT_T v, UINT ndigits)
+{
+	/*	Calculates quotient q = u div v
+		Returns remainder r = u mod v
+		where q, u are multiprecision integers of ndigits each
+		and d, v are single precision digits.
+
+		Makes no assumptions about normalisation.
+		
+		Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625
+	*/
+	UINT j;
+	DIGIT_T t[2], r;
+	UINT shift;
+	DIGIT_T bitmask, overflow, *uu;
+
+	if (ndigits == 0) return 0;
+	if (v == 0)	return 0;	/* Divide by zero error */
+
+	/*	Normalise first */
+	/*	Requires high bit of V
+		to be set, so find most signif. bit then shift left,
+		i.e. d = 2^shift, u' = u * d, v' = v * d.
+	*/
+	bitmask = HIBITMASK;
+	for (shift = 0; shift < BITS_PER_DIGIT; shift++){
+		if (v & bitmask)
+			break;
+		bitmask >>= 1;
+	}
+
+	v <<= shift;
+	overflow = mpShiftLeft(q, u, shift, ndigits);
+	uu = q;
+	
+	/* Step S1 - modified for extra digit. */
+	r = overflow;	/* New digit Un */
+	j = ndigits;
+	while (j--){
+		/* Step S2. */
+		t[1] = r;
+		t[0] = uu[j];
+		overflow = spDivide(&q[j], &r, t, v);
+	}
+
+	/* Unnormalise */
+	r >>= shift;
+	
+	return r;
+}
+
diff --git a/src/libm/mpShortMod.c b/src/libm/mpShortMod.c
new file mode 100644
index 000000000000..85c6798ab880
--- /dev/null
+++ b/src/libm/mpShortMod.c
@@ -0,0 +1,22 @@ 
+/* mpShortMod.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShortMod(const DIGIT_T a[], DIGIT_T d, UINT ndigits)
+{
+	/*	Calculates r = a mod d
+		where a is a multiprecision integer of ndigits
+		and r, d are single precision digits
+		using bit-by-bit method from left to right.
+
+		Use remainder from divide function.
+	*/
+
+	DIGIT_T q[MAX_DIG_LEN * 2];
+	DIGIT_T r = 0;
+
+	r= mpShortDiv(q, a, d, ndigits);
+
+	return r;
+}
+
diff --git a/src/libm/mpShortModMult.c b/src/libm/mpShortModMult.c
new file mode 100644
index 000000000000..314bb455849a
--- /dev/null
+++ b/src/libm/mpShortModMult.c
@@ -0,0 +1,30 @@ 
+/* mpShortModMult.c */
+
+#include "bigdigits.h"
+
+int mpShortModMult(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, DIGIT_T m[], UINT ndigits)
+{
+	/*	Computes product w = u * v mod m
+		where w, u, m are multiprecision integers of ndigits each
+		and v are single precision digits
+	*/
+	
+	DIGIT_T w1[MAX_DIG_LEN+1];
+	DIGIT_T u1[MAX_DIG_LEN+1];
+	DIGIT_T m1[MAX_DIG_LEN+1];
+	
+	mpSetEqual(u1, u, ndigits);
+	u1[ndigits] = 0;
+	
+	mpSetEqual(m1, m, ndigits);
+	m1[ndigits] = 0;
+	
+	mpShortMult(w1, u1, v, ndigits+1);
+		
+	mpModulo(u1, w1, ndigits+1, m1, ndigits+1);
+	
+	mpSetEqual(w, u1, ndigits);
+		
+	return 0;
+	
+}
diff --git a/src/libm/mpShortMult.c b/src/libm/mpShortMult.c
new file mode 100644
index 000000000000..da934d6f910b
--- /dev/null
+++ b/src/libm/mpShortMult.c
@@ -0,0 +1,40 @@ 
+/* mpShortMult.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShortMult(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, UINT ndigits)
+{
+	/*	Computes product w = u * v
+		Returns overflow k
+		where w, u are multiprecision integers of ndigits each
+		and v, k are single precision digits
+
+		Ref: Knuth Algorithm M.
+	*/
+
+	DIGIT_T k, t[2];
+	UINT j;
+
+	
+	if (v == 0) {
+		mpSetZero(w, ndigits);
+		
+		return 0;
+	}
+
+	k = 0;
+	for (j = 0; j < ndigits; j++){
+		/* t = x_i * v */
+		spMultiply(t, u[j], v);
+		/* w_i = LOHALF(t) + carry */
+		w[j] = t[0] + k;
+		/* Overflow? */
+		if (w[j] < k)
+			t[1]++;
+		/* Carry forward HIHALF(t) */
+		k = t[1];
+	}
+
+	return k;
+}
+
diff --git a/src/libm/mpShortSub.c b/src/libm/mpShortSub.c
new file mode 100644
index 000000000000..87a832aaa993
--- /dev/null
+++ b/src/libm/mpShortSub.c
@@ -0,0 +1,39 @@ 
+/* mpShortSub.c */
+
+#include "bigdigits.h"
+
+DIGIT_T mpShortSub(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v, UINT ndigits)
+{
+	/*	Calculates w = u - v
+		where w, u are multiprecision integers of ndigits each
+		and v is a single precision digit.
+		Returns borrow: 0 if u >= v, or 1 if v > u.
+
+		Ref: Derived from Knuth Algorithm S.
+	*/
+
+	DIGIT_T k;
+	UINT j;
+
+	k = 0;
+
+	/* Subtract v from first digit of u */
+	w[0] = u[0] - v;
+	if (w[0] > MAX_DIGIT - v)
+		k = 1;
+	else
+		k = 0;
+
+	/* Subtract borrow from subsequent digits */
+	for (j = 1; j < ndigits; j++)
+	{
+		w[j] = u[j] - k;
+		if (w[j] > MAX_DIGIT - k)
+			k = 1;
+		else
+			k = 0;
+	}
+
+	return k;
+}
+
diff --git a/src/libm/mpSizeof.c b/src/libm/mpSizeof.c
new file mode 100644
index 000000000000..1eb5753c8f38
--- /dev/null
+++ b/src/libm/mpSizeof.c
@@ -0,0 +1,14 @@ 
+/* mpSizeof.c */
+
+#include "bigdigits.h"
+
+UINT mpSizeof(const DIGIT_T a[], UINT ndigits)
+{	/* Returns size of significant digits in a */
+	
+	while(ndigits--){
+		if (a[ndigits] != 0)
+			return (++ndigits);
+	}
+	
+	return 0;
+}
diff --git a/src/libm/mpSolinasPrime.c b/src/libm/mpSolinasPrime.c
new file mode 100644
index 000000000000..6176eec2a9ed
--- /dev/null
+++ b/src/libm/mpSolinasPrime.c
@@ -0,0 +1,41 @@ 
+/* mpSolinasPrime.c - generate Solinas' prime of the form p = 2^a + 2^b + 1, 0 < b < a */
+/* useful for generating type-1 elliptic curve for pairing implementation */
+/* todo: try p = 2^a - 2^b -1 too */
+
+#include <stdlib.h>
+#include <time.h>
+#include "bigdigits.h"
+
+UINT mpSolinasPrime(DIGIT_T p[], UINT ndigits, UINT bit_len)
+{
+	UINT a, b;	
+	UINT i, j;
+	UINT n = 1000;	/* going to try at most n times */
+	
+	srand((unsigned)time(NULL));	
+	while(n--){
+		/* first, make p = 1 */		
+		mpSetDigit(p, 1, ndigits);
+		
+		/* let a = bit_len - 1 s.t. p's bit length is exactly bit_len */
+		a = bit_len - 1;
+		i = a / BITS_PER_DIGIT;
+		j = a % BITS_PER_DIGIT;
+		p[i] |= ((DIGIT_T)0x01) << j;
+		
+		/* choose b randomly from 1 to a - 1 */
+		do {
+			b = rand() % a;
+		} while(b==0);
+		i = b / BITS_PER_DIGIT;
+		j = b % BITS_PER_DIGIT;
+		p[i] |= ((DIGIT_T)0x01) << j;
+
+		/* test if p is a prime number */
+		if(mpIsPrime(p, ndigits, N_TEST_PRIME))
+			return b;
+	}	
+	
+	/* failed */
+	return 0;
+}
diff --git a/src/libm/mpSquare.c b/src/libm/mpSquare.c
new file mode 100644
index 000000000000..3e425ff00e8c
--- /dev/null
+++ b/src/libm/mpSquare.c
@@ -0,0 +1,65 @@ 
+/* Multi-precision squaring */
+
+#include <assert.h>
+#include "bigdigits.h"
+
+int mpSquare(DIGIT_T w[], const DIGIT_T u[], UINT ndigits)
+{
+	/* Ref: Modified Squaring Algorithm by Jorge Guajardo and Christof Paar */
+	UINT i, j;
+	DIGIT_T t[2];
+	DIGIT_T prod[2];
+	DIGIT_T C1;
+	DIGIT_T C2;
+	
+	assert(w != u);
+
+	mpSetZero(w, 2*ndigits);
+	
+	for(i=0;i<ndigits;i++){
+		/* t = w_(2i) + (x_i)^2 */
+		spMultiply(t, u[i], u[i]);
+		mpShortAdd(t, t, w[2*i], 2); 
+		
+		w[2*i] = t[0];
+		C1 = t[1];
+		C2 = 0;
+		
+		for(j=i+1;j<ndigits;j++){
+			/* prod = x_i * x_j */
+			spMultiply(prod, u[i], u[j]);
+			
+			/* t = w_(i+j) + prod + C1 */
+			mpShortAdd(t, prod, C1, 2);
+			mpShortAdd(t, t, w[i+j], 2);
+			
+			w[i+j] = t[0];
+			C1 = t[1];
+			
+			/* t = w_(i+j) + prod + C2 */
+			mpShortAdd(t, prod, C2, 2);
+			mpShortAdd(t, t, w[i+j], 2);
+			
+			w[i+j] = t[0];
+			C2 = t[1];
+		}
+		/* t = C1 + C2 */
+		mpSetZero(t, 2);
+		mpShortAdd(t, t, C1, 2);
+		mpShortAdd(t, t, C2, 2);
+		
+		C1 = t[0];
+		C2 = t[1];
+		
+		/* t = w_(i+ndigits) + C1 */
+		mpSetZero(t, 2);
+		mpShortAdd(t, t, w[i+ndigits], 2);
+		mpShortAdd(t, t, C1, 2);
+		
+		w[i+ndigits] = t[0];
+		
+		w[i+ndigits+1] = C2 + t[1];
+	}
+	
+	return 0;
+}
diff --git a/src/libm/mpSubtract.c b/src/libm/mpSubtract.c
new file mode 100644
index 000000000000..a65a8aa9e72e
--- /dev/null
+++ b/src/libm/mpSubtract.c
@@ -0,0 +1,41 @@ 
+/* mpSubtract.c */
+
+#include <assert.h>
+#include "bigdigits.h"
+
+DIGIT_T mpSubtract(DIGIT_T w[], const DIGIT_T u[], const DIGIT_T v[], UINT ndigits)
+{
+	/*	Calculates w = u - v where u >= v
+		w, u, v are multiprecision integers of ndigits each
+		Returns 0 if OK, or 1 if v > u.
+
+		Ref: Knuth Vol 2 Ch 4.3.1 p 267 Algorithm S.
+	*/
+
+	DIGIT_T k;
+	UINT j;
+
+	assert(w != v);
+
+	/* Step S1. Initialise */
+	k = 0;
+
+	for (j = 0; j < ndigits; j++){
+		/*	Step S2. Subtract digits w_j = (u_j - v_k - k)
+			Set k = 1 if borrow occurs.
+		*/
+		w[j] = u[j] - k;
+		if (w[j] > MAX_DIGIT - k)
+			k = 1;
+		else
+			k = 0;
+		
+		w[j] -= v[j];
+		if (w[j] > MAX_DIGIT - v[j])
+			k++;
+
+	}	/* Step S3. Loop on j */
+
+	return k;	/* Should be zero if u >= v */
+}
+
diff --git a/src/libm/mpSwap.c b/src/libm/mpSwap.c
new file mode 100644
index 000000000000..1e5aee4b68c6
--- /dev/null
+++ b/src/libm/mpSwap.c
@@ -0,0 +1,16 @@ 
+/* Swap two integers */
+
+#include "bigdigits.h"
+
+int mpSwap(DIGIT_T a[], DIGIT_T b[], UINT len)
+{
+	DIGIT_T temp[MAX_DIG_LEN];
+	
+	while(len--) {
+		temp[len] = a[len];
+		a[len] = b[len];
+		b[len] = temp[len];
+	}
+	
+	return 0;
+}
diff --git a/src/libm/mpXOR.c b/src/libm/mpXOR.c
new file mode 100644
index 000000000000..799668badd7d
--- /dev/null
+++ b/src/libm/mpXOR.c
@@ -0,0 +1,9 @@ 
+/* mpXOR : multi-precision bitwise XOR */
+
+#include "bigdigits.h"
+
+void mpXOR(DIGIT_T a[], const DIGIT_T x[], const DIGIT_T y[], UINT ndigits)	
+{
+	while(ndigits--)
+		a[ndigits] = x[ndigits] ^ y[ndigits];
+}
diff --git a/src/libm/pkcs1-rsa.c b/src/libm/pkcs1-rsa.c
new file mode 100644
index 000000000000..1a3132e1fa75
--- /dev/null
+++ b/src/libm/pkcs1-rsa.c
@@ -0,0 +1,833 @@ 
+/*--------------------------------------------------------*/
+/* PKCS #1 - RSA Cryptosystem Simplified Implementation   */
+/* Author : Dang Nguyen Duc, nguyenduc@icu.ac.kr          */
+/* Date   : 2006/11/12                                    */
+/* Note   : Bit length of modulus of ways divisible by bit*/
+/*          length of a double word (i.e. 32 bits)        */
+/* To do  :						  */
+/*          1. Fast Decryption Using CRT                  */			  
+/*--------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mcrypto.h"
+#include "pkcs1-rsa.h"
+#include "hash.h"
+#include "bigdigits.h"
+
+/* Internal Functions - Forward Declaration */
+static void memxor(BYTE *c, BYTE *a, BYTE *b, UINT len); 
+	/* Perform c = a XOR b */
+
+static int GenRsaPrime(DIGIT_T p[], UINT ndigits);
+	/* Generate a pseudoprime of length ndigits */ /* To do: put in BigInt lib */	
+
+static int MGF1(UINT hid, BYTE *seed, UINT seedlen, BYTE  *mask, UINT masklen);
+	/* Mask Generation Function Using Hash Function */
+
+/* Internal Functions */
+static void memxor(BYTE *c, BYTE *a, BYTE *b, UINT len)
+{
+	while(len--)
+		c[len] = a[len] ^ b[len]; 
+}
+
+static int GenRsaPrime(DIGIT_T p[], UINT ndigits)
+{
+	/* Generate a pseudorandom number */
+	mpMakeRandom(p, ndigits);
+
+	/*	Make sure two highest and the low bits are set.
+		Having the two highest bits set means the product
+		(pq) will always have its highest bit set. 
+	*/
+	p[ndigits - 1] |= HIBITMASK | (HIBITMASK >> 1);
+	p[0] |= 0x1;
+
+	/* Primality Testing using Miller-Rabin Method */
+	while (!mpIsPrime(p, ndigits, N_TEST_PRIME)) {
+		/* add 2 to p and try to test again */
+		mpShortAdd(p, p, 2, ndigits);
+
+		/* Check for overflow */
+		if (!(p[ndigits - 1] & HIBITMASK))
+			return -1;	/* Failed to find a prime */
+	}
+	
+	return 0;
+}
+
+static int MGF1(UINT hid, BYTE *seed, UINT seedlen, BYTE  *mask, UINT masklen)
+{
+	/* Mask Generation Function Using Hash Function */
+	UINT hlen;
+	DWORD i;
+	BYTE *hash;
+	BYTE *data;
+	DWORD n;
+	DWORD MAX_SIZE = 0x8000;
+	BYTE T[MAX_SIZE];
+	int ret;
+	
+	/* Init Ouput */
+	memset(T, 0x00, MAX_SIZE);
+	
+	/* masklen should be less than MAX_SIZE */
+	if((hlen = HashLenQuery(hid))==0)	/* Unkown Hash Algorithm */
+		return ERR_UNKNOWN_HASH;
+	
+	if(masklen % hlen)
+		n = masklen / hlen + 1;
+	else
+		n = masklen / hlen;
+	
+	/* Preparing Hash Input/Ouput */
+	data = (BYTE *)malloc(seedlen + 4);
+	memcpy(data, seed, seedlen);
+	
+	hash = (BYTE *)malloc(hlen);
+		 
+	for(i=0;i<n;i++) {
+		/* Constructing Hash Input */
+		memcpy(data+seedlen, &i, 4);
+		
+		/* Computing Hash */
+		if((ret=Hash(hid, data, seedlen+4, hash))!=0) {
+			free(data);
+			free(hash);
+			return ERR_HASH;
+		}
+		
+		/* Appending Hash to T */ 
+		memcpy(T+i*hlen, hash, hlen);
+	}
+	
+	free(data);
+	free(hash);
+	
+	memcpy(mask, T, masklen);
+	
+	return ERR_OK;
+}
+
+/* Main Functions */
+
+int PKCS1_RSA_GenKey(PKCS1_RSA_PUBLIC_KEY *spk, PKCS1_RSA_PRIVATE_KEY *ssk, UINT mod_len)
+{
+	DIGIT_T *p, *q, *n, *e, *d;
+	DIGIT_T Phi[MAX_DIG_LEN];
+	DIGIT_T g[MAX_DIG_LEN];
+	DIGIT_T t[MAX_DIG_LEN];
+	UINT plen;
+	UINT qlen;
+	UINT prime_len;
+	int ret;
+		
+	/* Limit checking */
+	if(mod_len < MIN_RSA_MODULUS_LEN)
+		return ERR_MOD_TOO_SMALL;
+	if(mod_len > MAX_RSA_MODULUS_LEN)
+		return ERR_MOD_TOO_LONG;
+		
+	/* Computing length of two primes */
+	prime_len = plen = mod_len / 2;
+	qlen = mod_len - plen;
+	if(qlen > prime_len)
+		prime_len = qlen;
+		
+	/* allocate memory */
+	n = (DIGIT_T*)malloc(NBYTE(mod_len));
+	mpSetZero(n, mod_len);
+	
+	e = (DIGIT_T*)malloc(NBYTE(mod_len));
+	mpSetZero(e, mod_len);
+	
+	d = (DIGIT_T*)malloc(NBYTE(mod_len));
+	mpSetZero(d, mod_len);
+	
+	p = (DIGIT_T*)malloc(NBYTE(plen));
+	mpSetZero(p, plen);
+	
+	q = (DIGIT_T*)malloc(NBYTE(qlen));
+	mpSetZero(q, qlen);
+	
+	/* Generate p and q */
+	ret = GenRsaPrime(p, plen);
+	if (ret==-1) 
+		return ERR_PRIME_FAILED;
+	mcrypto_dump("Key Gen: prime p",(BYTE *)p, NBYTE(plen));
+	
+	ret = GenRsaPrime(q, qlen);
+	if (ret==-1) 
+		return ERR_PRIME_FAILED;
+	mcrypto_dump("Key Gen: prime q",(BYTE *)q, NBYTE(qlen));
+	
+	/* Compute n */
+	mpMultiply(Phi, p, q, prime_len);
+	mpSetEqual(n, Phi, mod_len);
+	mcrypto_dump("Key Gen Modulus",(BYTE *)n, NBYTE(mod_len));
+	
+	/* Phi(n) = (p-1)*(q-1) */
+	mpShortSub(g, p, 1, plen);
+	mpShortSub(t, q, 1, qlen);
+	mpMultiply(Phi, g, t, prime_len);
+	mcrypto_dump("Key Gen Phi(n)=(p-1)(q-1)",(BYTE *)Phi, NBYTE(2*prime_len));
+	
+	do {
+		/* Generate e */
+		mpMakeRandom(e, mod_len);
+		
+		/* Calculate private key, d = e^-1 Mod L */
+		mpModInv(d, e, Phi, mod_len);
+		
+		/* Check whether e*d = 1 mod Phi(n) */
+		mpModMult(t, d, e, Phi, mod_len);
+		
+	} while(mpShortCmp(t, 1, mod_len) != 0); 
+	
+	mcrypto_dump("Key Gen Public Exponent e",(BYTE *)e, NBYTE(mod_len));
+	mcrypto_dump("Key Gen Private Exponent d",(BYTE *)d, NBYTE(mod_len));
+	
+	/* Collecting data */
+	spk->len = mod_len;
+	spk->modulus = n;
+	spk->exponent = e;
+	
+	ssk->len = mod_len;
+	ssk->modulus = n;
+	ssk->PublicExponent = e;
+	ssk->exponent = d;
+	ssk->p = p;
+	ssk->plen = plen;
+	ssk->q = q;
+	ssk->qlen = qlen;
+	
+	return ERR_OK;
+}
+
+int PKCS1_RSAEP(PKCS1_RSA_PUBLIC_KEY *spk, DIGIT_T *m, DIGIT_T *c)
+{
+	/* Do RSA Encryption */
+	mpModExp(c, m, spk->exponent, spk->modulus, spk->len);
+	
+	return ERR_OK;
+}
+
+int PKCS1_RSADP(PKCS1_RSA_PRIVATE_KEY *ssk, DIGIT_T *c, DIGIT_T *m)
+{
+	/* Do RSA Decryption */
+	mpModExp(m, c, ssk->exponent, ssk->modulus, ssk->len);
+	
+	return ERR_OK;
+}
+
+int PKCS1_RSASP1(PKCS1_RSA_PRIVATE_KEY *ssk, DIGIT_T *m, DIGIT_T *s)
+{
+	/* Do RSA Signing */
+	return PKCS1_RSADP(ssk, m, s);
+}
+
+
+int PKCS1_RSAVP1(PKCS1_RSA_PUBLIC_KEY *spk, DIGIT_T *s, DIGIT_T *m)
+{
+	/* Extract Encoded Message */
+	return PKCS1_RSAEP(spk, s, m);
+
+}
+
+int PKCS1_EME_OAEP_ENC(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, BYTE *L, UINT llen, BYTE *em)
+{
+	/* Encoding message m of length mlen to em using OAEP */
+	UINT hlen;	/* Hash Output Length in Byte */
+	UINT k;		/* Encoded Message Length */
+	BYTE *lHash;	/* Hash of L */
+	BYTE *DB;
+	BYTE *seed;
+	BYTE *dbMask;
+	BYTE *seedMask;
+	int ret;
+	
+	k = NBYTE(spk->len);
+	if((hlen = HashLenQuery(hid))==0)
+		return ERR_UNKNOWN_HASH;
+		
+	/* Length checking */
+	if(mlen > (k - 2*hlen - 2))
+		return ERR_MSG_TOO_LONG;
+	
+	/* Compute Hash of L */
+	mcrypto_dump("OAEP Encoding: L", L, llen);
+	lHash = (BYTE *)malloc(hlen);
+	if(Hash(hid, L, llen, lHash)!=0){
+		return ERR_HASH;
+	}
+	mcrypto_dump("OAEP Encoding: Hash of L", lHash, hlen);
+	
+	/* Forming DB */
+	DB = (BYTE *)malloc(k-hlen-1);
+	memset(DB, 0x00, k-hlen-1);
+	
+	memcpy(DB, lHash, hlen);
+	DB[k-hlen-mlen-2] = 0x01;
+	memcpy(DB+k-hlen-mlen-1, m, mlen);
+	mcrypto_dump("OAEP Encoding: DB", DB, k-hlen-1);
+	
+	/* Make a random seed */
+	seed = (BYTE *)malloc(hlen);
+	GenSeed(seed, hlen);
+	mcrypto_dump("OAEP Encoding: seed", seed, hlen);
+	
+	/* Forming maskedDB and maskedSeed */
+	dbMask = (BYTE *)malloc(k-hlen-1);
+	if((ret=MGF1(hid, seed, hlen, dbMask, k-hlen-1))!=ERR_OK) {
+		free(lHash);
+		free(DB);
+		free(seed);
+		
+		return ret;
+	}
+	mcrypto_dump("OAEP Encoding: dbMask", dbMask, k-hlen-1); 
+	
+	memxor(DB, DB, dbMask, k-hlen-1);
+	mcrypto_dump("OAEP Encoding: maskedDB", DB, k-hlen-1);
+	
+	seedMask = (BYTE *)malloc(hlen);
+	if((ret=MGF1(hid, DB, k-hlen-1, seedMask, hlen))!=ERR_OK) {
+		free(lHash);
+		free(DB);
+		free(seed);
+		free(seedMask);
+		
+		return ret;
+	}
+
+	mcrypto_dump("OAEP Encoding: seedMask", seedMask, hlen);
+	
+	memxor(seed, seed, seedMask, hlen);
+	mcrypto_dump("OAEP Encoding: maskedSeed", seed, hlen);
+	
+	/* forming OAEP-encoded message */
+	memset(em, 0x00, k);
+	memcpy(em+1, seed, hlen);
+	memcpy(em+1+hlen, DB, k-hlen-1);
+	mcrypto_dump("OAEP Encoding: Encoded Message em", em, k);
+	
+	/* free used memory */
+	free(lHash);
+	free(DB);
+	free(seed);
+	free(dbMask);
+	free(seedMask);
+	
+	return ERR_OK;
+}
+
+int PKCS1_RSA_OAEP_ENCRYPT(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, BYTE *L, UINT llen, BYTE *c)
+{
+	/* Encryption using RSA-OAEP */
+	BYTE *em;
+	int ret;
+	
+	mcrypto_dump("RSAOAEP Encrupt: Plaintext m", m, mlen);
+	
+	/* Encoding message */
+	em = (BYTE *)malloc(NBYTE(spk->len));
+	
+	if((ret = PKCS1_EME_OAEP_ENC(spk, hid, m, mlen, L, llen, em))!=ERR_OK) {
+		free(em);
+		return ret;
+	}
+	
+	/* Do Encryption */
+	ret = PKCS1_RSAEP(spk, (DIGIT_T *)em, (DIGIT_T *)c);
+	mcrypto_dump("RSAOAEP Encrypt: Ciphertext c", c, NBYTE(spk->len));
+	
+	free(em);
+	
+	return ret;
+}
+	
+
+int PKCS1_EME_OAEP_DEC(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *em, BYTE *L, UINT llen, BYTE *m, UINT *mlen)
+{
+	/* OAEP Decoding */
+	UINT hlen;	/* Hash Output Length in Byte */
+	UINT k;		/* Encoded Message Length */
+	BYTE *lHash;	/* Hash of L */
+	BYTE *DB;
+	BYTE *seed;
+	BYTE *maskedDB;
+	BYTE *maskedSeed;
+	UINT i;
+	int ret;
+	
+	k = NBYTE(ssk->len);
+	mcrypto_dump("OAEP Decoding: Encoded Message em", em, k);
+	
+	if(*(em)) /* fist byte of encoded message not 0x00 */
+		return ERR_DECRYPTION;
+	
+	if((hlen = HashLenQuery(hid))==0)
+		return ERR_UNKNOWN_HASH;
+		
+	/* Compute Hash of L */
+	mcrypto_dump("OAEP Decoding: L", L, llen);
+	lHash = (BYTE *)malloc(hlen);
+	if((ret=Hash(hid, L, llen, lHash))!=0) {
+		free(lHash);
+		
+		return ret;
+	}
+	
+	mcrypto_dump("OAEP Decoding: Hash of L", lHash, hlen);
+	
+	/* Extracting maskedDB and maskedSeed from encoded message em */
+	maskedSeed = (BYTE *)malloc(hlen);
+	memcpy(maskedSeed, em+1, hlen);
+	mcrypto_dump("OAEP Decoding: maskedSeed", maskedSeed, hlen);
+	
+	maskedDB = (BYTE *)malloc(k-hlen-1);
+	memcpy(maskedDB, em+1+hlen, k-hlen-1);
+	mcrypto_dump("OAEP Decoding: maskedDB", maskedDB, k-hlen-1);
+	
+	/* Finding seed and DB */
+	seed = (BYTE *)malloc(hlen);
+	if((ret=MGF1(hid, maskedDB, k-hlen-1, seed, hlen))!=ERR_OK)
+	{
+		free(lHash);
+		free(maskedSeed);
+		free(maskedDB);
+		free(seed);
+		
+		return ret;
+	}
+	mcrypto_dump("OAEP Decoding: seedMask", seed, hlen);
+	
+	memxor(seed, seed, maskedSeed, hlen);
+	mcrypto_dump("OAEP Decoding: seed", seed, hlen);
+	
+	DB = (BYTE *)malloc(k-hlen-1);
+	if((ret=MGF1(hid, seed, hlen, DB, k-hlen-1))!=ERR_OK) {
+		free(lHash);
+		free(maskedSeed);
+		free(maskedDB);
+		free(seed);
+		free(DB);
+		
+		return ret;
+	}
+
+	mcrypto_dump("OAEP Decoding: dbMask", DB, k-hlen-1);
+	memxor(DB, DB, maskedDB, k-hlen-1);
+	mcrypto_dump("OAEP Decoding: DB", DB, k-hlen-1);
+	
+	/* Checking whether first hlen bits of DB equals to lHash */
+	if(memcmp(lHash, DB, hlen)!=0) {
+		free(lHash);
+		free(DB);
+		free(seed);
+		free(maskedDB);
+		free(maskedSeed);
+		
+		return ERR_DECRYPTION;
+	}
+	
+	/* Try to Extract M from DB */
+	i = hlen;
+	while((DB[i] == 0x00) && (DB[i] != 0x01) && (i < (k-hlen-1-1))) i++;
+	
+	if(i == (k-hlen-1-1)) {
+		free(lHash);
+		free(DB);
+		free(seed);
+		free(maskedDB);
+		free(maskedSeed);
+		
+		return ERR_DECRYPTION;
+	}
+	
+	if(DB[i] != 0x01) {
+		free(lHash);
+		free(DB);
+		free(seed);
+		free(maskedDB);
+		free(maskedSeed);
+		
+		return ERR_DECRYPTION;
+	}	
+	
+	*mlen = k-hlen-1-1 - (i+1) + 1; /* starting after 0x01 byte to the end of DB */
+	memcpy(m, DB+i+1, *mlen);
+	mcrypto_dump("OAEP Decoding: Plaintext m", m, *mlen);
+	
+	free(lHash);
+	free(DB);
+	free(seed);
+	free(maskedDB);
+	free(maskedSeed);
+		
+	return ERR_OK;
+}
+
+int PKCS1_RSA_OAEP_DECRYPT(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *c, BYTE *L, UINT llen, BYTE *m, UINT *mlen)
+{
+	/* RSA-OAEP Decryption */
+	BYTE *em;
+	int ret;
+	UINT hlen;
+	
+	if((hlen = HashLenQuery(hid)) == 0)
+		return ERR_UNKNOWN_HASH;
+	
+	/* Length checking */
+	if(NBYTE(ssk->len)<(2*hlen+2))
+		return ERR_DECRYPTION;
+	
+	mcrypto_dump("RSAOAEP Decrypt: Ciphertext", c, NBYTE(ssk->len));
+	
+	/* Do RSA Decryption */
+	em = (BYTE *)malloc(NBYTE(ssk->len));
+	ret = PKCS1_RSADP(ssk, (DIGIT_T *)c, (DIGIT_T *)em);
+	
+	mcrypto_dump("RSAOAEP Decrypt: OAEP-Encoded Message (After Decryption)",(BYTE *)em, NBYTE(ssk->len));
+	
+	/* Decoding Message */
+	ret = PKCS1_EME_OAEP_DEC(ssk, hid, em, L, llen, m, mlen);
+	
+	free(em); 
+	
+	return ret;
+}
+
+int PKCS1_RSASSA_PSS_SIGN(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *s)
+{
+	/* PKCS1 #1 RSA Signature Generation Using PSS Encoding */
+	BYTE *em;
+	int ret;
+	
+	/* Preparing encoded message */
+	em = (BYTE *)malloc(NBYTE(ssk->len));
+	
+	/* PSS Encoding */
+	if((ret=PKCS1_EMSA_PSS_ENCODE(hid, m, mlen, slen, em, NBYTE(ssk->len)))!=ERR_OK) {
+		free(em);
+		return ret;
+	}
+	
+	/* Signing */
+	ret = PKCS1_RSASP1(ssk, (DIGIT_T*)em, (DIGIT_T*)s);
+	mcrypto_dump("Signature",(BYTE *)s, NBYTE(ssk->len));
+	
+	free(em);
+	
+	return ret;
+}
+
+int PKCS1_RSASSA_PSS_VERIFY(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *s)
+{
+	/* PKCS #1 RSA Signature Verification Using PSS Encoding */
+	BYTE *em;
+	int ret;
+	
+	mcrypto_dump("Signature", s, NBYTE(spk->len));
+
+	/* Extracting encoded message */
+	em = (BYTE *)malloc(NBYTE(spk->len));
+	
+	if((ret = PKCS1_RSAVP1(spk, (DIGIT_T *)s, (DIGIT_T *)em))!=ERR_OK) {
+		free(em);
+		return ret;
+	}
+	mcrypto_dump("PSS-Encoded Message (Before Verificaton)",(BYTE *)em, NBYTE(spk->len));
+	
+	/* Verify encoded message */
+	ret = PKCS1_EMSA_PSS_VERIFY(hid, m, mlen, slen, em, NBYTE(spk->len));
+	
+	free(em);
+	
+	if(ret == ERR_PSS_CONSISTENT)
+		return ERR_VALID_SIGNATURE;
+		
+	return ERR_INVALID_SIGNATURE;
+}
+
+int PKCS1_EMSA_PSS_ENCODE(UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *em, UINT emlen)
+{
+	/* PSS Encoding */
+	UINT hlen;	/* Length of Hash Output */
+	BYTE *H;	/* Hash of m */
+	BYTE *salt;
+	BYTE *M;
+	BYTE *DB;
+	BYTE *maskedDB;
+	int ret;
+	
+	if((hlen = HashLenQuery(hid)) == 0)
+		return ERR_UNKNOWN_HASH;
+	
+	/* Computing Hash of m */
+	mcrypto_dump("PSS Encoding: Message", m, mlen);
+	H = (BYTE *)malloc(hlen);
+	if((ret = Hash(hid, m, mlen, H))!=0) {
+		free(H);
+		
+		return ret;
+	}
+
+	mcrypto_dump("PSS Encoding: Hashed Message", H, hlen);
+	
+	/* Length checking */
+	if(emlen<(hlen+slen+2)) {
+		free(H);
+		return ERR_PSS_ENCODING;
+	}
+	
+	/* Generating salt and constructing M */
+	salt = (BYTE *)malloc(slen);
+	GenSeed(salt, slen);
+	mcrypto_dump("PSS Encoding: Salt", salt, slen);
+	
+	M = (BYTE *)malloc(8+hlen+slen);
+	memset(M, 0x00, 8+hlen+slen);
+	memcpy(M+8, H, hlen);
+	memcpy(M+8+hlen, salt, slen);
+	mcrypto_dump("PSS Encoding: Message to be encoded", M, 8+hlen+slen);
+	
+	/* Constructing DB */
+	if((ret = Hash(hid, M, 8+hlen+slen, H))!=0) {
+		free(H);
+		free(M);
+		free(salt);
+		
+		return ret;
+	}
+	mcrypto_dump("PSS Encoding: Hash of Message to be encoded", H, hlen);
+	
+	DB = (BYTE *)malloc(emlen-hlen-1);
+	memset(DB, 0x00, emlen-hlen-1);
+	DB[emlen-slen-hlen-2] = 0x01;
+	memcpy(DB+emlen-slen-hlen-1, salt, slen);
+	mcrypto_dump("PSS Encoding: DB", DB, emlen-hlen-1);
+	
+	/* Computing maskedDB */
+	maskedDB = (BYTE *)malloc(emlen-hlen-1);
+	if((ret=MGF1(hid, H, hlen, maskedDB, emlen-hlen-1))!=ERR_OK) {
+		free(H);
+		free(M);
+		free(salt);
+		free(maskedDB);
+		free(DB);
+		
+		return ret;
+	}
+
+	mcrypto_dump("PSS Encoding: dbMask", maskedDB, emlen-hlen-1);
+	
+	memxor(maskedDB, maskedDB, DB, emlen-hlen-1);
+	mcrypto_dump("PSS Encoding: maskedDB", maskedDB, emlen-hlen-1);
+	
+	/* Constructing encoded message, em */
+	memcpy(em, maskedDB, emlen-hlen-1);
+	memcpy(em+emlen-hlen-1, H, hlen);
+	em[emlen-1] = 0xbc;
+	mcrypto_dump("PSS Encoding: Encoded Message", em, emlen);
+	
+	return ERR_OK;
+}
+
+int PKCS1_EMSA_PSS_VERIFY(UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *em, UINT emlen)
+{
+	/* PSS Verification */
+	UINT hlen;	/* Length of Hash Output */
+	BYTE *H;	/* Hash of m */
+	BYTE *M;
+	BYTE *mHash;
+	BYTE *DB;
+	BYTE *maskedDB;
+	int ret;
+	
+	if((hlen = HashLenQuery(hid)) == 0)
+		return ERR_UNKNOWN_HASH;
+	
+	/* Computing Hash of m */
+	mcrypto_dump("PSS Verify: Message", m, mlen);
+	mHash = (BYTE *)malloc(hlen);
+	if((ret = Hash(hid, m, mlen, mHash))!=0) {
+		free(mHash);
+		return ret;
+	}
+	
+	mcrypto_dump("PSS Verify: Hash of Message", mHash, hlen);
+	
+	/* Length checking */
+	mcrypto_dump("PSS Verify: Encoded Message", em, emlen);
+	
+	if(emlen<(hlen+slen+2)) {
+		free(mHash);
+		return ERR_PSS_INCONSISTENT;
+	}
+	
+	/* Verification */
+	if(em[emlen-1]!=0xbc) {
+		free(mHash);
+		return ERR_PSS_INCONSISTENT;
+	}
+	
+	/* Extracting maskedDB and H */
+	maskedDB = (BYTE *)malloc(emlen-hlen-1);
+	memcpy(maskedDB, em, emlen-hlen-1);
+	mcrypto_dump("PSS Verify: maskedDB", maskedDB, emlen-hlen-1);
+	
+	H = (BYTE *)malloc(hlen);
+	memcpy(H, em+emlen-hlen-1, hlen);
+	mcrypto_dump("PSS Verify: H", H, hlen);
+	
+	/* Computing DB */ 
+	DB = (BYTE *)malloc(emlen-hlen-1);
+	if((ret=MGF1(hid, H, hlen, DB, emlen-hlen-1))!=ERR_OK) {
+		free(H);
+		free(mHash);
+		free(maskedDB);
+		free(DB);
+		
+		return ret;
+	}
+	mcrypto_dump("PSS Verify: dbMask", DB, emlen-hlen-1);
+	
+	memxor(DB, DB, maskedDB, emlen-hlen-1);
+	mcrypto_dump("PSS Verify: DB", DB, emlen-hlen-1);
+	
+	if(DB[emlen-slen-hlen-2]!=0x01) {
+		free(H);
+		free(mHash);
+		free(maskedDB);
+		free(DB);
+		
+		return ERR_PSS_INCONSISTENT;
+	}
+	
+	M = (BYTE *)malloc(8+hlen+slen);
+	memset(M, 0x00, 8+hlen+slen);
+	memcpy(M+8, mHash, hlen);
+	memcpy(M+8+hlen, DB+emlen-slen-hlen-1, slen);
+	mcrypto_dump("PSS Verify: Message to encoded", M, 8+hlen+slen);
+	
+	if((ret = Hash(hid, M, 8+hlen+slen, mHash))!=0) {
+		free(H);
+		free(mHash);
+		free(maskedDB);
+		free(DB);
+		free(M);
+		
+		return ret;
+	}
+	
+	mcrypto_dump("PSS Verify: Hash of Message to encoded", mHash, hlen);
+	
+	if(memcmp(H, mHash, hlen)!=0) 
+		return ERR_PSS_INCONSISTENT;
+		
+	return ERR_PSS_CONSISTENT;
+}
+
+void errmsg(int err)
+{
+	switch(err) {
+	case ERR_OK:			printf("Job Done Successfully!!!\n"); break;
+	case ERR_MOD_TOO_SMALL:		printf("Wow!!! Modulus Length Too Short.\n"); break;
+	case ERR_MOD_TOO_LONG:		printf("Sorry!!! Modulus Length Too Long.\n"); break;
+	case ERR_PRIME_FAILED:		printf("Failed To Generate A Prime. Try It Again.\n"); break;
+	case ERR_MSG_TOO_LONG:		printf("Sorry!!! Message Too Long.\n"); break;
+	case ERR_LABEL_TOO_LONG:	printf("Sorry!!! OAEP Label Too Long\n"); break;
+	case ERR_DECRYPTION:		printf("Sorry!!! Decryption Error.\n"); break;
+	case ERR_UNKNOWN_HASH:		printf("Sorry!!! Hash Function Not Available.\n"); break;
+	case ERR_VALID_SIGNATURE:	printf("Good!!! Signature Is Valid.\n"); break;	
+	case ERR_INVALID_SIGNATURE:	printf("Sorry!!! Signature Is Invalid.\n"); break;
+	case ERR_PSS_CONSISTENT:	printf("Good!!! PSS-Encoded Message Is Consistent.\n"); break;
+	case ERR_PSS_INCONSISTENT:	printf("Sorry!!! PSS-Encoded Message Is Inconsistent.\n"); break;
+	case ERR_PSS_ENCODING:		printf("Sorry!!! PSS Encoding Error\n"); break;
+	case ERR_HASH:			printf("Sorry!!! Hash Function Error. Maybe Hash Input Limit Exceeded\n"); break;
+	default: 			printf("Unkown Error!!!\n"); break;
+	}
+}
+
+int LoadPublicKey(char *fname, PKCS1_RSA_PUBLIC_KEY *spk)
+{
+	/* Load keys from files */
+	char s[5][PKCS1_MAX_LINE_LEN];	
+	FILE *f;
+	UINT i;
+	UINT len;
+	
+	f = fopen(fname, "r");
+	if(f == NULL)
+		return -1;
+	
+	memset(s, 0x00, PKCS1_MAX_LINE_LEN*5);	
+	/* reading data */
+	for(i=0;i<5;i++)
+	{
+		if(feof(f))
+		{
+			fclose(f);
+			return -1;
+		}
+		fgets(s[i], PKCS1_MAX_LINE_LEN, f);
+		
+		/* ignore newline charater */		
+		s[i][strlen(s[i])-1] = '\0';
+	}
+	fclose(f);
+	
+	/* Decoding data */
+	spk->len = (UINT)atoi(s[1]);
+	
+	if((spk->modulus = mpBase64Decode(&len, s[2]))==NULL)
+		return -1; 
+	if((spk->exponent = mpBase64Decode(&len, s[3]))==NULL)
+		return -1; 
+	return 0;
+}
+
+int LoadPrivateKey(char *fname, PKCS1_RSA_PRIVATE_KEY *ssk)
+{
+	/* Load keys from files */
+	char s[6][PKCS1_MAX_LINE_LEN];
+	FILE *f;
+	UINT i;
+	UINT len;
+	
+	f = fopen(fname, "r");
+	if(f == NULL)
+		return -1;
+		
+	memset(s, 0x00, PKCS1_MAX_LINE_LEN*6);	
+	
+	/* reading data */
+	for(i=0;i<5;i++)
+	{
+		if(feof(f))
+		{
+			fclose(f);
+			return -1;
+		}
+		fgets(s[i], PKCS1_MAX_LINE_LEN, f);
+		s[i][strlen(s[i])-1] = '\0';
+	}
+	fclose(f);
+	
+	ssk->len = (UINT)atoi(s[1]);
+	
+	if((ssk->modulus = mpBase64Decode(&len, s[2]))==NULL)
+		return -1; 
+	if((ssk->PublicExponent = mpBase64Decode(&len, s[3]))==NULL)
+		return -1; 
+	if((ssk->exponent = mpBase64Decode(&len, s[4]))==NULL)
+		return -1; 	
+	
+	return 0;
+}
+
+
diff --git a/src/libm/pkcs1-rsa.h b/src/libm/pkcs1-rsa.h
new file mode 100644
index 000000000000..9e2b58acd9da
--- /dev/null
+++ b/src/libm/pkcs1-rsa.h
@@ -0,0 +1,119 @@ 
+/* pkcs1-rsa.h */
+
+#ifndef _PKCS1RSA_H_
+#define _PKCS1RSA_H_
+
+#include "bigdigits.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PKCS1_MAX_LINE_LEN	346	/* for reading parameter file */
+
+#define PKCS1_VERSION_MAJOR 2
+#define PKCS1_VERSION_MINOR 1
+
+/* RSA key lengths. */
+#define MIN_RSA_MODULUS_LEN 	5		/* 160 bits */
+#define MAX_RSA_MODULUS_LEN 	MAX_DIG_LEN	/* 2048 bits */
+#define MAX_MSG_LEN		256		/* bytes */
+
+/* Error codes - todo: move into mcrypto.h and add MCRYPTO prefix */
+#define ERR_DEFAULT		0x00
+#define ERR_OK			0x01
+#define ERR_MOD_TOO_SMALL	0x02
+#define ERR_MOD_TOO_LONG	0x03
+#define ERR_PRIME_FAILED	0x04
+#define ERR_MSG_TOO_LONG        0x05
+#define ERR_LABEL_TOO_LONG      0x06
+#define ERR_DECRYPTION		0x07
+#define ERR_UNKNOWN_HASH	0x08
+#define ERR_VALID_SIGNATURE     0x09
+#define ERR_INVALID_SIGNATURE   0x0a
+#define ERR_PSS_CONSISTENT	0x0b
+#define ERR_PSS_INCONSISTENT	0x0c
+#define ERR_PSS_ENCODING	0x0d
+#define ERR_HASH		0x0e
+
+
+
+/* PKCS1-RSA public and private key. */
+typedef struct {
+  UINT    len;			/* length in digits of modulus */
+  DIGIT_T *modulus;  		/* modulus */
+  DIGIT_T *exponent; 		/* public exponent */
+} PKCS1_RSA_PUBLIC_KEY;
+
+typedef struct {
+  UINT len;       		/* length in digits of modulus */
+  DIGIT_T *modulus;		/* modulus */
+  DIGIT_T *PublicExponent; 	/* public exponent */
+  DIGIT_T *exponent; 		/* private exponent */
+  
+  /* for fast decryption using CRT */
+  DIGIT_T *p;   		/* prime factor 1 */
+  UINT    plen;			/* length in digits of p */
+  DIGIT_T *q;   		/* prime factor 2 */
+  UINT    qlen;			/* length in digits of q = len - plen */
+  DIGIT_T *dP;     		/* e*dP = 1 mod p-1 */
+  DIGIT_T *dQ;     		/* e*dQ = 1 mod q-1 */
+  DIGIT_T *qInv;          	/* q*qInv = 1 mod p */
+} PKCS1_RSA_PRIVATE_KEY;
+
+
+/* function prototype */
+void errmsg(int err);
+	/* Print out error message */
+	
+int PKCS1_RSA_GenKey(PKCS1_RSA_PUBLIC_KEY *spk, PKCS1_RSA_PRIVATE_KEY *ssk, UINT mod_len);
+	/* PKCS #1 Key Generation according to modulus bit length, len*BITS_PER_DIGIT */
+
+int PKCS1_RSAEP(PKCS1_RSA_PUBLIC_KEY *spk, DIGIT_T *m, DIGIT_T *c);
+	/* PKCS #1 Encryption Primitive */
+
+int PKCS1_RSADP(PKCS1_RSA_PRIVATE_KEY *ssk, DIGIT_T *c, DIGIT_T *m);
+	/* PKCS #1 Decryption Primitive */
+
+int PKCS1_RSASP1(PKCS1_RSA_PRIVATE_KEY *ssk, DIGIT_T *m, DIGIT_T *s);
+	/* PKCS #1 Signature Generation Primitive */
+
+int PKCS1_RSAVP1(PKCS1_RSA_PUBLIC_KEY *spk, DIGIT_T *s, DIGIT_T *m);
+	/* PKCS #1 Signature Verification Primitive */
+
+int PKCS1_EME_OAEP_ENC(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, BYTE *L, UINT llen, BYTE *em);
+	/* PKCS #1 OAEP encoding function */
+
+int PKCS1_RSA_OAEP_ENCRYPT(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, BYTE *L, UINT llen, BYTE *c); 
+	/* PKCS #1 OAEP Encryption */
+
+int PKCS1_EME_OAEP_DEC(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *em, BYTE *L, UINT llen, BYTE *m, UINT *mlen);
+	/* PKCS #1 OAEP decoding function */
+
+int PKCS1_RSA_OAEP_DECRYPT(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *c, BYTE *L, UINT llen, BYTE *m, UINT *mlen); 
+	/* PKCS #1 OAEP Decryption */
+
+int PKCS1_RSASSA_PSS_SIGN(PKCS1_RSA_PRIVATE_KEY *ssk, UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *s);
+	/* PKCS #1 Signature Generation Using PSS encoding method */
+
+int PKCS1_RSASSA_PSS_VERIFY(PKCS1_RSA_PUBLIC_KEY *spk, UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *s);
+	/* PKCS #1 Signature Verification */
+
+int PKCS1_EMSA_PSS_ENCODE(UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *em, UINT emlen);
+	/* PKCS #1 PSS Encoding */
+
+int PKCS1_EMSA_PSS_VERIFY(UINT hid, BYTE *m, UINT mlen, UINT slen, BYTE *em, UINT emlen);	
+	/* PKCS #1 PSS Verification */
+
+/* Untility Functions */
+int LoadPublicKey(char *fname, PKCS1_RSA_PUBLIC_KEY *spk);
+	/* Public Key Loader */
+
+int LoadPrivateKey(char *fname, PKCS1_RSA_PRIVATE_KEY *ssk);
+	/* Secret Key Loader */
+			
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _PKCS1RSA_H_ */
diff --git a/src/libm/sha1.c b/src/libm/sha1.c
new file mode 100644
index 000000000000..ffe9645d80c9
--- /dev/null
+++ b/src/libm/sha1.c
@@ -0,0 +1,155 @@ 
+/*
+SHA-1 in C
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+    unsigned long a, b, c, d, e;
+    typedef union {
+        unsigned char c[64];
+        unsigned long l[16];
+    } CHAR64LONG16;
+    
+    CHAR64LONG16* block;
+    
+    block = (CHAR64LONG16*)buffer;
+
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+    
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+    unsigned int i, j;
+
+    j = (context->count[0] >> 3) & 63;
+    
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+    unsigned long i, j;
+    unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+    for (i = 0; i < 20; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    
+    /* Wipe variables */
+    i = j = 0;
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, 20);
+    memset(context->count, 0, 8);
+    memset(&finalcount, 0, 8);
+}
+
+/*--------------- end of sha1.c -------------------*/
+
diff --git a/src/libm/sha1.h b/src/libm/sha1.h
new file mode 100644
index 000000000000..b208a9533484
--- /dev/null
+++ b/src/libm/sha1.h
@@ -0,0 +1,26 @@ 
+/* sha1.h */
+
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    unsigned long state[5];
+    unsigned long count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/libm/sha2.c b/src/libm/sha2.c
new file mode 100644
index 000000000000..a9ff5659f54a
--- /dev/null
+++ b/src/libm/sha2.c
@@ -0,0 +1,724 @@ 
+
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+Issue Date: 9/10/2002
+
+   This is a byte oriented version of SHA2 that operates on arrays of bytes
+   stored in memory. This code implements sha256, sha384 and sha512 but the
+   latter two functions rely on efficient 64-bit integer operations that 
+   may not be very efficient on 32-bit machines
+
+   The sha256 functions use a type 'sha256_ctx' to hold details of the 
+   current hash state and uses the following three calls:
+
+       void sha256_begin(sha256_ctx ctx[1])
+       void sha256_hash(const unsigned char data[], 
+							const unsigned long len, sha256_ctx ctx[1])
+       void sha256_end(unsigned char hval[], sha256_ctx ctx[1])
+
+   The first subroutine initialises a hash computation by setting up the 
+   context in the sha256_ctx context. The second subroutine hashes 8-bit 
+   bytes from array data[] into the hash state withinh sha256_ctx context, 
+   the number of bytes to be hashed being given by the the unsigned long 
+   integer len.  The third subroutine completes the hash calculation and 
+   places the resulting digest value in the array of 8-bit bytes hval[].
+
+   The sha384 and sha512 functions are similar and use the interfaces:
+
+       void sha384_begin(sha384_ctx ctx[1]);
+       void sha384_hash(const unsigned char data[], 
+							const unsigned long len, sha384_ctx ctx[1]);
+       void sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
+
+       void sha512_begin(sha512_ctx ctx[1]);
+       void sha512_hash(const unsigned char data[], 
+							const unsigned long len, sha512_ctx ctx[1]);
+       void sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
+
+   In addition there is a function sha2 that can be used to call all these
+   functions using a call with a hash length parameter as follows:
+
+       int sha2_begin(const unsigned long len, sha2_ctx ctx[1]);
+       void sha2_hash(const unsigned char data[], 
+							const unsigned long len, sha2_ctx ctx[1]);
+       void sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
+
+   My thanks to Erik Andersen <andersen@codepoet.org> for testing this code 
+   on big-endian systems and for his assistance with corrections
+ */
+
+/* define the hash functions that you need  */
+
+#define SHA_2
+#define SHA_256
+#define SHA_384
+#define SHA_512
+
+/*  Defining FAST_COPY will generally improve speed but it assumes that 
+    arrays of 32-bit words can be addressed as arrays of bytes by casting 
+	the array base address. Defining WORD_COPY avoids this problem by 
+	assembling bytes into a word variable before copying to memory. If
+    neither is defined a slow but safe byte oriented version is used.
+*/
+
+#if 1
+#define FAST_COPY
+#elif 0
+#define WORD_COPY
+#endif
+
+/* end of user defined options */
+
+#include <string.h>     /* for memcpy() etc.        */
+#include <stdlib.h>     /* for _lrotr with VC++     */
+
+#include "sha2.h"
+
+/*  1. PLATFORM SPECIFIC INCLUDES */
+
+#if defined(__GNU_LIBRARY__)
+#  include <endian.h>
+#  include <byteswap.h>
+#elif defined(_MSC_VER)
+#  include <stdlib.h>
+#elif !defined(WIN32)
+#  include <stdlib.h>
+#endif
+
+/*  2. BYTE ORDER IN 32-BIT WORDS
+
+    To obtain the highest speed on processors with 32-bit words, this code 
+    needs to determine the order in which bytes are packed into such words.
+    The following block of code is an attempt to capture the most obvious 
+    ways in which various environemnts specify their endian definitions. 
+	It may well fail, in which case the definitions will need to be set by 
+    editing at the points marked **** EDIT HERE IF NECESSARY **** below.
+*/
+#define SHA_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
+#define SHA_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
+
+#if !defined(PLATFORM_BYTE_ORDER)
+#if defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN)
+#  if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+#    if defined(BYTE_ORDER)
+#      if   (BYTE_ORDER == LITTLE_ENDIAN)
+#        define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#      elif (BYTE_ORDER == BIG_ENDIAN)
+#        define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#      endif
+#    endif
+#  elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) 
+#    define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#  elif !defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+#    define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#  endif
+#elif defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)
+#  if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+#    if defined(_BYTE_ORDER)
+#      if   (_BYTE_ORDER == _LITTLE_ENDIAN)
+#        define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#      elif (_BYTE_ORDER == _BIG_ENDIAN)
+#        define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#      endif
+#    endif
+#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) 
+#    define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#  elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+#    define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#  endif
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#elif (('1234' >> 24) == '1')
+#  define PLATFORM_BYTE_ORDER SHA_LITTLE_ENDIAN
+#elif (('4321' >> 24) == '1')
+#  define PLATFORM_BYTE_ORDER SHA_BIG_ENDIAN
+#endif
+#endif
+
+#if !defined(PLATFORM_BYTE_ORDER)
+#  error Please set undetermined byte order (lines 171 or 173 of sha2.c).
+#endif
+
+/* this Microsft VC++ intrinsic rotate makes a big difference to the speed of this code */
+
+#if defined(_MSC_VER)
+#define rotr32(x,n)   _lrotr(x,n)
+#else
+#define rotr32(x,n)   (((x) >> n) | ((x) << (32 - n)))
+#endif
+
+#define rotr64(x,n)   (((x) >> n) | ((x) << (64 - n)))
+
+/* reverse byte order in 32-bit words   */
+
+#if !defined(bswap_32)
+#define bswap_32(x) (rotr32((x), 24) & 0x00ff00ff | rotr32((x), 8) & 0xff00ff00)
+#endif
+
+#if !defined(bswap_64)
+#define bswap_64(x) (((sha_64t)(bswap_32((sha_32t)(x)))) << 32 | bswap_32((sha_32t)((x) >> 32)))
+#endif
+
+#if defined(FAST_COPY) && (PLATFORM_BYTE_ORDER == SHA_LITTLE_ENDIAN)
+#define SWAP_BYTES
+#else
+#undef  SWAP_BYTES
+#endif
+
+#if defined(SHA_2) || defined(SHA_256)
+
+/* SHA256 mixing function definitions   */
+
+#define ch(x,y,z)   (((x) & (y)) ^ (~(x) & (z)))
+#define maj(x,y,z)  (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+#define s256_0(x) (rotr32((x),  2) ^ rotr32((x), 13) ^ rotr32((x), 22)) 
+#define s256_1(x) (rotr32((x),  6) ^ rotr32((x), 11) ^ rotr32((x), 25)) 
+#define g256_0(x) (rotr32((x),  7) ^ rotr32((x), 18) ^ ((x) >>  3)) 
+#define g256_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) 
+
+/* rotated SHA256 round definition. Rather than swapping variables as in    */
+/* FIPS-180, different variables are 'rotated' on each round, returning     */
+/* to their starting positions every eight rounds                           */
+
+#define h2(i) ctx->wdat[i & 15] += \
+    g256_1(ctx->wdat[(i + 14) & 15]) + ctx->wdat[(i + 9) & 15] + g256_0(ctx->wdat[(i + 1) & 15])
+
+#define h2_cycle(i,j)  \
+    v[(7 - i) & 7] += (j ? h2(i) : ctx->wdat[i & 15]) + k256[i + j] \
+        + s256_1(v[(4 - i) & 7]) + ch(v[(4 - i) & 7], v[(5 - i) & 7], v[(6 - i) & 7]); \
+    v[(3 - i) & 7] += v[(7 - i) & 7]; \
+    v[(7 - i) & 7] += s256_0(v[(0 - i) & 7]) + maj(v[(0 - i) & 7], v[(1 - i) & 7], v[(2 - i) & 7])
+
+/* SHA256 mixing data   */
+
+const sha_32t k256[64] =
+{   n_u32(428a2f98), n_u32(71374491), n_u32(b5c0fbcf), n_u32(e9b5dba5), 
+    n_u32(3956c25b), n_u32(59f111f1), n_u32(923f82a4), n_u32(ab1c5ed5), 
+    n_u32(d807aa98), n_u32(12835b01), n_u32(243185be), n_u32(550c7dc3), 
+    n_u32(72be5d74), n_u32(80deb1fe), n_u32(9bdc06a7), n_u32(c19bf174), 
+    n_u32(e49b69c1), n_u32(efbe4786), n_u32(0fc19dc6), n_u32(240ca1cc), 
+    n_u32(2de92c6f), n_u32(4a7484aa), n_u32(5cb0a9dc), n_u32(76f988da), 
+    n_u32(983e5152), n_u32(a831c66d), n_u32(b00327c8), n_u32(bf597fc7), 
+    n_u32(c6e00bf3), n_u32(d5a79147), n_u32(06ca6351), n_u32(14292967), 
+    n_u32(27b70a85), n_u32(2e1b2138), n_u32(4d2c6dfc), n_u32(53380d13), 
+    n_u32(650a7354), n_u32(766a0abb), n_u32(81c2c92e), n_u32(92722c85),
+    n_u32(a2bfe8a1), n_u32(a81a664b), n_u32(c24b8b70), n_u32(c76c51a3), 
+    n_u32(d192e819), n_u32(d6990624), n_u32(f40e3585), n_u32(106aa070), 
+    n_u32(19a4c116), n_u32(1e376c08), n_u32(2748774c), n_u32(34b0bcb5), 
+    n_u32(391c0cb3), n_u32(4ed8aa4a), n_u32(5b9cca4f), n_u32(682e6ff3), 
+    n_u32(748f82ee), n_u32(78a5636f), n_u32(84c87814), n_u32(8cc70208), 
+    n_u32(90befffa), n_u32(a4506ceb), n_u32(bef9a3f7), n_u32(c67178f2),
+};
+
+/* SHA256 initialisation data */
+
+const sha_32t i256[8] =
+{
+    n_u32(6a09e667), n_u32(bb67ae85), n_u32(3c6ef372), n_u32(a54ff53a),
+    n_u32(510e527f), n_u32(9b05688c), n_u32(1f83d9ab), n_u32(5be0cd19)
+};
+
+void sha256_begin(sha256_ctx ctx[1])
+{
+    ctx->count[0] = ctx->count[1] = 0;
+    memcpy(ctx->hash, i256, 32);
+}
+
+/* Compile 64 bytes of hash data into SHA256 digest value  */
+
+static void sha256_compile(sha256_ctx ctx[1])
+{   sha_32t    v[8], j;
+
+    memcpy(v, ctx->hash, 32);
+
+    for(j = 0; j < 64; j += 16)
+    {
+        h2_cycle( 0, j); h2_cycle( 1, j); h2_cycle( 2, j); h2_cycle( 3, j);
+        h2_cycle( 4, j); h2_cycle( 5, j); h2_cycle( 6, j); h2_cycle( 7, j);
+        h2_cycle( 8, j); h2_cycle( 9, j); h2_cycle(10, j); h2_cycle(11, j);
+        h2_cycle(12, j); h2_cycle(13, j); h2_cycle(14, j); h2_cycle(15, j);
+    }
+
+    ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
+    ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
+}
+
+/* SHA256 hash data in an array of bytes into hash buffer and call the      */
+/* hash_compile function as required.                                       */
+
+/* If FAST_COPY is defined the data to be hashed is processed as an array   */
+/* bytes and compiled into the buffer ctx->wdat[] of 32-bit words in the    */
+/* native byte order.  On little endian machines a 32-bit word byte swap    */
+/* is then performed before this data is compiled into the hash. But when   */
+/* FAST_COPY is not defined the bytes are compiled into the buffer in the   */
+/* big-endian format directly so no later byte order changes are needed.    */
+
+#if defined(FAST_COPY)
+
+void sha256_hash(const unsigned char data[], const unsigned long len, sha256_ctx ctx[1])
+{   sha_32t            free = 64 - (sha_32t)(ctx->count[0] & 63), rlen = len, j;
+    const unsigned char *sp = data;
+    unsigned char       *p = ((unsigned char*)ctx->wdat) + (ctx->count[0] & 63);
+
+    while(rlen >= free)     /* tranfer whole blocks while possible  */
+    {
+        memcpy(p, sp, free);
+        if((ctx->count[0] += free) < free)
+            ++(ctx->count[1]);
+        sp += free; rlen -= free; free = 64; 
+        p = (unsigned char*)ctx->wdat;
+#if defined(SWAP_BYTES)
+        for(j = 0; j < 16; ++j)
+            ctx->wdat[j] = bswap_32(ctx->wdat[j]);
+#endif
+        sha256_compile(ctx);
+    }
+
+    memcpy(p, sp, rlen);    /* transfer partial block               */
+    if((ctx->count[0] += rlen) < rlen)
+        ++(ctx->count[1]);
+    p = (unsigned char*)ctx->wdat;
+    rlen = (ctx->count[0] & 63);
+    while(rlen & 3)         /* ensure rest of 32-bit word is zero   */
+        *(p + rlen++) = 0;	/* [could be done in sha256_end()]		*/
+}
+
+#elif defined(WORD_COPY)    /* alternative implementations          */
+
+void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1])
+{   sha_32t i = 0, *ptr, cnt, val, j;
+
+    ptr = ctx->wdat + ((ctx->count[0] >> 2) & 15);
+    cnt = (ctx->count[0] << 3) & 24;
+    val = (cnt ? *ptr : 0);
+    while(i < len)
+    {   /* assemble values in big-endian format */
+        val |= ((sha_32t)data[i++]) << 24 - cnt;
+        if(!++(ctx->count[0])) ++(ctx->count[1]);
+        if(!(cnt = (cnt + 8) & 24))
+        {   *ptr++ = val; val = 0;
+            if(ptr - ctx->wdat == 16) 
+            {
+                sha256_compile(ctx); 
+                ptr = ctx->wdat;
+            }
+        }
+    }
+    *ptr = val;
+}
+
+#else
+
+void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1])
+{   sha_32t i = 0, cnt = ctx->count[0], j;
+
+    while(i < len)
+    {   /* assemble values in big-endian format */
+        if((cnt & 3) == 0) ctx->wdat[(cnt >> 2) & 15] = 0;
+        ctx->wdat[(cnt >> 2) & 15] |= (sha_32t)data[i++] << (24 - (8 * (cnt & 3)));
+        if(!++(ctx->count[0])) ++(ctx->count[1]);
+        if((++cnt & 63) == 0) 
+        {
+            sha256_compile(ctx);
+        }
+    }
+}
+
+#endif
+
+/* SHA256 Final padding and digest calculation  */
+
+void sha256_end(unsigned char hval[], sha256_ctx ctx[1])
+{   sha_32t    i, j, cnt = (sha_32t)(ctx->count[0] & 63);
+
+#if defined(SWAP_BYTES)
+        for(i = 0, j = (cnt + 3) >> 2; i < j; ++i)
+            ctx->wdat[i] = bswap_32(ctx->wdat[i]);
+#endif
+
+    /* we are now in big-endian order within the ctx->wdat[] buffer	*/
+	/* we now need to add the padding which is a single 1 bit and	*/
+	/* as many zero bits as necessary. Start by padding out the		*/
+	/* last valid 32-bit word in the buffer							*/
+
+    if(cnt & 3)
+        ctx->wdat[(cnt >> 2) & 15] |= n_u32(00000080) << (24  - (8 * (cnt & 3)));
+    else
+        ctx->wdat[(cnt >> 2) & 15] = n_u32(80000000);
+
+    if((cnt & 63) > 55)	/* there is not enough space in the buffer	*/
+    {					/* for the length field - pad and empty it	*/
+        if((cnt & 63) == 55) ctx->wdat[14] = 0;
+        if((cnt & 63) <= 59) ctx->wdat[15] = 0;
+        sha256_compile(ctx);
+        cnt = 0;
+    }
+    else	/* compute a word index for the empty buffer positions	*/
+        cnt = (cnt >> 2) + 1;
+
+    while(cnt < 14)	/* and zero pad all but last two positions		*/ 
+        ctx->wdat[cnt++] = 0;
+    
+    /* the following 32-bit length fields are assembled in the		*/
+	/* wrong byte order on little endian machines but this is		*/
+	/* corrected later since they are only ever used as 32-bit		*/
+	/* word values.													*/
+
+    ctx->wdat[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
+    ctx->wdat[15] = ctx->count[0] << 3;
+
+    sha256_compile(ctx);
+
+	/* extract the hash value as bytes in case the hash buffer is	*/
+	/* mislaigned for 32-bit words									*/
+
+	for(i = 0; i < SHA256_DIGEST_LENGTH; ++i)
+        hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (24 - 8 * (i & 3)));
+}
+
+#endif
+
+#if defined(SHA_2) || defined(SHA_384) || defined(SHA_512)
+
+/* SHA512 mixing function definitions   */
+
+#define s512_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39)) 
+#define s512_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41)) 
+#define g512_0(x) (rotr64((x),  1) ^ rotr64((x),  8) ^ ((x) >>  7)) 
+#define g512_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >>  6)) 
+
+/* rotated SHA512 round definition. Rather than swapping variables as in    */
+/* FIPS-180, different variables are 'rotated' on each round, returning     */
+/* to their starting positions every eight rounds                           */
+
+#define h5(i) ctx->wdat[i & 15] += \
+    g512_1(ctx->wdat[(i + 14) & 15]) + ctx->wdat[(i + 9) & 15] + g512_0(ctx->wdat[(i + 1) & 15])
+
+#define h5_cycle(i,j)  \
+    v[(7 - i) & 7] += (j ? h5(i) : ctx->wdat[i & 15]) + k512[i + j] \
+        + s512_1(v[(4 - i) & 7]) + ch(v[(4 - i) & 7], v[(5 - i) & 7], v[(6 - i) & 7]); \
+    v[(3 - i) & 7] += v[(7 - i) & 7]; \
+    v[(7 - i) & 7] += s512_0(v[(0 - i) & 7]) + maj(v[(0 - i) & 7], v[(1 - i) & 7], v[(2 - i) & 7])
+
+/* SHA384/SHA512 mixing data    */
+
+const sha_64t  k512[80] = 
+{
+    n_u64(428a2f98d728ae22), n_u64(7137449123ef65cd), 
+    n_u64(b5c0fbcfec4d3b2f), n_u64(e9b5dba58189dbbc),
+    n_u64(3956c25bf348b538), n_u64(59f111f1b605d019),
+    n_u64(923f82a4af194f9b), n_u64(ab1c5ed5da6d8118),
+    n_u64(d807aa98a3030242), n_u64(12835b0145706fbe),
+    n_u64(243185be4ee4b28c), n_u64(550c7dc3d5ffb4e2),
+    n_u64(72be5d74f27b896f), n_u64(80deb1fe3b1696b1),
+    n_u64(9bdc06a725c71235), n_u64(c19bf174cf692694),
+    n_u64(e49b69c19ef14ad2), n_u64(efbe4786384f25e3),
+    n_u64(0fc19dc68b8cd5b5), n_u64(240ca1cc77ac9c65),
+    n_u64(2de92c6f592b0275), n_u64(4a7484aa6ea6e483),
+    n_u64(5cb0a9dcbd41fbd4), n_u64(76f988da831153b5),
+    n_u64(983e5152ee66dfab), n_u64(a831c66d2db43210),
+    n_u64(b00327c898fb213f), n_u64(bf597fc7beef0ee4),
+    n_u64(c6e00bf33da88fc2), n_u64(d5a79147930aa725),
+    n_u64(06ca6351e003826f), n_u64(142929670a0e6e70),
+    n_u64(27b70a8546d22ffc), n_u64(2e1b21385c26c926),
+    n_u64(4d2c6dfc5ac42aed), n_u64(53380d139d95b3df),
+    n_u64(650a73548baf63de), n_u64(766a0abb3c77b2a8),
+    n_u64(81c2c92e47edaee6), n_u64(92722c851482353b),
+    n_u64(a2bfe8a14cf10364), n_u64(a81a664bbc423001),
+    n_u64(c24b8b70d0f89791), n_u64(c76c51a30654be30),
+    n_u64(d192e819d6ef5218), n_u64(d69906245565a910),
+    n_u64(f40e35855771202a), n_u64(106aa07032bbd1b8),
+    n_u64(19a4c116b8d2d0c8), n_u64(1e376c085141ab53),
+    n_u64(2748774cdf8eeb99), n_u64(34b0bcb5e19b48a8),
+    n_u64(391c0cb3c5c95a63), n_u64(4ed8aa4ae3418acb),
+    n_u64(5b9cca4f7763e373), n_u64(682e6ff3d6b2b8a3),
+    n_u64(748f82ee5defb2fc), n_u64(78a5636f43172f60),
+    n_u64(84c87814a1f0ab72), n_u64(8cc702081a6439ec),
+    n_u64(90befffa23631e28), n_u64(a4506cebde82bde9),
+    n_u64(bef9a3f7b2c67915), n_u64(c67178f2e372532b),
+    n_u64(ca273eceea26619c), n_u64(d186b8c721c0c207),
+    n_u64(eada7dd6cde0eb1e), n_u64(f57d4f7fee6ed178),
+    n_u64(06f067aa72176fba), n_u64(0a637dc5a2c898a6),
+    n_u64(113f9804bef90dae), n_u64(1b710b35131c471b),
+    n_u64(28db77f523047d84), n_u64(32caab7b40c72493),
+    n_u64(3c9ebe0a15c9bebc), n_u64(431d67c49c100d4c),
+    n_u64(4cc5d4becb3e42b6), n_u64(597f299cfc657e2a),
+    n_u64(5fcb6fab3ad6faec), n_u64(6c44198c4a475817)
+};
+
+/* Compile 64 bytes of hash data into SHA384/SHA512 digest value  */
+
+static void sha512_compile(sha512_ctx ctx[1])
+{   sha_64t    v[8];
+    sha_32t    j;
+
+    memcpy(v, ctx->hash, 64);
+
+    for(j = 0; j < 80; j += 16)
+    {
+        h5_cycle( 0, j); h5_cycle( 1, j); h5_cycle( 2, j); h5_cycle( 3, j);
+        h5_cycle( 4, j); h5_cycle( 5, j); h5_cycle( 6, j); h5_cycle( 7, j);
+        h5_cycle( 8, j); h5_cycle( 9, j); h5_cycle(10, j); h5_cycle(11, j);
+        h5_cycle(12, j); h5_cycle(13, j); h5_cycle(14, j); h5_cycle(15, j);
+    }
+
+    ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
+    ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
+}
+
+/* SHA512 hash data in an array of bytes into hash buffer and call the      */
+/* hash_compile function as required.                                       */
+
+/* If FAST_COPY is defined the data to be hashed is processed as an array   */
+/* bytes and compiled into the buffer ctx->wdat[] of 32-bit words in the    */
+/* native byte order.  On little endian machines a 32-bit word byte swap    */
+/* is then performed before this data is compiled into the hash. But when   */
+/* FAST_COPY is not defined the bytes are compiled into the buffer in the   */
+/* big-endian format directly so no later byte order changes are needed.    */
+
+#if defined(FAST_COPY)
+
+void sha512_hash(const unsigned char data[], const unsigned long len, sha512_ctx ctx[1])
+{   sha_32t            free = 128 - (sha_32t)(ctx->count[0] & 127), rlen = len, j;
+    const unsigned char *sp = data;
+    unsigned char       *p = ((unsigned char*)ctx->wdat) + (ctx->count[0] & 127);
+
+    while(rlen >= free)     /* tranfer whole blocks while possible  */
+    {
+        memcpy(p, sp, free);
+        if((ctx->count[0] += free) < free)
+            ++(ctx->count[1]);
+        sp += free; rlen -= free; free = 128; 
+        p = (unsigned char*)ctx->wdat;
+#if defined(SWAP_BYTES)
+        for(j = 0; j < 16; ++j)
+            ctx->wdat[j] = bswap_64(ctx->wdat[j]);
+#endif
+        sha512_compile(ctx);
+    }
+
+    memcpy(p, sp, rlen);    /* transfer partial block               */
+    if((ctx->count[0] += rlen) < rlen)
+        ++(ctx->count[1]);
+    p = (unsigned char*)ctx->wdat;
+    rlen = (sha_32t)(ctx->count[0] & 127);
+    while(rlen & 7)         /* ensure rest of 32-bit word is zero   */
+        *(p + rlen++) = 0;
+}
+
+#elif defined(WORD_COPY)    /* alternative implementations          */
+
+void sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1])
+{   sha_32t    i = 0, cnt, j;
+    sha_64t    *ptr, val;
+
+    ptr = ctx->wdat + ((ctx->count[0] >> 3) & 15);
+    cnt = (ctx->count[0] << 3) & 56;
+    val = (cnt ? *ptr : 0);
+    while(i < len)
+    {   /* assemble values in big-endian format */
+        val |= ((sha_64t)data[i++]) << 56 - cnt;
+        if(!++(ctx->count[0])) ++(ctx->count[1]);
+        if(!(cnt = (cnt + 8) & 56))
+        {   *ptr++ = val; val = 0;
+            if(ptr - ctx->wdat == 16) 
+            {
+                sha512_compile(ctx); 
+                ptr = ctx->wdat;
+            }
+        }
+    }
+    *ptr = val;
+}
+
+#else
+
+void sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1])
+{   sha_32t i = 0, cnt = ctx->count[0], j;
+
+    while(i < len)
+    {   /* assemble values in big-endian format */
+        if((cnt & 7) == 0) ctx->wdat[(cnt >> 3) & 15] = 0;
+        ctx->wdat[(cnt >> 3) & 15] |= (sha_64t)data[i++] << (56 - (8 * (cnt & 7)));
+        if(!++(ctx->count[0])) ++(ctx->count[1]);
+        if((++cnt & 127) == 0) 
+        {
+            sha512_compile(ctx);
+        }
+    }
+}
+
+#endif
+
+/* SHA384/512 Final padding and digest calculation  */
+
+static void sha_end(unsigned char hval[], sha512_ctx ctx[1], const unsigned int hlen)
+{   sha_32t    i, j, cnt = (sha_32t)(ctx->count[0] & 127);
+
+#if defined(SWAP_BYTES)
+        for(i = 0, j = (cnt + 7) >> 3; i < j; ++i)
+            ctx->wdat[i] = bswap_64(ctx->wdat[i]);
+#endif
+
+    /* we are now in big-endian order within the ctx-wdat[] buffer  */
+
+    if(cnt & 7)
+        ctx->wdat[(cnt >> 3) & 15] 
+            |= n_u64(0000000000000080) << (56  - (8 * (cnt & 7)));
+    else
+        ctx->wdat[(cnt >> 3) & 15] = n_u64(8000000000000000);
+
+    if((cnt & 127) > 111)
+    {
+        if((cnt & 127) == 111) ctx->wdat[14] = 0;
+        if((cnt & 127) <= 119) ctx->wdat[15] = 0;
+        sha512_compile(ctx);
+        cnt = 0;
+    }
+    else
+        cnt = (cnt >> 3) + 1;
+
+    while(cnt < 14)
+        ctx->wdat[cnt++] = 0;
+    
+    /* the following 32-bit length fields are assembled in the wrong	*/
+	/* byte	order on little endian machines but this is corrected later	*/
+	/* since they are only picked up as 32-bit word values.				*/
+
+    ctx->wdat[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
+    ctx->wdat[15] = ctx->count[0] << 3;
+
+    sha512_compile(ctx);
+
+    for(i = 0; i < hlen; ++i)
+        hval[i] = (unsigned char)(ctx->hash[i >> 3] >> (56 - 8 * (i & 7)));
+}
+
+#endif
+
+#if defined(SHA_2) || defined(SHA_384)
+
+/* SHA384 initialisation data   */
+
+const sha_64t  i384[80] = 
+{
+    n_u64(cbbb9d5dc1059ed8), n_u64(629a292a367cd507),
+    n_u64(9159015a3070dd17), n_u64(152fecd8f70e5939),
+    n_u64(67332667ffc00b31), n_u64(8eb44a8768581511),
+    n_u64(db0c2e0d64f98fa7), n_u64(47b5481dbefa4fa4)
+};
+
+void sha384_begin(sha384_ctx ctx[1])
+{
+    ctx->count[0] = ctx->count[1] = 0;
+    memcpy(ctx->hash, i384, 64);
+}
+
+void sha384_end(unsigned char hval[], sha384_ctx ctx[1])
+{
+    sha_end(hval, ctx, SHA384_DIGEST_LENGTH);
+}
+
+#endif
+
+#if defined(SHA_2) || defined(SHA_512)
+
+/* SHA512 initialisation data   */
+
+const sha_64t  i512[80] = 
+{
+    n_u64(6a09e667f3bcc908), n_u64(bb67ae8584caa73b),
+    n_u64(3c6ef372fe94f82b), n_u64(a54ff53a5f1d36f1),
+    n_u64(510e527fade682d1), n_u64(9b05688c2b3e6c1f),
+    n_u64(1f83d9abfb41bd6b), n_u64(5be0cd19137e2179)
+};
+
+void sha512_begin(sha512_ctx ctx[1])
+{
+    ctx->count[0] = ctx->count[1] = 0;
+    memcpy(ctx->hash, i512, 64);
+}
+
+void sha512_end(unsigned char hval[], sha512_ctx ctx[1])
+{
+    sha_end(hval, ctx, SHA512_DIGEST_LENGTH);
+}
+
+#endif
+
+#if defined(SHA_2)
+
+#define CTX_256(x)  ((x)->uu->ctx256)
+#define CTX_384(x)  ((x)->uu->ctx512)
+#define CTX_512(x)  ((x)->uu->ctx512)
+
+/* SHA2 initialisation */
+
+int sha2_begin(const unsigned long len, sha2_ctx ctx[1])
+{   unsigned long   l = len;
+    switch(len)
+    {
+        case 256:   l = len >> 3;
+        case  32:   CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;
+                    memcpy(CTX_256(ctx)->hash, i256, 32); break;
+        case 384:   l = len >> 3;
+        case  48:   CTX_384(ctx)->count[0] = CTX_384(ctx)->count[1] = 0;
+                    memcpy(CTX_384(ctx)->hash, i384, 64); break;
+        case 512:   l = len >> 3;
+        case  64:   CTX_512(ctx)->count[0] = CTX_512(ctx)->count[1] = 0;
+                    memcpy(CTX_512(ctx)->hash, i512, 64); break;
+        default:    return SHA2_BAD;
+    }
+    
+    ctx->sha2_len = l; return SHA2_GOOD;
+}
+
+void sha2_hash(const unsigned char data[], const unsigned long len, sha2_ctx ctx[1])
+{
+    switch(ctx->sha2_len)
+    {
+        case 32: sha256_hash(data, len, CTX_256(ctx)); return;
+        case 48: sha384_hash(data, len, CTX_384(ctx)); return;
+        case 64: sha512_hash(data, len, CTX_512(ctx)); return;
+    }
+}
+
+void sha2_end(unsigned char hval[], sha2_ctx ctx[1])
+{
+    switch(ctx->sha2_len)
+    {
+        case 32: sha256_end(hval, CTX_256(ctx)); return;
+        case 48: sha_end(hval, CTX_384(ctx), SHA384_DIGEST_LENGTH); return;
+        case 64: sha_end(hval, CTX_512(ctx), SHA512_DIGEST_LENGTH); return;
+    }
+}
+
+#endif
+
diff --git a/src/libm/sha2.h b/src/libm/sha2.h
new file mode 100644
index 000000000000..3fa627f98d7c
--- /dev/null
+++ b/src/libm/sha2.h
@@ -0,0 +1,128 @@ 
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+Issue Date: 9/10/2002
+*/
+
+#ifndef _SHA2_H
+#define _SHA2_H
+
+#include <limits.h>
+
+/*  Defines for suffixes to 32 and 64 bit unsigned numeric values	*/
+
+#define sfx_lo(x,y) x##y
+#define sfx_hi(x,y) sfx_lo(x,y)
+#define n_u32(p)    sfx_hi(0x##p,s_u32)
+#define n_u64(p)    sfx_hi(0x##p,s_u64)
+
+/* define an unsigned 32-bit type */
+
+#if UINT_MAX == 0xffffffff
+  typedef   unsigned int     sha_32t;
+  #define s_u32    u
+#elif ULONG_MAX == 0xffffffff
+  typedef   unsigned long    sha_32t;
+  #define s_u32   ul
+#else
+#error Please define sha_32t as an unsigned 32 bit type in sha2.h
+#endif
+
+/* define an unsigned 64-bit type */
+
+#if defined( _MSC_VER )
+  typedef unsigned __int64   sha_64t;
+  #define s_u64 ui64
+#elif ULONG_MAX == 0xffffffffffffffff
+  typedef unsigned long      sha_64t;
+  #define s_u64   ul
+#elif ULONG_MAX == 0xffffffff
+  typedef unsigned long long sha_64t;	/* a somewhat dangerous guess */
+  #define s_u64  ull
+#else
+#error Please define sha_64t as an unsigned 64 bit type in sha2.h
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define SHA256_DIGEST_LENGTH    32
+#define SHA384_DIGEST_LENGTH    48
+#define SHA512_DIGEST_LENGTH    64
+
+#define SHA2_DIGEST_LENGTH      SHA256_DIGEST_LENGTH
+#define SHA2_MAX_DIGEST_LENGTH  SHA512_DIGEST_LENGTH
+
+#define SHA2_GOOD   0
+#define SHA2_BAD    1
+
+/* type to hold the SHA256 context  */
+
+typedef struct
+{   sha_32t count[2];
+    sha_32t hash[8];
+    sha_32t wdat[16];
+} sha256_ctx;
+
+typedef struct
+{   sha_64t count[2];
+    sha_64t hash[8];
+    sha_64t wdat[16];
+} sha512_ctx;
+
+typedef sha512_ctx  sha384_ctx;
+
+typedef struct
+{   union
+    {   sha256_ctx  ctx256[1];
+        sha512_ctx  ctx512[1];
+    } uu[1];
+    sha_32t    sha2_len;
+} sha2_ctx;
+
+void sha256_begin(sha256_ctx ctx[1]);
+void sha256_hash(const unsigned char data[], const unsigned long len, sha256_ctx ctx[1]);
+void sha256_end(unsigned char hval[], sha256_ctx ctx[1]);
+
+void sha384_begin(sha384_ctx ctx[1]);
+#define sha384_hash sha512_hash
+void sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
+
+void sha512_begin(sha512_ctx ctx[1]);
+void sha512_hash(const unsigned char data[], const unsigned long len, sha512_ctx ctx[1]);
+void sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
+
+int sha2_begin(const unsigned long len, sha2_ctx ctx[1]);
+void sha2_hash(const unsigned char data[], const unsigned long len, sha2_ctx ctx[1]);
+void sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/src/libm/spDivide.c b/src/libm/spDivide.c
new file mode 100644
index 000000000000..11a8242eb13b
--- /dev/null
+++ b/src/libm/spDivide.c
@@ -0,0 +1,175 @@ 
+/* spDivide.c */
+
+#include "bigdigits.h"
+#define B (MAX_HALF_DIGIT + 1)
+
+static void spMultSub(DIGIT_T uu[2], DIGIT_T qhat, 
+					  DIGIT_T v1, DIGIT_T v0);
+
+
+DIGIT_T spDivide(DIGIT_T *q, DIGIT_T *r, DIGIT_T u[2], DIGIT_T v)
+{	
+#if MCRYPTO_USE_ASM==1	
+	/* use inline assembly for this routine */
+	#ifdef __GNUC__
+	/* gnu c uses AT&T syntax */
+	#else
+	/* for compiler uses Intel syntax, say Intel C++ */
+	#endif	
+#else
+	/*	Computes quotient q = u / v, remainder r = u mod v
+		where u is a double digit
+		and q, v, r are single precision digits.
+		Returns high digit of quotient (max value is 1)
+		Assumes normalised such that v1 >= b/2
+		where b is size of HALF_DIGIT
+		i.e. the most significant bit of v should be one
+
+		In terms of half-digits in Knuth notation:
+		(q2q1q0) = (u4u3u2u1u0) / (v1v0)
+		(r1r0) = (u4u3u2u1u0) mod (v1v0)
+		for m = 2, n = 2 where u4 = 0
+		q2 is either 0 or 1.
+		We set q = (q1q0) and return q2 as "overflow'
+	*/
+	DIGIT_T qhat, rhat, t, v0, v1, u0, u1, u2, u3;
+	DIGIT_T uu[2], q2;
+
+	/* Check for normalisation */
+	if (!(v & HIBITMASK))
+	{
+		*q = *r = 0;
+		return MAX_DIGIT;
+	}
+	
+	/* Split up into half-digits */
+	v0 = LOHALF(v);
+	v1 = HIHALF(v);
+	u0 = LOHALF(u[0]);
+	u1 = HIHALF(u[0]);
+	u2 = LOHALF(u[1]);
+	u3 = HIHALF(u[1]);
+
+	/* Do three rounds of Knuth Algorithm D Vol 2 p272 */
+
+	/*	ROUND 1. Set j = 2 and calculate q2 */
+	/*	Estimate qhat = (u4u3)/v1  = 0 or 1 
+		then set (u4u3u2) -= qhat(v1v0)
+		where u4 = 0.
+	*/
+	qhat = u3 / v1;
+	if (qhat > 0)
+	{
+		rhat = u3 - qhat * v1;
+		t = TOHIGH(rhat) | u2;
+		if (qhat * v0 > t)
+			qhat--;
+	}
+	uu[1] = 0;		/* (u4) */
+	uu[0] = u[1];	/* (u3u2) */
+	if (qhat > 0)
+	{
+		/* (u4u3u2) -= qhat(v1v0) where u4 = 0 */
+		spMultSub(uu, qhat, v1, v0);
+		if (HIHALF(uu[1]) != 0)
+		{	/* Add back */
+			qhat--;
+			uu[0] += v;
+			uu[1] = 0;
+		}
+	}
+	q2 = qhat;
+
+	/*	ROUND 2. Set j = 1 and calculate q1 */
+	/*	Estimate qhat = (u3u2) / v1 
+		then set (u3u2u1) -= qhat(v1v0)
+	*/
+	t = uu[0];
+	qhat = t / v1;
+	rhat = t - qhat * v1;
+	/* Test on v0 */
+	t = TOHIGH(rhat) | u1;
+	if ((qhat == B) || (qhat * v0 > t))
+	{
+		qhat--;
+		rhat += v1;
+		t = TOHIGH(rhat) | u1;
+		if ((rhat < B) && (qhat * v0 > t))
+			qhat--;
+	}
+
+	/*	Multiply and subtract 
+		(u3u2u1)' = (u3u2u1) - qhat(v1v0)	
+	*/
+	uu[1] = HIHALF(uu[0]);	/* (0u3) */
+	uu[0] = TOHIGH(LOHALF(uu[0])) | u1;	/* (u2u1) */
+	spMultSub(uu, qhat, v1, v0);
+	if (HIHALF(uu[1]) != 0)
+	{	/* Add back */
+		qhat--;
+		uu[0] += v;
+		uu[1] = 0;
+	}
+
+	/* q1 = qhat */
+	*q = TOHIGH(qhat);
+
+	/* ROUND 3. Set j = 0 and calculate q0 */
+	/*	Estimate qhat = (u2u1) / v1
+		then set (u2u1u0) -= qhat(v1v0)
+	*/
+	t = uu[0];
+	qhat = t / v1;
+	rhat = t - qhat * v1;
+	/* Test on v0 */
+	t = TOHIGH(rhat) | u0;
+	if ((qhat == B) || (qhat * v0 > t))
+	{
+		qhat--;
+		rhat += v1;
+		t = TOHIGH(rhat) | u0;
+		if ((rhat < B) && (qhat * v0 > t))
+			qhat--;
+	}
+
+	/*	Multiply and subtract 
+		(u2u1u0)" = (u2u1u0)' - qhat(v1v0)
+	*/
+	uu[1] = HIHALF(uu[0]);	/* (0u2) */
+	uu[0] = TOHIGH(LOHALF(uu[0])) | u0;	/* (u1u0) */
+	spMultSub(uu, qhat, v1, v0);
+	if (HIHALF(uu[1]) != 0)
+	{	/* Add back */
+		qhat--;
+		uu[0] += v;
+		uu[1] = 0;
+	}
+
+	/* q0 = qhat */
+	*q |= LOHALF(qhat);
+
+	/* Remainder is in (u1u0) i.e. uu[0] */
+	*r = uu[0];
+	
+	return q2;
+#endif
+}
+
+static void spMultSub(DIGIT_T uu[2], DIGIT_T qhat, 
+					  DIGIT_T v1, DIGIT_T v0)
+{
+	/*	Compute uu = uu - q(v1v0) 
+		where uu = u3u2u1u0, u3 = 0
+		and u_n, v_n are all half-digits
+		even though v1, v2 are passed as full digits.
+	*/
+	DIGIT_T p0, p1, t;
+
+	p0 = qhat * v0;
+	p1 = qhat * v1;
+	t = p0 + TOHIGH(LOHALF(p1));
+	uu[0] -= t;
+	if (uu[0] > MAX_DIGIT - t)
+		uu[1]--;	/* Borrow */
+	uu[1] -= HIHALF(p1);
+}
diff --git a/src/libm/spGcd.c b/src/libm/spGcd.c
new file mode 100644
index 000000000000..0e8c1a4ef40b
--- /dev/null
+++ b/src/libm/spGcd.c
@@ -0,0 +1,24 @@ 
+/* spGcd.c */
+
+#include "bigdigits.h"
+
+DIGIT_T spGcd(DIGIT_T x, DIGIT_T y)
+{	/*	Returns gcd(x, y) */
+
+	/* Ref: Schneier 2nd ed, p245 */
+	
+	DIGIT_T g;
+
+	if (x + y == 0)
+		return 0;	/* Error */
+
+	g = y;
+	while (x > 0)
+	{
+		g = x;
+		x = y % x;
+		y = g;
+	}
+	
+	return g;
+}
diff --git a/src/libm/spIsPrime.c b/src/libm/spIsPrime.c
new file mode 100644
index 000000000000..3e85592869c4
--- /dev/null
+++ b/src/libm/spIsPrime.c
@@ -0,0 +1,89 @@ 
+/* spIsPrime.c */
+
+#include <assert.h>
+#include "bigdigits.h"
+
+static DIGIT_T SMALL_PRIMES[] = { 2, 3, 5, 7, 11, 13, 17, 19 };
+#define N_SMALL_PRIMES sizeof(SMALL_PRIMES)/sizeof(DIGIT_T)
+
+int spIsPrime(DIGIT_T w, UINT t)
+{	/*	Returns true if w is a probable prime 
+		Carries out t iterations
+		(Use t = 50 for DSS Standard) 
+	*/
+	/*	Uses Rabin-Miller Probabilistic Primality Test,
+		Ref: FIPS-186-2 Appendix 2.
+		Also Schneier 2nd ed p 260 & Knuth Vol 2, p 379.
+	*/
+	/*	Rabin-Miller Probabilistic Primality Test,
+		from FIPS-186-2 Appendix 2.
+		Also Schneier 2nd ed p 260 & Knuth Vol 2, p 379.
+	*/
+
+	UINT i, j;
+	DIGIT_T m, a, b, z;
+	int failed;
+
+	/*	First check for small primes */
+	for (i = 0; i < N_SMALL_PRIMES; i++)
+	{
+		if (w % SMALL_PRIMES[i] == 0)
+			return 0;	/* Failed */
+	}
+
+	/*	Now do Rabin-Miller  */
+	/*	Step 2. Find a and m where w = 1 + (2^a)m
+		m is odd and 2^a is largest power of 2 dividing w - 1 */
+	m = w - 1;
+	for (a = 0; ISEVEN(m); a++)
+		m >>= 1;	/* Divide by 2 until m is odd */
+
+	/*
+	assert((1 << a) * m + 1 == w);
+	*/
+
+	for (i = 0; i < t; i++)
+	{
+		failed = 1;	/* Assume fail unless passed in loop */
+		/* Step 3. Generate a random integer 1 < b < w */
+		b = spPseudoRand(2, w - 1);
+
+		/*
+		assert(1 < b && b < w);
+		*/
+
+		/* Step 4. Set j = 0 and z = b^m mod w */
+		j = 0;
+		spModExp(&z, b, m, w);
+		do
+		{
+			/* Step 5. If j = 0 and z = 1, or if z = w - 1 */
+			if ((j == 0 && z == 1) || (z == w - 1))
+			{	/* Passes on this loop  - go to Step 9 */
+				failed = 0;
+				break;
+			}
+
+			/* Step 6. If j > 0 and z = 1 */
+			if (j > 0 && z == 1)
+			{	/* Fails - go to Step 8 */
+				failed = 1;
+				break;
+			}
+
+			/* Step 7. j = j + 1. If j < a set z = z^2 mod w */
+			j++;
+			if (j < a)
+				spModMult(&z, z, z, w);
+			/* Loop: if j < a go to Step 5 */
+		} while (j < a);
+
+		if (failed)
+		{	/* Step 8. Not a prime - stop */
+			return 0;
+		}
+	}	/* Step 9. Go to Step 3 until i >= n */
+	/* If got here, probably prime => success */
+	
+	return 1;
+}
diff --git a/src/libm/spModExp.c b/src/libm/spModExp.c
new file mode 100644
index 000000000000..07683304f798
--- /dev/null
+++ b/src/libm/spModExp.c
@@ -0,0 +1,64 @@ 
+/* spModExp.c */
+
+#include "bigdigits.h"
+
+static int spModExpK(DIGIT_T *exp, DIGIT_T x, 
+			DIGIT_T n, DIGIT_T d);
+static int spModExpB(DIGIT_T *exp, DIGIT_T x, 
+			DIGIT_T n, DIGIT_T d);
+
+int spModExp(DIGIT_T *exp, DIGIT_T x, 
+			DIGIT_T n, DIGIT_T d)
+{
+	return spModExpB(exp, x, n, d);
+}
+
+static int spModExpK(DIGIT_T *exp, DIGIT_T x, 
+			DIGIT_T n, DIGIT_T d)
+{	/*	Computes exp = x^n mod d */
+	/*	Ref: Knuth Vol 2 Ch 4.6.3 p 462 Algorithm A
+	*/
+	DIGIT_T y = 1;		/* Step A1. Initialise */
+
+	while (n > 0)
+	{							/* Step A2. Halve N */
+		if (n & 0x1)			/* If odd */
+			spModMult(&y, y, x, d);	/*   Step A3. Multiply Y by Z */	
+		
+		n >>= 1;					/* Halve N */
+		if (n > 0)				/* Step A4. N = 0? Y is answer */
+			spModMult(&x, x, x, d);	/* Step A5. Square Z */
+	}
+
+	*exp = y;
+	return 0;
+}
+
+static int spModExpB(DIGIT_T *exp, DIGIT_T x, 
+			DIGIT_T e, DIGIT_T m)
+{	/*	Computes exp = x^e mod m */
+	/*	Binary left-to-right method
+	*/
+	DIGIT_T mask;
+	DIGIT_T y;	/* Temp variable */
+
+	/* Find most significant bit in e */
+	for (mask = HIBITMASK; mask > 0; mask >>= 1)
+	{
+		if (e & mask)
+			break;
+	}
+
+	y = x;
+	/* For j = k-2 downto 0 step -1 */
+	for (mask >>= 1; mask > 0; mask >>= 1)
+	{
+		spModMult(&y, y, y, m);		/* Square */
+		if (e & mask)
+			spModMult(&y, y, x, m);	/* Multiply */
+	}
+
+	*exp = y;
+	
+	return 0;
+}
diff --git a/src/libm/spModInv.c b/src/libm/spModInv.c
new file mode 100644
index 000000000000..0a03a8434176
--- /dev/null
+++ b/src/libm/spModInv.c
@@ -0,0 +1,41 @@ 
+/* spModInv.c */
+
+#include "bigdigits.h"
+
+int spModInv(DIGIT_T *inv, DIGIT_T u, DIGIT_T v)
+{	/*	Computes inv = u^(-1) mod v */
+	/*	Ref: Knuth Algorithm X Vol 2 p 342 
+		ignoring u2, v2, t2
+		and avoiding negative numbers
+	*/
+	DIGIT_T u1, u3, v1, v3, t1, t3, q, w;
+	int bIterations = 1;
+	
+	/* Step X1. Initialise */
+	u1 = 1;
+	u3 = u;
+	v1 = 0;
+	v3 = v;
+
+	while (v3 != 0)	/* Step X2. */
+	{	/* Step X3. */
+		q = u3 / v3;	/* Divide and */
+		t3 = u3 % v3;
+		w = q * v1;		/* "Subtract" */
+		t1 = u1 + w;
+		/* Swap */
+		u1 = v1;
+		v1 = t1;
+		u3 = v3;
+		v3 = t3;
+		bIterations = -bIterations;
+	}
+
+	if (bIterations < 0)
+		*inv = v - u1;
+	else
+		*inv = u1;
+
+	return 0;
+}
+
diff --git a/src/libm/spModMult.c b/src/libm/spModMult.c
new file mode 100644
index 000000000000..16d583a7b092
--- /dev/null
+++ b/src/libm/spModMult.c
@@ -0,0 +1,17 @@ 
+/* spModMult.c */
+
+#include "bigdigits.h"
+
+int spModMult(DIGIT_T *a, DIGIT_T x, DIGIT_T y, DIGIT_T m)
+{	/*	Computes a = (x * y) mod m */
+	
+	/* Calc p[2] = x * y */
+	DIGIT_T p[2];
+	spMultiply(p, x, y);
+
+	/* Then modulo */
+	*a = mpShortMod(p, m, 2);
+	
+	return 0;
+}
+
diff --git a/src/libm/spMultiply.c b/src/libm/spMultiply.c
new file mode 100644
index 000000000000..51d5e3ebd82a
--- /dev/null
+++ b/src/libm/spMultiply.c
@@ -0,0 +1,76 @@ 
+/* spMultiply.c */
+
+#include "bigdigits.h"
+
+int spMultiply(DIGIT_T p[2], DIGIT_T x, DIGIT_T y)
+{	
+#if MCRYPTO_USE_ASM==1
+	/* use inline assembly for this routine */
+	#ifdef __GNUC__
+	/* gnu c uses AT&T syntax */
+	#else
+	/* for compiler uses Intel syntax, say Intel C++ */
+	#endif	
+
+#else	
+	/*	Computes p = x * y */
+	/*	Ref: Arbitrary Precision Computation
+	http://numbers.computation.free.fr/Constants/constants.html
+
+         high    p1                p0     low
+        +--------+--------+--------+--------+
+        |      x1*y1      |      x0*y0      |
+        +--------+--------+--------+--------+
+               +-+--------+--------+
+               |1| (x0*y1 + x1*y1) |
+               +-+--------+--------+
+                ^carry from adding (x0*y1+x1*y1) together
+                        +-+
+                        |1|< carry from adding LOHALF t
+                        +-+  to high half of p0
+	*/
+	DIGIT_T x0, y0, x1, y1;
+	DIGIT_T t, u, carry;
+
+	/*	Split each x,y into two halves
+		x = x0 + B*x1
+		y = y0 + B*y1
+		where B = 2^16, half the digit size
+		Product is
+		xy = x0y0 + B(x0y1 + x1y0) + B^2(x1y1)
+	*/
+
+	x0 = LOHALF(x);
+	x1 = HIHALF(x);
+	y0 = LOHALF(y);
+	y1 = HIHALF(y);
+
+	/* Calc low part - no carry */
+	p[0] = x0 * y0;
+
+	/* Calc middle part */
+	t = x0 * y1;
+	u = x1 * y0;
+	t += u;
+	if (t < u)
+		carry = 1;
+	else
+		carry = 0;
+
+	/*	This carry will go to high half of p[1]
+		+ high half of t into low half of p[1] */
+	carry = TOHIGH(carry) + HIHALF(t);
+
+	/* Add low half of t to high half of p[0] */
+	t = TOHIGH(t);
+	p[0] += t;
+	if (p[0] < t)
+		carry++;
+
+	p[1] = x1 * y1;
+	p[1] += carry;
+#endif
+
+	return 0;
+}
+
diff --git a/src/libm/spPseudoRand.c b/src/libm/spPseudoRand.c
new file mode 100644
index 000000000000..6c72b11f515d
--- /dev/null
+++ b/src/libm/spPseudoRand.c
@@ -0,0 +1,30 @@ 
+/* spPseudoRand */
+
+#include <stdlib.h>
+#include <time.h>
+#include "bigdigits.h"
+
+DIGIT_T spPseudoRand(DIGIT_T lower, DIGIT_T upper)
+{	
+	/*	Returns a pseudo-random digit.
+		Handles own seeding using time
+		NOT for cryptographically-secure random numbers.
+	*/
+	static unsigned seeded = 0;
+	UINT i;
+	double f;
+
+	if (!seeded)
+	{
+		/* seed with system time */
+		srand((unsigned)time(NULL));
+		/* Throw away a random few to avoid similar starts */
+		i = rand() & 0xFF;
+		while (i--)
+			rand();
+		seeded = 1;
+	}
+	f = (double)rand() / RAND_MAX * upper;
+	
+	return (lower + (DIGIT_T)f);
+}