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@xxxxxxxxxx> --- 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 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@xxxxxxxxx */ +/* 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@xxxxxxxxx */ +/* 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@xxxxxxxxx */ +/* 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@xxxxxxxxx */ +/* 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@xxxxxxxxx */ +/* 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@xxxxxxxxxxxxx>, 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@xxxxxxxxxxxx> 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@xxxxxxxxxxxxx>, 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); +} -- 1.8.1.5 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html