From d6071c6267b9bba40ba34c0d8d95d766853ea31c Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Sun, 1 Jun 2003 18:55:11 +0000 Subject: [PATCH] added libtomcrypt-0.84 --- aes.c | 4 + ampi.c | 55 - blowfish.c | 4 + cast5.c | 4 + changes | 11 + config.pl | 3 +- crypt.pdf | Bin 354942 -> 356268 bytes crypt.tex | 47 +- demos/test.c | 182 +- des.c | 8 + dh.c | 48 +- dh_sys.c | 19 +- ecc.c | 166 +- ecc_sys.c | 14 +- hmac.c | 6 +- makefile | 11 +- makefile.msvc | 4 +- md2.c | 4 + md4.c | 4 + md5.c | 4 + mpi.c | 13200 ++++++++++++++++++++++++--------------------- mycrypt.h | 4 +- mycrypt_custom.h | 6 +- noekeon.c | 6 +- prime.c | 147 +- rc2.c | 4 + rc5.c | 4 + rc6.c | 4 + rsa.c | 87 +- rsa_sys.c | 5 +- safer+.c | 4 + safer.c | 16 +- serpent.c | 4 + sha1.c | 4 + sha256.c | 8 +- sha384.c | 4 + sha512.c | 4 + tiger.c | 4 + tommath.h | 141 +- twofish.c | 4 + xtea.c | 4 + 41 files changed, 7688 insertions(+), 6574 deletions(-) delete mode 100644 ampi.c diff --git a/aes.c b/aes.c index c1bf568..4d63992 100644 --- a/aes.c +++ b/aes.c @@ -327,6 +327,9 @@ void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ int rijndael_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else int errno; static const struct { int keylen; @@ -377,6 +380,7 @@ int rijndael_test(void) } } return CRYPT_OK; + #endif } int rijndael_keysize(int *desired_keysize) diff --git a/ampi.c b/ampi.c deleted file mode 100644 index 2d015ca..0000000 --- a/ampi.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Code submitted by Svante Seleborg, cleaned up by Tom St Denis */ - -#include "mycrypt.h" -#include - -#ifdef MPI - -mp_err mp_init_multi(mp_int *mp, ...) -{ - mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ - int n = 0; /* Number of ok inits */ - mp_int* cur_arg = mp; - va_list args; - - va_start(args, mp); /* init args to next argument from caller */ - while (cur_arg != NULL) { - if (mp_init(cur_arg) != MP_OKAY) { - /* Oops - error! Back-track and mp_clear what we already - succeeded in init-ing, then return error. - */ - va_list clean_args; - cur_arg = mp; - va_start(clean_args, mp); - while (n--) { - mp_clear(cur_arg); - cur_arg = va_arg(clean_args, mp_int*); - } - va_end(clean_args); - res = MP_MEM; - break; - } - n++; - cur_arg = va_arg(args, mp_int*); - } - va_end(args); - return res; /* Assumed ok, if error flagged above. */ -} - -/* - Clear all arguments given, ended by a NULL marker. -*/ -void mp_clear_multi(mp_int *mp, ...) -{ - mp_int* next_mp = mp; - va_list args; - va_start(args, mp); - while (next_mp != NULL) { - mp_clear(next_mp); - next_mp = va_arg(args, mp_int*); - } - va_end(args); -} - -#endif - diff --git a/blowfish.c b/blowfish.c index db8fc1a..3b27e39 100644 --- a/blowfish.c +++ b/blowfish.c @@ -436,6 +436,9 @@ void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ int blowfish_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else int err; symmetric_key key; static const struct { @@ -476,6 +479,7 @@ int blowfish_test(void) } } return CRYPT_OK; + #endif } int blowfish_keysize(int *desired_keysize) diff --git a/cast5.c b/cast5.c index 77b6262..0969aaf 100644 --- a/cast5.c +++ b/cast5.c @@ -552,6 +552,9 @@ void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key int cast5_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[16]; @@ -590,6 +593,7 @@ int cast5_test(void) } return CRYPT_OK; + #endif } int cast5_keysize(int *desired_keysize) diff --git a/changes b/changes index 4c7cdef..e2cf92d 100644 --- a/changes +++ b/changes @@ -1,3 +1,14 @@ +Jun 1st, 2003 +v0.84 -- Removed a 4KB buffer from rsa_decrypt_key that wasn't being used no more + -- Fixed another potential buffer problem. Not an overflow but could cause the + PK import routines to read past the end of the buffer. + -- Optimized the ECC mulmod more by removing a if condition that will always be false + -- Optimized prime.c to not include a 2nd prime table, removed code from is_prime calls prime + test from LibTomMath now + -- Added LTC_TEST define which when defined will enable the test vector routines [see mycrypt_custom.h] + -- Removed ampi.o from the depends cuz it ain't no not working in *nix with it [routines are in mpi.c now]. + + Mar 29th, 2003 v0.83 -- Optimized the ecc_mulmod, it's faster and takes less heap/stack space -- Fixed a free memory error in ecc_mulmod and del_point which would try to free NULL diff --git a/config.pl b/config.pl index 4f68282..cee3453 100644 --- a/config.pl +++ b/config.pl @@ -24,6 +24,7 @@ "SMALL_CODE,Use small code where possible (slower code),y", "NO_FILE,Avoid file I/O calls,n", "CLEAN_STACK,Clean the stack within functions,n", + "LTC_TEST,Include Test Vector Routines,y", "BLOWFISH,Include Blowfish block cipher,y", "RC2,Include RC2 block cipher,y", @@ -144,7 +145,7 @@ for (@settings) { # output objects print OUT "\ndefault: library\n\n"; -print OUT "OBJECTS = keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o\n\n"; +print OUT "OBJECTS = keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o mpi.o prime.o twofish.o packet.o hmac.o strings.o\n\n"; # some depends print OUT "rsa.o: rsa_sys.c\ndh.o: dh_sys.c\necc.o: ecc_sys.c\n\n"; diff --git a/crypt.pdf b/crypt.pdf index a132eb01a44d49e5bfd59560e0ce55025bef67ce..0fe991a16c3ee45f2241fd38097fc5262dc520c1 100644 GIT binary patch delta 128981 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˽(QPIahNx0THf$ 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 z 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%0AP2thH(B{ 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 RZB81f!W`n_YJ1c<{s&RlN8JDb diff --git a/crypt.tex b/crypt.tex index e3b23ef..3b64457 100644 --- a/crypt.tex +++ b/crypt.tex @@ -48,7 +48,7 @@ \def\gap{\vspace{0.5ex}} \makeindex \begin{document} -\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.83} +\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.84} \author{Tom St Denis \\ Algonquin College \\ \\ @@ -64,8 +64,8 @@ Canada \newpage \tableofcontents \chapter{Introduction} -\section{What is the Libtomcrypt?} -Libtomcrypt is a portable ANSI C cryptographic library that supports symmetric ciphers, one-way hashes, +\section{What is the LibTomCrypt?} +LibTomCrypt is a portable ANSI C cryptographic library that supports symmetric ciphers, one-way hashes, pseudo-random number generators, public key cryptography (via RSA,DH or ECC/DH) and a plethora of support routines. It is designed to compile out of the box with the GNU C Compiler (GCC) version 2.95.3 (and higher) and with MSVC version 6 in win32. @@ -932,12 +932,12 @@ int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen); \end{verbatim} -All three functions return {\bf CRYPT\_OK} on success, otherwise they return an error code. The ``hash'' parameter is -the location in the descriptor table of the hash. The ``*outlen'' variable is used to keep track of the output size. You +The ``hash'' parameter is the location in the descriptor table of the hash (\textit{e.g. the return of find\_hash()}). +The ``*outlen'' variable is used to keep track of the output size. You must set it to the size of your output buffer before calling the functions. When they complete succesfully they store the length of the message digest back in it. The functions are otherwise straightforward. The ``hash\_filehandle'' -function assumes that ``in'' is an file handle opened in binary mode. It will not reset the file position after -hashing the content. +function assumes that ``in'' is an file handle opened in binary mode. It will hash to the end of file and not reset +the file position when finished. To perform the above hash with md5 the following code could be used: \begin{small} @@ -993,7 +993,7 @@ int unregister_hash(const struct _hash_descriptor *hash); \end{verbatim} \subsection{Notice} -It is highly recommended that you not use the MD4 or MD5 hashes for the purposes of digital signatures or authentication codes. +It is highly recommended that you \textbf{not} use the MD4 or MD5 hashes for the purposes of digital signatures or authentication codes. These hashes are provided for completeness and they still can be used for the purposes of password hashing or one-way accumulators (e.g. Yarrow). @@ -1039,16 +1039,16 @@ int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, unsigned char *dst, unsigned long *dstlen); \end{verbatim} This will produce an HMAC code for the array of octets in ``data'' of length ``len''. The index into the hash descriptor -table must be provided in ``hash'' it uses the key from ``key'' with a key length of ``keylen''. -The result is stored in the array of octets ``dst'' and the length in ``dstlen''. Similarly for files there is the -following function: +table must be provided in ``hash''. It uses the key from ``key'' with a key length of ``keylen''. +The result is stored in the array of octets ``dst'' and the length in ``dstlen''. The value of ``dstlen'' must be set +to the size of the destination buffer before calling this function. Similarly for files there is the following function: \begin{verbatim} int hmac_file(int hash, const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *dst, unsigned long *dstlen); \end{verbatim} -``hash'' is the index into the hash descriptor table of the hash you want to use. ``fname'' is the filename to process. ``key'' -is the array of octets to use as the key. ``keylen'' is the length of the key. ``dst'' is the array of octets where the +``hash'' is the index into the hash descriptor table of the hash you want to use. ``fname'' is the filename to process. +``key'' is the array of octets to use as the key of length ``keylen''. ``dst'' is the array of octets where the result should be stored. To test if the HMAC code is working there is the following function: @@ -1378,7 +1378,7 @@ int rsa_make_key(prng_state *prng, Where ``wprng'' is the index into the PRNG descriptor array. ``size'' is the size in bytes of the RSA modulus desired. ``e'' is the encryption exponent desired, typical values are 3, 17, 257 and 65537. I suggest you stick with 65537 since its big enough to prevent trivial math attacks and not super slow. ``key'' is where the key is placed. All keys must be at -least 128 bytes and no more than 512 bytes in size (that is from 1024 to 4096 bits). +least 128 bytes and no more than 512 bytes in size (\textit{that is from 1024 to 4096 bits}). Note that the ``rsa\_make\_key()'' function allocates memory at runtime when you make the key. Make sure to call ``rsa\_free()'' (see below) when you are finished with the key. If ``rsa\_make\_key()'' fails it will automatically @@ -1408,22 +1408,21 @@ recipient who can RSA decrypt it and symmetrically decrypt the message. int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, unsigned char *outkey, unsigned long *outlen, prng_state *prng, int wprng, rsa_key *key); +\end{verbatim} +This function is used to RSA encrypt a symmetric to share with another user. The symmetric key and its length are +passed as ``inkey'' and ``inlen'' respectively. The symmetric key is limited to a range of 8 to 32 bytes +(\textit{64 to 256 bits}). The RSA encrypted packet is stored in ``outkey'' and will be of length ``outlen'' bytes. The +value of ``outlen'' must be originally set to the size of the output buffer. +\begin{verbatim} int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *outkey, unsigned long *keylen, rsa_key *key); \end{verbatim} -The ``rsa\_encrypt\_key()'' function accepts a symmetric key (limited to 32 bytes) as input in ``inkey''. ``inlen'' -is the size of the input key in bytes. The function will then ``rsa\_pad()'' the key and encrypt it using the RSA -algorithm. It will store the result in ``outkey'' along with the length in ``outlen''. - -The ``rsa\_decrypt\_key()'' function performs the opposite. The ``in'' variable is where the RSA packet of length -``inlen'' goes and it will store the original symmetric key in the ``outkey'' variable along with its length in -``keylen''. - -Similarly to sign or verify a hash of a message the following two messages are provided. The idea is to hash your -message then use these functions to RSA sign the hash. +This function will decrypt an RSA packet to retrieve the original symmetric key encrypted with rsa\_encrypt\_key(). +Similarly to sign or verify a hash of a message the following two messages are provided. The idea is to hash your message +then use these functions to RSA sign the hash. \begin{verbatim} int rsa_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, diff --git a/demos/test.c b/demos/test.c index d60051f..dcdceaf 100644 --- a/demos/test.c +++ b/demos/test.c @@ -14,21 +14,21 @@ int errnum; int null_setup (const unsigned char *key, int keylen, int num_rounds, - symmetric_key * skey) + symmetric_key * skey) { return CRYPT_OK; } void null_ecb_encrypt (const unsigned char *pt, unsigned char *ct, - symmetric_key * key) + symmetric_key * key) { memcpy (ct, pt, 8); } void null_ecb_decrypt (const unsigned char *ct, unsigned char *pt, - symmetric_key * key) + symmetric_key * key) { memcpy (pt, ct, 8); } @@ -156,7 +156,7 @@ cbc_tests (void) /* now lets start a cbc session */ if ((errnum = cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, - &cbc)) != CRYPT_OK) { + &cbc)) != CRYPT_OK) { printf ("CBC Setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -179,7 +179,7 @@ cbc_tests (void) /* now lets start a cbc session */ if ((errnum = cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, - &cbc)) != CRYPT_OK) { + &cbc)) != CRYPT_OK) { printf ("CBC Setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -201,12 +201,12 @@ cbc_tests (void) /* lets actually check the bytes */ memset (IV, 0, 8); - IV[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ + IV[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ memset (blk, 0, 32); - blk[8] = 0xFF; /* BLK = 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 */ + blk[8] = 0xFF; /* BLK = 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 */ cbc_start (find_cipher ("memcpy()"), IV, key, 8, 0, &cbc); - cbc_encrypt (blk, ct, &cbc); /* expect: FF 00 00 00 00 00 00 00 */ - cbc_encrypt (blk + 8, ct + 8, &cbc); /* expect: 00 00 00 00 00 00 00 00 */ + cbc_encrypt (blk, ct, &cbc); /* expect: FF 00 00 00 00 00 00 00 */ + cbc_encrypt (blk + 8, ct + 8, &cbc); /* expect: 00 00 00 00 00 00 00 00 */ if (memcmp (ct, test, 16)) { printf ("CBC failed logical testing.\n"); for (x = 0; x < 16; x++) @@ -309,7 +309,7 @@ cfb_tests (void) /* now lets start a cfb session */ if ((errnum = cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, - &cfb)) != CRYPT_OK) { + &cfb)) != CRYPT_OK) { printf ("CFB setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -332,7 +332,7 @@ cfb_tests (void) /* now lets start a cfb session */ if ((errnum = cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, - &cfb)) != CRYPT_OK) { + &cfb)) != CRYPT_OK) { printf ("CFB Setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -380,7 +380,7 @@ ctr_tests (void) /* now lets start a ctr session */ if ((errnum = ctr_start (find_cipher ("xtea"), count, key, 16, 0, - &ctr)) != CRYPT_OK) { + &ctr)) != CRYPT_OK) { printf ("CTR Setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -403,7 +403,7 @@ ctr_tests (void) /* now lets start a cbc session */ if ((errnum = ctr_start (find_cipher ("xtea"), count, key, 16, 0, - &ctr)) != CRYPT_OK) { + &ctr)) != CRYPT_OK) { printf ("CTR Setup: %s\n", error_to_string (errnum)); exit (-1); } @@ -426,12 +426,12 @@ ctr_tests (void) /* lets actually check the bytes */ memset (count, 0, 8); - count[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ + count[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ memset (blk, 0, 32); - blk[9] = 2; /* BLK = 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 */ + blk[9] = 2; /* BLK = 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 */ ctr_start (find_cipher ("memcpy()"), count, key, 8, 0, &ctr); - ctr_encrypt (blk, ct, 8, &ctr); /* expect: FF 00 00 00 00 00 00 00 */ - ctr_encrypt (blk + 8, ct + 8, 8, &ctr); /* expect: 00 03 00 00 00 00 00 00 */ + ctr_encrypt (blk, ct, 8, &ctr); /* expect: FF 00 00 00 00 00 00 00 */ + ctr_encrypt (blk + 8, ct + 8, 8, &ctr); /* expect: 00 03 00 00 00 00 00 00 */ if (memcmp (ct, test, 16)) { printf ("CTR failed logical testing.\n"); for (x = 0; x < 16; x++) @@ -520,7 +520,7 @@ rsa_test (void) /* encrypt a short 8 byte string */ if ((errnum = rsa_make_key (&prng, find_prng ("yarrow"), 1024 / 8, 65537, - &key)) != CRYPT_OK) { + &key)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -555,7 +555,7 @@ rsa_test (void) y = sizeof (out); if ((errnum = rsa_encrypt_key (in, 16, out, &y, &prng, find_prng ("yarrow"), - &key)) != CRYPT_OK) { + &key)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -614,47 +614,47 @@ rsa_test (void) for (z = 1024; z <= limit; z += 512) { t = XCLOCK (); for (tt = 0; tt < 3; tt++) { - if ((errnum = - rsa_make_key (&prng, find_prng ("yarrow"), z / 8, 65537, - &key)) != CRYPT_OK) { - printf ("Error: %s\n", error_to_string (errnum)); - exit (-1); - } - if (tt < 2) - rsa_free (&key); + if ((errnum = + rsa_make_key (&prng, find_prng ("yarrow"), z / 8, 65537, + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + if (tt < 2) + rsa_free (&key); } t = XCLOCK () - t; printf ("Took %.0f ms to make a %ld-bit RSA key.\n", - 1000.0 * (((double) t / 3.0) / (double) XCLOCKS_PER_SEC), z); + 1000.0 * (((double) t / 3.0) / (double) XCLOCKS_PER_SEC), z); /* time encryption */ t = XCLOCK (); - for (tt = 0; tt < 100; tt++) { - y = sizeof (in); - if ((errnum = - rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { - printf ("Error: %s\n", error_to_string (errnum)); - exit (-1); - } + for (tt = 0; tt < 20; tt++) { + y = sizeof (in); + if ((errnum = + rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } } t = XCLOCK () - t; printf ("Took %.0f ms to encrypt with a %ld-bit RSA key.\n", - 1000.0 * (((double) t / 100.0) / (double) XCLOCKS_PER_SEC), z); + 1000.0 * (((double) t / 20.0) / (double) XCLOCKS_PER_SEC), z); /* time decryption */ t = XCLOCK (); - for (tt = 0; tt < 100; tt++) { - x = sizeof (out); - if ((errnum = - rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { - printf ("Error: %s\n", error_to_string (errnum)); - exit (-1); - } + for (tt = 0; tt < 20; tt++) { + x = sizeof (out); + if ((errnum = + rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } } t = XCLOCK () - t; printf ("Took %.0f ms to decrypt with a %ld-bit RSA key.\n", - 1000.0 * (((double) t / 100.0) / (double) XCLOCKS_PER_SEC), z); + 1000.0 * (((double) t / 20.0) / (double) XCLOCKS_PER_SEC), z); rsa_free (&key); } } @@ -765,9 +765,9 @@ time_hash (void) } t1 = XCLOCK () - t1; printf ("%-20s: Hash at %5.2f Mbit/sec\n", hash_descriptor[x].name, - ((8.0 * 4096.0) * - ((double) y / ((double) t1 / (double) XCLOCKS_PER_SEC))) / - 1000000.0); + ((8.0 * 4096.0) * + ((double) y / ((double) t1 / (double) XCLOCKS_PER_SEC))) / + 1000000.0); } } @@ -783,7 +783,7 @@ time_ecb (void) printf ("ECB Time Trials for the Symmetric Ciphers:\n"); for (x = 0; cipher_descriptor[x].name != NULL; x++) { cipher_descriptor[x].setup (key, cipher_descriptor[x].min_key_length, 0, - &skey); + &skey); #define DO1 func(pt,pt,&skey); #define DO2 DO1 DO1 @@ -816,9 +816,9 @@ time_ecb (void) ("%-20s: Encrypt at %5.2f Mbit/sec and Decrypt at %5.2f Mbit/sec\n", cipher_descriptor[x].name, ((8.0 * (double) cipher_descriptor[x].block_length) * - ((double) y1 / ((double) t1 / (double) XCLOCKS_PER_SEC))) / 1000000.0, + ((double) y1 / ((double) t1 / (double) XCLOCKS_PER_SEC))) / 1000000.0, ((8.0 * (double) cipher_descriptor[x].block_length) * - ((double) y2 / ((double) t2 / (double) XCLOCKS_PER_SEC))) / + ((double) y2 / ((double) t2 / (double) XCLOCKS_PER_SEC))) / 1000000.0); #undef DO256 @@ -843,7 +843,7 @@ dh_tests (void) dh_key usera, userb; clock_t t1; -/* if ((errnum = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errnum)); */ +/* if ((errnum = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errnum)); */ dh_sizes (&low, &high); printf ("DH Keys from %d to %d supported.\n", low * 8, high * 8); @@ -921,12 +921,12 @@ dh_tests (void) for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { t1 = XCLOCK (); for (tt = 0; tt < 5; tt++) { - dh_make_key (&prng, find_prng ("yarrow"), sizes[ii], &usera); - dh_free (&usera); + dh_make_key (&prng, find_prng ("yarrow"), sizes[ii], &usera); + dh_free (&usera); } t1 = XCLOCK () - t1; printf ("Make dh-%d key took %f msec\n", sizes[ii] * 8, - 1000.0 * (((double) t1 / 5.0) / (double) XCLOCKS_PER_SEC)); + 1000.0 * (((double) t1 / 5.0) / (double) XCLOCKS_PER_SEC)); } } @@ -937,7 +937,7 @@ dh_tests (void) y = sizeof (buf[1]); if ((errnum = dh_encrypt_key (buf[0], 16, buf[1], &y, &prng, find_prng ("yarrow"), - find_hash ("md5"), &usera)) != CRYPT_OK) { + find_hash ("md5"), &usera)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -965,7 +965,7 @@ dh_tests (void) x = sizeof (buf[1]); if ((errnum = dh_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), - &usera)) != CRYPT_OK) { + &usera)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -979,8 +979,8 @@ dh_tests (void) exit (-1); } printf ("dh_sign/verify_hash: %s (%d,%d), %lu\n", - ((stat == 1) - && (stat2 == 0)) ? "passed" : "failed", stat, stat2, x); + ((stat == 1) + && (stat2 == 0)) ? "passed" : "failed", stat, stat2, x); dh_free (&usera); } #else @@ -1013,7 +1013,7 @@ rng_tests (void) x = rng_get_bytes (buf, sizeof (buf), &callback); t1 = XCLOCK () - t1; printf (" %f bytes per second...", - (double) x / ((double) t1 / (double) XCLOCKS_PER_SEC)); + (double) x / ((double) t1 / (double) XCLOCKS_PER_SEC)); printf ("read %d bytes.\n ", x); for (y = 0; y < x; y++) printf ("%02x ", buf[y]); @@ -1022,7 +1022,7 @@ rng_tests (void) #ifdef YARROW if ((errnum = rng_make_prng (128, find_prng ("yarrow"), &prng, - &callback)) != CRYPT_OK) { + &callback)) != CRYPT_OK) { printf (" starting yarrow error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1123,18 +1123,18 @@ ecc_tests (void) for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { t1 = XCLOCK (); - for (tt = 0; tt < 25; tt++) { - if ((errnum = - ecc_make_key (&prng, find_prng ("yarrow"), sizes[ii], - &usera)) != CRYPT_OK) { - printf ("Error: %s\n", error_to_string (errnum)); - exit (-1); - } - ecc_free (&usera); + for (tt = 0; tt < 10; tt++) { + if ((errnum = + ecc_make_key (&prng, find_prng ("yarrow"), sizes[ii], + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + ecc_free (&usera); } t1 = XCLOCK () - t1; printf ("Make ECC-%d key took %f msec\n", sizes[ii] * 8, - 1000.0 * (((double) t1 / 25.0) / (double) XCLOCKS_PER_SEC)); + 1000.0 * (((double) t1 / 10.0) / (double) XCLOCKS_PER_SEC)); } } @@ -1145,7 +1145,7 @@ ecc_tests (void) y = sizeof (buf[1]); if ((errnum = ecc_encrypt_key (buf[0], 32, buf[1], &y, &prng, find_prng ("yarrow"), - find_hash ("sha256"), &usera)) != CRYPT_OK) { + find_hash ("sha256"), &usera)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1172,7 +1172,7 @@ ecc_tests (void) x = sizeof (buf[1]); if ((errnum = ecc_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), - &usera)) != CRYPT_OK) { + &usera)) != CRYPT_OK) { printf ("Error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1187,7 +1187,7 @@ ecc_tests (void) exit (-1); } printf ("ecc_sign/verify_hash: %s (%d,%d)\n", - ((stat == 1) && (stat2 == 0)) ? "passed" : "failed", stat, stat2); + ((stat == 1) && (stat2 == 0)) ? "passed" : "failed", stat, stat2); ecc_free (&usera); } #else @@ -1342,15 +1342,15 @@ register_all_algs (void) register_cipher (&null_desc); +#ifdef SHA1 + register_hash (&sha1_desc); +#endif #ifdef SHA256 register_hash (&sha256_desc); #endif #ifdef TIGER register_hash (&tiger_desc); #endif -#ifdef SHA1 - register_hash (&sha1_desc); -#endif #ifdef MD5 register_hash (&md5_desc); #endif @@ -1383,8 +1383,8 @@ kr_display (pk_key * kr) while (kr->system != NON_KEY) { printf ("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, - sys[kr->system], type[kr->key_type], kr->name, kr->email, - kr->description); + sys[kr->system], type[kr->key_type], kr->name, kr->email, + kr->description); kr = kr->next; } printf ("\n"); @@ -1402,7 +1402,7 @@ kr_test_makekeys (pk_key ** kr) printf ("KR: Making DH key...\n"); if ((errnum = kr_make_key (*kr, &prng, find_prng ("yarrow"), DH_KEY, 128, "dhkey", - "dh@dh.dh", "dhkey one")) != CRYPT_OK) { + "dh@dh.dh", "dhkey one")) != CRYPT_OK) { printf ("Make key error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1411,7 +1411,7 @@ kr_test_makekeys (pk_key ** kr) printf ("KR: Making ECC key...\n"); if ((errnum = kr_make_key (*kr, &prng, find_prng ("yarrow"), ECC_KEY, 20, "ecckey", - "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { + "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { printf ("Make key error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1420,7 +1420,7 @@ kr_test_makekeys (pk_key ** kr) printf ("KR: Making RSA key...\n"); if ((errnum = kr_make_key (*kr, &prng, find_prng ("yarrow"), RSA_KEY, 128, "rsakey", - "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { + "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { printf ("Make key error: %s\n", error_to_string (errnum)); exit (-1); } @@ -1533,12 +1533,12 @@ kr_test (void) _kr = kr; for (i = 0; i < 3; i++) { printf ("Testing a key with system %d, type %d:\t", _kr->system, - _kr->key_type); + _kr->key_type); len = sizeof (buf2); if ((errnum = - kr_encrypt_key (kr, _kr->ID, buf, 16, buf2, &len, &prng, - find_prng ("yarrow"), - find_hash ("md5"))) != CRYPT_OK) { + kr_encrypt_key (kr, _kr->ID, buf, 16, buf2, &len, &prng, + find_prng ("yarrow"), + find_hash ("md5"))) != CRYPT_OK) { printf ("Encrypt error, %d, %s\n", i, error_to_string (errnum)); exit (-1); } @@ -1555,8 +1555,8 @@ kr_test (void) len = sizeof (buf2); if ((errnum = - kr_sign_hash (kr, _kr->ID, buf, 32, buf2, &len, &prng, - find_prng ("yarrow"))) != CRYPT_OK) { + kr_sign_hash (kr, _kr->ID, buf, 32, buf2, &len, &prng, + find_prng ("yarrow"))) != CRYPT_OK) { printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errnum)); exit (-1); } @@ -1576,8 +1576,8 @@ kr_test (void) len = sizeof (buf); if ((errnum = - kr_fingerprint (kr, _kr->ID, find_hash ("sha1"), buf, - &len)) != CRYPT_OK) { + kr_fingerprint (kr, _kr->ID, find_hash ("sha1"), buf, + &len)) != CRYPT_OK) { printf ("kr_fingerprint failed, %i, %lu\n", i, len); exit (-1); } @@ -1585,7 +1585,7 @@ kr_test (void) for (j = 0; j < 20; j++) { printf ("%02x", buf[j]); if (j < 19) - printf (":"); + printf (":"); } printf ("\n\n"); @@ -1633,8 +1633,8 @@ kr_test (void) len = sizeof (buf3); if ((errnum = kr_encrypt_key (kr, kr->ID, buf, 16, buf3, &len, &prng, - find_prng ("yarrow"), - find_hash ("md5"))) != CRYPT_OK) { + find_prng ("yarrow"), + find_hash ("md5"))) != CRYPT_OK) { printf ("Encrypt error, %d, %s\n", i, error_to_string (errnum)); exit (-1); } diff --git a/des.c b/des.c index 42b11d9..21b4198 100644 --- a/des.c +++ b/des.c @@ -519,6 +519,9 @@ void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key int des_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else int err; static const struct des_test_case { int num, mode; // mode 1 = encrypt @@ -648,10 +651,14 @@ int des_test(void) } return CRYPT_OK; + #endif } int des3_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else unsigned char key[24], pt[8], ct[8], tmp[8]; symmetric_key skey; int x, err; @@ -680,6 +687,7 @@ int des3_test(void) } return CRYPT_OK; + #endif } int des_keysize(int *desired_keysize) diff --git a/dh.c b/dh.c index 0e4ac43..7540292 100644 --- a/dh.c +++ b/dh.c @@ -109,7 +109,7 @@ static const struct { #ifdef DH4096 { 512, - "DH-4096", + "DH-4096", "3", "Id8ukxZdao3hS0NGTKAXdt3c8PpiyigIyBY8lwOHjM2cqkaZgwvr1pA6OowS" "32kJkeOqKB8gNTZZZVqOFkPXgvC4WveUgA5a7rhTj28pDidNROmMO70CCcSw" @@ -125,7 +125,7 @@ static const struct { "PT0+ZAUyLSAVHbsul++cawh" }, #endif -{ +{ 0, NULL, NULL, @@ -160,7 +160,7 @@ int dh_test(void) /* ensure p is prime */ if ((res = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } - if (primality == 0) { + if (primality == 0) { res = CRYPT_FAIL_TESTVECTOR; goto done; } @@ -213,7 +213,7 @@ int dh_get_size(dh_key *key) return INT_MAX; /* large value that would cause dh_make_key() to fail */ } } - + int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) { unsigned char buf[512]; @@ -232,7 +232,7 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++); #ifdef FAST_PK keysize = MIN(sets[x].size, 32); -#else +#else keysize = sets[x].size; #endif @@ -257,7 +257,7 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) if (mp_read_unsigned_bin(&key->x, buf, keysize) != MP_OKAY) { goto error; } if (mp_exptmod(&g, &key->x, &p, &key->y) != MP_OKAY) { goto error; } key->type = PK_PRIVATE; - + if (mp_shrink(&key->x) != MP_OKAY) { goto error; } if (mp_shrink(&key->y) != MP_OKAY) { goto error; } @@ -341,11 +341,11 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) /* export y */ OUTPUT_BIGNUM(&key->y, buf2, y, z); - if (type == PK_PRIVATE) { + if (type == PK_PRIVATE) { /* export x */ OUTPUT_BIGNUM(&key->x, buf2, y, z); } - + /* check for overflow */ if (*outlen < y) { #ifdef CLEAN_STACK @@ -362,9 +362,9 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) memcpy(out, buf2, (size_t)y); /* clear mem */ -#ifdef CLEAN_STACK +#ifdef CLEAN_STACK zeromem(buf2, sizeof(buf2)); -#endif +#endif return CRYPT_OK; } @@ -376,24 +376,30 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key) _ARGCHK(in != NULL); _ARGCHK(key != NULL); - /* check type byte */ - if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { - return err; - } - + /* make sure valid length */ if (2+PACKET_SIZE > inlen) { return CRYPT_INVALID_PACKET; } + /* check type byte */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + /* init */ - if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { + if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { return CRYPT_MEM; } + /* advance past packet header */ y = PACKET_SIZE; + + /* key type, e.g. private, public */ key->type = (int)in[y++]; + + /* key size in bytes */ s = (unsigned long)in[y++] * 8; - + for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); if (sets[x].size == 0) { err = CRYPT_INVALID_KEYSIZE; @@ -423,7 +429,7 @@ int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key) /* eliminate private key if public */ if (key->type == PK_PUBLIC) { mp_clear(&key->x); - } + } return CRYPT_OK; error: @@ -431,7 +437,7 @@ error: return err; } -int dh_shared_secret(dh_key *private_key, dh_key *public_key, +int dh_shared_secret(dh_key *private_key, dh_key *public_key, unsigned char *out, unsigned long *outlen) { mp_int tmp, p; @@ -454,7 +460,7 @@ int dh_shared_secret(dh_key *private_key, dh_key *public_key, } /* compute y^x mod p */ - if (mp_init_multi(&tmp, &p, NULL) != MP_OKAY) { + if (mp_init_multi(&tmp, &p, NULL) != MP_OKAY) { return CRYPT_MEM; } @@ -467,7 +473,7 @@ int dh_shared_secret(dh_key *private_key, dh_key *public_key, res = CRYPT_BUFFER_OVERFLOW; goto done; } - (void)mp_to_unsigned_bin(&tmp, out); + if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY) { goto error; } *outlen = x; res = CRYPT_OK; goto done; diff --git a/dh_sys.c b/dh_sys.c index fc39c5c..ade0da5 100644 --- a/dh_sys.c +++ b/dh_sys.c @@ -194,7 +194,24 @@ done: return res; } - +/* perform an ElGamal Signature of a hash + * + * The math works as follows. x is the private key, M is the message to sign + + 1. pick a random k + 2. compute a = g^k mod p + 3. compute b = (M - xa)/k mod p + 4. Send (a,b) + + Now to verify with y=g^x mod p, a and b + + 1. compute y^a * a^b = g^(xa) * g^(k*(M-xa)/k) + = g^(xa + (M - xa)) + = g^M [all mod p] + + 2. Compare against g^M mod p [based on input hash]. + 3. If result of #2 == result of #1 then signature valid +*/ int dh_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, dh_key *key) diff --git a/ecc.c b/ecc.c index bdd9488..21b59af 100644 --- a/ecc.c +++ b/ecc.c @@ -30,7 +30,7 @@ static const struct { }, #endif #ifdef ECC192 -{ +{ 24, "ECC-192", /* prime */ @@ -65,7 +65,7 @@ static const struct { /* Gx */ "jpqOf1BHus6Yd/pyhyVpP", - + /* Gy */ "3FCtyo2yHA5SFjkCGbYxbOvNeChwS+j6wSIwck", }, @@ -88,7 +88,7 @@ static const struct { /* Gy */ "4/ZGkB+6d+RZkVhIdmFdXOhpZDNQp5UpiksG6Wtlr7r" -}, +}, #endif #ifdef ECC384 { @@ -97,11 +97,11 @@ static const struct { /* prime */ "//////////////////////////////////////////x/////00000000003/" "////", - + /* B */ "ip4lf+8+v+IOZWLhu/Wj6HWTd6x+WK4I0nG8Zr0JXrh6LZcDYYxHdIg5oEtJ" "x2hl", - + /* Order */ "////////////////////////////////nsDDWVGtBTzO6WsoIB2dUkpi6MhC" "nIbp", @@ -109,7 +109,7 @@ static const struct { /* Gx and Gy */ "geVA8hwB1JUEiSSUyo2jT6uTEsABfvkOMVT1u89KAZXL0l9TlrKfR3fKNZXo" "TWgt", - + "DXVUIfOcB6zTdfY/afBSAVZq7RqecXHywTen4xNmkC0AOB7E7Nw1dNf37NoG" "wWvV" }, @@ -118,22 +118,22 @@ static const struct { { 65, "ECC-521", - /* prime */ + /* prime */ "V///////////////////////////////////////////////////////////" "///////////////////////////", - + /* B */ "56LFhbXZXoQ7vAQ8Q2sXK3kejfoMvcp5VEuj8cHZl49uLOPEL7iVfDx5bB0l" "JknlmSrSz+8FImqyUz57zHhK3y0", - - /* Order */ + + /* Order */ "V//////////////////////////////////////////+b66XuE/BvPhVym1I" "FS9fT0xjScuYPn7hhjljnwHE6G9", /* Gx and Gy */ "CQ5ZWQt10JfpPu+osOZbRH2d6I1EGK/jI7uAAzWQqqzkg5BNdVlvrae/Xt19" "wB/gDupIBF1XMf2c/b+VZ72vRrc", - + "HWvAMfucZl015oANxGiVHlPcFL4ILURH6WNhxqN9pvcB9VkSfbUz2P0nL2v0" "J+j1s4rF726edB2G8Y+b7QVqMPG", }, @@ -189,7 +189,7 @@ void ecc_find_base(void) mp_sqrmod(&tmp2, &p, &tmp2); /* tmp2 should equal tmp1 */ - } while (mp_cmp(&tmp1, &tmp2)); + } while (mp_cmp(&tmp1, &tmp2)); /* now output values in way that libtomcrypt wants */ mp_todecimal(&p, buf); @@ -249,8 +249,8 @@ static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus, mp_int *mu) { mp_int s, tmp, tmpx; int res; - - if (mp_init_multi(&s, &tmp, &tmpx, NULL) != MP_OKAY) { + + if (mp_init_multi(&s, &tmp, &tmpx, NULL) != MP_OKAY) { return CRYPT_MEM; } @@ -293,8 +293,8 @@ static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus, { mp_int s, tmp, tmpx; int res; - - if (mp_init(&tmp) != MP_OKAY) { + + if (mp_init(&tmp) != MP_OKAY) { return CRYPT_MEM; } @@ -303,14 +303,14 @@ static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus, mp_clear(&tmp); return CRYPT_MEM; } - + if (mp_cmp(&P->x, &Q->x) == MP_EQ) if (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &tmp) == MP_EQ) { mp_clear(&tmp); return dbl_point(P, R, modulus, mu); } - if (mp_init_multi(&tmpx, &s, NULL) != MP_OKAY) { + if (mp_init_multi(&tmpx, &s, NULL) != MP_OKAY) { mp_clear(&tmp); return CRYPT_MEM; } @@ -360,7 +360,7 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) mp_int mu; mp_digit buf; int first, bitbuf, bitcpy, bitcnt, mode, digidx; - + /* init barrett reduction */ if (mp_init(&mu) != MP_OKAY) { return CRYPT_MEM; @@ -369,7 +369,7 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) mp_clear(&mu); return CRYPT_MEM; } - + /* alloc ram for window temps */ for (i = 0; i < 8; i++) { M[i] = new_point(); @@ -381,7 +381,7 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) return CRYPT_MEM; } } - + /* make a copy of G incase R==G */ tG = new_point(); if (tG == NULL) { goto error; } @@ -391,12 +391,12 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) if (dbl_point(G, M[0], modulus, &mu) != CRYPT_OK) { goto error; } if (dbl_point(M[0], M[0], modulus, &mu) != CRYPT_OK) { goto error; } if (dbl_point(M[0], M[0], modulus, &mu) != CRYPT_OK) { goto error; } - + /* now find (8+k)G for k=1..7 */ for (j = 9; j < 16; j++) { if (add_point(M[j-9], G, M[j-8], modulus, &mu) != CRYPT_OK) { goto error; } } - + /* tG = G */ if (mp_copy(&G->x, &tG->x) != MP_OKAY) { goto error; } if (mp_copy(&G->y, &tG->y) != MP_OKAY) { goto error; } @@ -408,13 +408,13 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) digidx = k->used - 1; bitcpy = bitbuf = 0; first = 1; - + /* perform ops */ for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { if (digidx == -1) { - break; + break; } buf = k->dp[digidx--]; bitcnt = (int) DIGIT_BIT; @@ -423,17 +423,18 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) /* grab the next msb from the multiplicand */ i = (buf >> (DIGIT_BIT - 1)) & 1; buf <<= 1; - + /* skip leading zero bits */ - if (mode == 0 && i == 0) - continue; - - /* if the bit is zero and mode == 1 then we double */ - if (mode == 1 && i == 0) { - if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } + if (mode == 0 && i == 0) { continue; } - + + /* if the bit is zero and mode == 1 then we double */ + if (mode == 1 && i == 0) { + if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } + continue; + } + /* else we add it to the window */ bitbuf |= (i << (WINSIZE - ++bitcpy)); mode = 2; @@ -442,39 +443,35 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) /* if this is the first window we do a simple copy */ if (first == 1) { /* R = kG [k = first window] */ - if (mp_copy(&M[bitbuf-8]->x, &R->x) != MP_OKAY) { goto error; } - if (mp_copy(&M[bitbuf-8]->y, &R->y) != MP_OKAY) { goto error; } + if (mp_copy(&M[bitbuf-8]->x, &R->x) != MP_OKAY) { goto error; } + if (mp_copy(&M[bitbuf-8]->y, &R->y) != MP_OKAY) { goto error; } first = 0; } else { /* normal window */ /* ok window is filled so double as required and add */ /* double first */ for (j = 0; j < WINSIZE; j++) { - if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } + if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } } - /* then add, bitbuf will be 1..15 [1..2^WINSIZE] guaranteed */ - if (bitbuf == 1) { - if (add_point(R, tG, R, modulus, &mu) != CRYPT_OK) { goto error; } - } else { - if (add_point(R, M[bitbuf-8], R, modulus, &mu) != CRYPT_OK) { goto error; } - } + /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ + if (add_point(R, M[bitbuf-8], R, modulus, &mu) != CRYPT_OK) { goto error; } } /* empty window and reset */ bitcpy = bitbuf = 0; mode = 1; } } - + /* if bits remain then double/add */ if (mode == 2 && bitcpy > 0) { /* double then add */ for (j = 0; j < bitcpy; j++) { /* only double if we have had at least one add first */ if (first == 0) { - if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } + if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } } - + bitbuf <<= 1; if ((bitbuf & (1 << WINSIZE)) != 0) { if (first == 1){ @@ -489,7 +486,7 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) } } } - res = CRYPT_OK; + res = CRYPT_OK; goto done; error: res = CRYPT_MEM; @@ -510,18 +507,18 @@ int ecc_test(void) ecc_point *G, *GG; int i, res, primality; - if (mp_init_multi(&modulus, &order, NULL) != MP_OKAY) { + if (mp_init_multi(&modulus, &order, NULL) != MP_OKAY) { return CRYPT_MEM; } G = new_point(); - if (G == NULL) { + if (G == NULL) { mp_clear_multi(&modulus, &order, NULL); return CRYPT_MEM; } GG = new_point(); - if (GG == NULL) { + if (GG == NULL) { mp_clear_multi(&modulus, &order, NULL); del_point(G); return CRYPT_MEM; @@ -540,7 +537,7 @@ int ecc_test(void) res = CRYPT_FAIL_TESTVECTOR; goto done1; } - + /* is order prime ? */ if (is_prime(&order, &primality) != CRYPT_OK) { goto error; } if (primality == 0) { @@ -579,11 +576,11 @@ void ecc_sizes(int *low, int *high) *low = INT_MAX; *high = 0; for (i = 0; sets[i].size != 0; i++) { - if (sets[i].size < *low) { - *low = sets[i].size; + if (sets[i].size < *low) { + *low = sets[i].size; } - if (sets[i].size > *high) { - *high = sets[i].size; + if (sets[i].size > *high) { + *high = sets[i].size; } } } @@ -606,7 +603,7 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++); keysize = sets[x].size; - if (sets[x].size == 0) { + if (sets[x].size == 0) { return CRYPT_INVALID_KEYSIZE; } key->idx = x; @@ -617,7 +614,7 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) } /* setup the key variables */ - if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL) != MP_OKAY) { + if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL) != MP_OKAY) { return CRYPT_MEM; } base = new_point(); @@ -635,7 +632,7 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) /* make the public key */ if (ecc_mulmod(&key->k, base, &key->pubkey, &prime) != CRYPT_OK) { goto error; } key->type = PK_PRIVATE; - + /* shrink key */ if (mp_shrink(&key->k) != MP_OKAY) { goto error; } if (mp_shrink(&key->pubkey.x) != MP_OKAY) { goto error; } @@ -689,12 +686,12 @@ static int compress_y_point(ecc_point *pt, int idx, int *result) if (mp_exptmod(&tmp, &tmp2, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = (x^3 - 3x + b)^((p+1)/4) mod p */ /* if tmp equals the y point give a 0, otherwise 1 */ - if (mp_cmp(&tmp, &pt->y) == 0) { + if (mp_cmp(&tmp, &pt->y) == 0) { *result = 0; } else { *result = 1; } - + res = CRYPT_OK; goto done; error: @@ -710,7 +707,7 @@ static int expand_y_point(ecc_point *pt, int idx, int result) int res; _ARGCHK(pt != NULL); - + if (mp_init_multi(&tmp, &tmp2, &p, NULL) != MP_OKAY) { return CRYPT_MEM; } @@ -736,7 +733,7 @@ static int expand_y_point(ecc_point *pt, int idx, int result) } else { if (mp_sub(&p, &tmp, &pt->y) != MP_OKAY) { goto error; } } - + res = CRYPT_OK; goto done; error: @@ -795,8 +792,8 @@ int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key _ARGCHK(key != NULL); /* type valid? */ - if (key->type != PK_PRIVATE && type == PK_PRIVATE) { - return CRYPT_PK_TYPE_MISMATCH; + if (key->type != PK_PRIVATE && type == PK_PRIVATE) { + return CRYPT_PK_TYPE_MISMATCH; } /* output type and magic byte */ @@ -818,7 +815,7 @@ int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key } /* check size */ - if (*outlen < y) { + if (*outlen < y) { return CRYPT_BUFFER_OVERFLOW; } @@ -842,15 +839,16 @@ int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) _ARGCHK(in != NULL); _ARGCHK(key != NULL); - /* check type */ - if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { - return err; - } - + /* check length */ if (2+PACKET_SIZE > inlen) { return CRYPT_INVALID_PACKET; } + /* check type */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + /* init key */ if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL) != MP_OKAY) { return CRYPT_MEM; @@ -859,9 +857,9 @@ int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) y = PACKET_SIZE; key->type = (int)in[y++]; s = (unsigned long)in[y++]; - + for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); - if (sets[x].size == 0) { + if (sets[x].size == 0) { err = CRYPT_INVALID_KEYSIZE; goto error; } @@ -881,30 +879,30 @@ int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) /* load x coordinate */ INPUT_BIGNUM(&key->pubkey.x, in, x, y); - + /* load y */ x = (unsigned long)in[y++]; - if ((err = expand_y_point(&key->pubkey, key->idx, (int)x)) != CRYPT_OK) { - goto error; + if ((err = expand_y_point(&key->pubkey, key->idx, (int)x)) != CRYPT_OK) { + goto error; } if (key->type == PK_PRIVATE) { /* load private key */ INPUT_BIGNUM(&key->k, in, x, y); } - + /* eliminate private key if public */ if (key->type == PK_PUBLIC) { mp_clear(&key->k); - } - + } + return CRYPT_OK; error: mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); return err; } -int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, +int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, unsigned char *out, unsigned long *outlen) { unsigned long x, y; @@ -928,17 +926,17 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, /* make new point */ result = new_point(); - if (result == NULL) { + if (result == NULL) { return CRYPT_MEM; } - if (mp_init(&prime) != MP_OKAY) { + if (mp_init(&prime) != MP_OKAY) { del_point(result); return CRYPT_MEM; } - if (mp_read_radix(&prime, (unsigned char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } - if ((err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime)) != CRYPT_OK) { res = err; goto done1; } + if (mp_read_radix(&prime, (unsigned char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } + if ((res = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime)) != CRYPT_OK) { goto done1; } x = (unsigned long)mp_unsigned_bin_size(&result->x); y = (unsigned long)mp_unsigned_bin_size(&result->y); @@ -948,8 +946,8 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, goto done1; } *outlen = x+y; - (void)mp_to_unsigned_bin(&result->x, out); - (void)mp_to_unsigned_bin(&result->y, out+x); + if (mp_to_unsigned_bin(&result->x, out) != MP_OKAY) { goto error; } + if (mp_to_unsigned_bin(&result->y, out+x) != MP_OKAY) { goto error; } res = CRYPT_OK; goto done1; diff --git a/ecc_sys.c b/ecc_sys.c index 6a3eb9e..e15e473 100644 --- a/ecc_sys.c +++ b/ecc_sys.c @@ -299,7 +299,19 @@ done1: return res; } -/* verify that mG = (bA + Y) */ +/* verify that mG = (bA + Y) + * + * The signatures work by making up a fresh key "a" with a public key "A". Now we want to sign so the + * public key Y = xG can verify it. + * + * b = (m - x)/k, A is the public key embedded and Y is the users public key [who signed it] + * A = kG therefore bA == ((m-x)/k)kG == (m-x)G + * + * Adding Y = xG to the bA gives us (m-x)G + xG == mG + * + * The user given only xG, kG and b cannot determine k or x which means they can't find the private key. + * + */ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long inlen, int *stat, ecc_key *key) diff --git a/hmac.c b/hmac.c index 60fc6ec..833f749 100644 --- a/hmac.c +++ b/hmac.c @@ -37,7 +37,7 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon return err; } - if(key == NULL || keylen == 0) { + if (keylen == 0) { return CRYPT_INVALID_KEYSIZE; } @@ -231,6 +231,9 @@ Category: Informational R. Glenn int hmac_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else unsigned char digest[MAXBLOCKSIZE]; int i; @@ -497,6 +500,7 @@ Key First" } else { return CRYPT_OK; } + #endif } #endif diff --git a/makefile b/makefile index faf011b..f2255a9 100644 --- a/makefile +++ b/makefile @@ -9,7 +9,7 @@ # a build. This is easy to remedy though, for those that have problems. # The version -VERSION=0.83 +VERSION=0.84 #ch1-01-1 # Compiler and Linker Names @@ -31,7 +31,7 @@ CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Wshadow -Werror # optimize for SIZE CFLAGS += -Os -# compile for DEBUGGING +# compile for DEBUGING #CFLAGS += -g3 #ch1-01-3 @@ -57,7 +57,7 @@ OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \ md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \ safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o \ -ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o +mpi.o prime.o twofish.o packet.o hmac.o strings.o TESTOBJECTS=demos/test.o HASHOBJECTS=demos/hashsum.o @@ -71,7 +71,7 @@ LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz #Header files used by libtomcrypt. -HEADERS=mpi.h mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \ +HEADERS=tommath.h mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \ mycrypt_misc.h mycrypt_prng.h mycrypt_cipher.h mycrypt_hash.h \ mycrypt_macros.h mycrypt_pk.h mycrypt.h mycrypt_argchk.h mycrypt_custom.h @@ -129,8 +129,7 @@ clean: #nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to #delete it if we are rebuilding it. docs: crypt.tex - rm -f crypt.pdf - rm -f $(LEFTOVERS) + rm -f crypt.pdf $(LEFTOVERS) latex crypt > /dev/null makeindex crypt > /dev/null pdflatex crypt > /dev/null diff --git a/makefile.msvc b/makefile.msvc index bbf9059..381ebb8 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -2,7 +2,7 @@ # #Tom St Denis -CFLAGS = /I. /Ogiyb2t /Gs /DWIN32 /W3 +CFLAGS = /I. /Ogiyb1s /Gs /DWIN32 /W3 default: library @@ -11,7 +11,7 @@ OBJECTS=keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj \ bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj \ md5.obj md4.obj md2.obj sha256.obj sha512.obj xtea.obj aes.obj serpent.obj des.obj \ safer_tab.obj safer.obj safer+.obj rc4.obj rc2.obj rc6.obj rc5.obj cast5.obj noekeon.obj \ -blowfish.obj crypt.obj ampi.obj mpi.obj prime.obj twofish.obj packet.obj hmac.obj strings.obj +blowfish.obj crypt.obj mpi.obj prime.obj twofish.obj packet.obj hmac.obj strings.obj library: $(OBJECTS) lib /out:tomcrypt.lib $(OBJECTS) diff --git a/md2.c b/md2.c index 82bd4a3..249f53a 100644 --- a/md2.c +++ b/md2.c @@ -136,6 +136,9 @@ void md2_done(hash_state * md, unsigned char *hash) int md2_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char md[16]; @@ -184,6 +187,7 @@ int md2_test(void) } } return CRYPT_OK; + #endif } #endif diff --git a/md4.c b/md4.c index cff1442..6c6003f 100644 --- a/md4.c +++ b/md4.c @@ -221,6 +221,9 @@ void md4_done(hash_state * md, unsigned char *hash) int md4_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct md4_test_case { char *input; unsigned char digest[16]; @@ -261,6 +264,7 @@ int md4_test(void) } return CRYPT_OK; + #endif } #endif diff --git a/md5.c b/md5.c index ae9a1dd..ef999c2 100644 --- a/md5.c +++ b/md5.c @@ -208,6 +208,9 @@ void md5_done(hash_state * md, unsigned char *hash) int md5_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[16]; @@ -249,6 +252,7 @@ int md5_test(void) } } return CRYPT_OK; + #endif } #endif diff --git a/mpi.c b/mpi.c index 10288b1..383d198 100644 --- a/mpi.c +++ b/mpi.c @@ -1,6051 +1,7149 @@ -/* File Generated Automatically by gen.pl */ - -/* Start: bncore.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* configured for a AMD Duron Morgan core with etc/tune.c */ -int KARATSUBA_MUL_CUTOFF = 73, /* Min. number of digits before Karatsuba multiplication is used. */ - KARATSUBA_SQR_CUTOFF = 121, /* Min. number of digits before Karatsuba squaring is used. */ - MONTGOMERY_EXPT_CUTOFF = 128; /* max. number of digits that montgomery reductions will help for */ - -/* End: bncore.c */ - -/* Start: bn_fast_mp_invmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes the modular inverse via binary extended euclidean algorithm, - * that is c = 1/a mod b - * - * Based on mp_invmod except this is optimized for the case where b is - * odd as per HAC Note 14.64 on pp. 610 - */ -int -fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x, y, u, v, B, D; - int res, neg; - - /* init all our temps */ - if ((res = mp_init (&x)) != MP_OKAY) { - goto __ERR; - } - - if ((res = mp_init (&y)) != MP_OKAY) { - goto __X; - } - - if ((res = mp_init (&u)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_init (&v)) != MP_OKAY) { - goto __U; - } - - if ((res = mp_init (&B)) != MP_OKAY) { - goto __V; - } - - if ((res = mp_init (&D)) != MP_OKAY) { - goto __B; - } - - /* x == modulus, y == value to invert */ - if ((res = mp_copy (b, &x)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (a, &y)) != MP_OKAY) { - goto __D; - } - - /* we need |y| */ - if ((res = mp_abs (&y, &y)) != MP_OKAY) { - goto __D; - } - - /* 2. [modified] if x,y are both even then return an error! - * - * That is if gcd(x,y) = 2 * k then obviously there is no inverse. - */ - if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { - res = MP_VAL; - goto __D; - } - - /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ - if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto __D; - } - mp_set (&D, 1); - -top: - /* 4. while u is even do */ - while (mp_iseven (&u) == 1) { - /* 4.1 u = u/2 */ - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __D; - } - /* 4.2 if A or B is odd then */ - if (mp_iseven (&B) == 0) { - if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __D; - } - } - /* B = B/2 */ - if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto __D; - } - } - - /* 5. while v is even do */ - while (mp_iseven (&v) == 1) { - /* 5.1 v = v/2 */ - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __D; - } - /* 5.2 if C,D are even then */ - if (mp_iseven (&D) == 0) { - /* D = (D-x)/2 */ - if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __D; - } - } - /* D = D/2 */ - if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto __D; - } - } - - /* 6. if u >= v then */ - if (mp_cmp (&u, &v) != MP_LT) { - /* u = u - v, B = B - D */ - if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto __D; - } - } else { - /* v - v - u, D = D - B */ - if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto __D; - } - } - - /* if not zero goto step 4 */ - if (mp_iszero (&u) == 0) { - goto top; - } - - /* now a = C, b = D, gcd == g*v */ - - /* if v != 1 then there is no inverse */ - if (mp_cmp_d (&v, 1) != MP_EQ) { - res = MP_VAL; - goto __D; - } - - /* b is now the inverse */ - neg = a->sign; - while (D.sign == MP_NEG) { - if ((res = mp_add (&D, b, &D)) != MP_OKAY) { - goto __D; - } - } - mp_exch (&D, c); - c->sign = neg; - res = MP_OKAY; - -__D:mp_clear (&D); -__B:mp_clear (&B); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: - return res; -} - -/* End: bn_fast_mp_invmod.c */ - -/* Start: bn_fast_mp_montgomery_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes xR^-1 == x (mod N) via Montgomery Reduction - * - * This is an optimized implementation of mp_montgomery_reduce - * which uses the comba method to quickly calculate the columns of the - * reduction. - * - * Based on Algorithm 14.32 on pp.601 of HAC. -*/ -int -fast_mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) -{ - int ix, res, olduse; - mp_word W[512]; - - /* get old used count */ - olduse = a->used; - - /* grow a as required */ - if (a->alloc < m->used + 1) { - if ((res = mp_grow (a, m->used + 1)) != MP_OKAY) { - return res; - } - } - - { - register mp_word *_W; - register mp_digit *tmpa; - - _W = W; - tmpa = a->dp; - - /* copy the digits of a into W[0..a->used-1] */ - for (ix = 0; ix < a->used; ix++) { - *_W++ = *tmpa++; - } - - /* zero the high words of W[a->used..m->used*2] */ - for (; ix < m->used * 2 + 1; ix++) { - *_W++ = 0; - } - } - - for (ix = 0; ix < m->used; ix++) { - /* ui = ai * m' mod b - * - * We avoid a double precision multiplication (which isn't required) - * by casting the value down to a mp_digit. Note this requires that W[ix-1] have - * the carry cleared (see after the inner loop) - */ - register mp_digit ui; - ui = (((mp_digit) (W[ix] & MP_MASK)) * mp) & MP_MASK; - - /* a = a + ui * m * b^i - * - * This is computed in place and on the fly. The multiplication - * by b^i is handled by offseting which columns the results - * are added to. - * - * Note the comba method normally doesn't handle carries in the inner loop - * In this case we fix the carry from the previous column since the Montgomery - * reduction requires digits of the result (so far) [see above] to work. This is - * handled by fixing up one carry after the inner loop. The carry fixups are done - * in order so after these loops the first m->used words of W[] have the carries - * fixed - */ - { - register int iy; - register mp_digit *tmpx; - register mp_word *_W; - - /* alias for the digits of the modulus */ - tmpx = m->dp; - - /* Alias for the columns set by an offset of ix */ - _W = W + ix; - - /* inner loop */ - for (iy = 0; iy < m->used; iy++) { - *_W++ += ((mp_word) ui) * ((mp_word) * tmpx++); - } - } - - /* now fix carry for next digit, W[ix+1] */ - W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); - } - - - { - register mp_digit *tmpa; - register mp_word *_W, *_W1; - - /* nox fix rest of carries */ - _W1 = W + ix; - _W = W + ++ix; - - for (; ix <= m->used * 2 + 1; ix++) { - *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); - } - - /* copy out, A = A/b^n - * - * The result is A/b^n but instead of converting from an array of mp_word - * to mp_digit than calling mp_rshd we just copy them in the right - * order - */ - tmpa = a->dp; - _W = W + m->used; - - for (ix = 0; ix < m->used + 1; ix++) { - *tmpa++ = *_W++ & ((mp_word) MP_MASK); - } - - /* zero oldused digits, if the input a was larger than - * m->used+1 we'll have to clear the digits */ - for (; ix < olduse; ix++) { - *tmpa++ = 0; - } - } - - /* set the max used and clamp */ - a->used = m->used + 1; - mp_clamp (a); - - /* if A >= m then A = A - m */ - if (mp_cmp_mag (a, m) != MP_LT) { - return s_mp_sub (a, m, a); - } - return MP_OKAY; -} - -/* End: bn_fast_mp_montgomery_reduce.c */ - -/* Start: bn_fast_s_mp_mul_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Fast (comba) multiplier - * - * This is the fast column-array [comba] multiplier. It is designed to compute - * the columns of the product first then handle the carries afterwards. This - * has the effect of making the nested loops that compute the columns very - * simple and schedulable on super-scalar processors. - * - * This has been modified to produce a variable number of digits of output so - * if say only a half-product is required you don't have to compute the upper half - * (a feature required for fast Barrett reduction). - * - * Based on Algorithm 14.12 on pp.595 of HAC. - * - */ -int -fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - int olduse, res, pa, ix; - mp_word W[512]; - - /* grow the destination as required */ - if (c->alloc < digs) { - if ((res = mp_grow (c, digs)) != MP_OKAY) { - return res; - } - } - - /* clear temp buf (the columns) */ - memset (W, 0, sizeof (mp_word) * digs); - - /* calculate the columns */ - pa = a->used; - for (ix = 0; ix < pa; ix++) { - - /* this multiplier has been modified to allow you to control how many digits - * of output are produced. So at most we want to make upto "digs" digits - * of output. - * - * this adds products to distinct columns (at ix+iy) of W - * note that each step through the loop is not dependent on - * the previous which means the compiler can easily unroll - * the loop without scheduling problems - */ - { - register mp_digit tmpx, *tmpy; - register mp_word *_W; - register int iy, pb; - - /* alias for the the word on the left e.g. A[ix] * A[iy] */ - tmpx = a->dp[ix]; - - /* alias for the right side */ - tmpy = b->dp; - - /* alias for the columns, each step through the loop adds a new - term to each column - */ - _W = W + ix; - - /* the number of digits is limited by their placement. E.g. - we avoid multiplying digits that will end up above the # of - digits of precision requested - */ - pb = MIN (b->used, digs - ix); - - for (iy = 0; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - - } - - /* setup dest */ - olduse = c->used; - c->used = digs; - - { - register mp_digit *tmpc; - - /* At this point W[] contains the sums of each column. To get the - * correct result we must take the extra bits from each column and - * carry them down - * - * Note that while this adds extra code to the multiplier it saves time - * since the carry propagation is removed from the above nested loop. - * This has the effect of reducing the work from N*(N+N*c)==N^2 + c*N^2 to - * N^2 + N*c where c is the cost of the shifting. On very small numbers - * this is slower but on most cryptographic size numbers it is faster. - */ - tmpc = c->dp; - for (ix = 1; ix < digs; ix++) { - W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); - - /* clear unused */ - for (; ix < olduse; ix++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_mul_digs.c */ - -/* Start: bn_fast_s_mp_mul_high_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* this is a modified version of fast_s_mp_mul_digs that only produces - * output digits *above* digs. See the comments for fast_s_mp_mul_digs - * to see how it works. - * - * This is used in the Barrett reduction since for one of the multiplications - * only the higher digits were needed. This essentially halves the work. - * - * Based on Algorithm 14.12 on pp.595 of HAC. - */ -int -fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - int oldused, newused, res, pa, pb, ix; - mp_word W[512]; - - /* calculate size of product and allocate more space if required */ - newused = a->used + b->used + 1; - if (c->alloc < newused) { - if ((res = mp_grow (c, newused)) != MP_OKAY) { - return res; - } - } - - /* like the other comba method we compute the columns first */ - pa = a->used; - pb = b->used; - memset (W + digs, 0, (pa + pb + 1 - digs) * sizeof (mp_word)); - for (ix = 0; ix < pa; ix++) { - { - register mp_digit tmpx, *tmpy; - register int iy; - register mp_word *_W; - - /* work todo, that is we only calculate digits that are at "digs" or above */ - iy = digs - ix; - - /* copy of word on the left of A[ix] * B[iy] */ - tmpx = a->dp[ix]; - - /* alias for right side */ - tmpy = b->dp + iy; - - /* alias for the columns of output. Offset to be equal to or above the - * smallest digit place requested - */ - _W = &(W[digs]); - - /* compute column products for digits above the minimum */ - for (; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - } - - /* setup dest */ - oldused = c->used; - c->used = newused; - - /* now convert the array W downto what we need */ - for (ix = digs + 1; ix < newused; ix++) { - W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - c->dp[ix - 1] = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - c->dp[(pa + pb + 1) - 1] = (mp_digit) (W[(pa + pb + 1) - 1] & ((mp_word) MP_MASK)); - - for (; ix < oldused; ix++) { - c->dp[ix] = 0; - } - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_mul_high_digs.c */ - -/* Start: bn_fast_s_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* fast squaring - * - * This is the comba method where the columns of the product are computed first - * then the carries are computed. This has the effect of making a very simple - * inner loop that is executed the most - * - * W2 represents the outer products and W the inner. - * - * A further optimizations is made because the inner products are of the form - * "A * B * 2". The *2 part does not need to be computed until the end which is - * good because 64-bit shifts are slow! - * - * Based on Algorithm 14.16 on pp.597 of HAC. - * - */ -int -fast_s_mp_sqr (mp_int * a, mp_int * b) -{ - int olduse, newused, res, ix, pa; - mp_word W2[512], W[512]; - - /* calculate size of product and allocate as required */ - pa = a->used; - newused = pa + pa + 1; - if (b->alloc < newused) { - if ((res = mp_grow (b, newused)) != MP_OKAY) { - return res; - } - } - - /* zero temp buffer (columns) - * Note that there are two buffers. Since squaring requires - * a outter and inner product and the inner product requires - * computing a product and doubling it (a relatively expensive - * op to perform n^2 times if you don't have to) the inner and - * outer products are computed in different buffers. This way - * the inner product can be doubled using n doublings instead of - * n^2 - */ - memset (W, 0, newused * sizeof (mp_word)); - memset (W2, 0, newused * sizeof (mp_word)); - -/* note optimization - * values in W2 are only written in even locations which means - * we can collapse the array to 256 words [and fixup the memset above] - * provided we also fix up the summations below. Ideally - * the fixup loop should be unrolled twice to handle the even/odd - * cases, and then a final step to handle odd cases [e.g. newused == odd] - * - * This will not only save ~8*256 = 2KB of stack but lower the number of - * operations required to finally fix up the columns - */ - - /* This computes the inner product. To simplify the inner N^2 loop - * the multiplication by two is done afterwards in the N loop. - */ - for (ix = 0; ix < pa; ix++) { - /* compute the outer product - * - * Note that every outer product is computed - * for a particular column only once which means that - * there is no need todo a double precision addition - */ - W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); - - { - register mp_digit tmpx, *tmpy; - register mp_word *_W; - register int iy; - - /* copy of left side */ - tmpx = a->dp[ix]; - - /* alias for right side */ - tmpy = a->dp + (ix + 1); - - /* the column to store the result in */ - _W = W + (ix + ix + 1); - - /* inner products */ - for (iy = ix + 1; iy < pa; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); - } - } - } - - /* setup dest */ - olduse = b->used; - b->used = newused; - - /* double first value, since the inner products are half of what they should be */ - W[0] += W[0] + W2[0]; - - /* now compute digits */ - { - register mp_digit *tmpb; - - tmpb = b->dp; - - for (ix = 1; ix < newused; ix++) { - /* double/add next digit */ - W[ix] += W[ix] + W2[ix]; - - W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); - *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); - } - *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); - - /* clear high */ - for (; ix < olduse; ix++) { - *tmpb++ = 0; - } - } - - mp_clamp (b); - return MP_OKAY; -} - -/* End: bn_fast_s_mp_sqr.c */ - -/* Start: bn_mp_2expt.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes a = 2^b - * - * Simple algorithm which zeroes the int, grows it then just sets one bit - * as required. - */ -int -mp_2expt (mp_int * a, int b) -{ - int res; - - mp_zero (a); - if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - a->used = b / DIGIT_BIT + 1; - a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); - - return MP_OKAY; -} - -/* End: bn_mp_2expt.c */ - -/* Start: bn_mp_abs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = |a| - * - * Simple function copies the input and fixes the sign to positive - */ -int -mp_abs (mp_int * a, mp_int * b) -{ - int res; - if ((res = mp_copy (a, b)) != MP_OKAY) { - return res; - } - b->sign = MP_ZPOS; - return MP_OKAY; -} - -/* End: bn_mp_abs.c */ - -/* Start: bn_mp_add.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level addition (handles signs) */ -int -mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - /* get sign of both inputs */ - sa = a->sign; - sb = b->sign; - - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive */ - res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a + -b == a - b, but if b>a then we do it as -(b-a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a + b == b - a, but if a>b then we do it as -(a-b) */ - if (mp_cmp_mag (a, b) == MP_GT) { - res = s_mp_sub (a, b, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; - } - } else { - /* -a + -b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; - } - return res; -} - -/* End: bn_mp_add.c */ - -/* Start: bn_mp_addmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a + b (mod c) */ -int -mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_add (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_addmod.c */ - -/* Start: bn_mp_add_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit addition */ -int -mp_add_d (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t; - int res; - - if ((res = mp_init_size(&t, 1)) != MP_OKAY) { - return res; - } - mp_set (&t, b); - res = mp_add (a, &t, c); - - mp_clear (&t); - return res; -} - -/* End: bn_mp_add_d.c */ - -/* Start: bn_mp_and.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* AND two ints together */ -int -mp_and (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] &= x->dp[ix]; - } - - /* zero digits above the last from the smallest mp_int */ - for (; ix < t.used; ix++) { - t.dp[ix] = 0; - } - - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_and.c */ - -/* Start: bn_mp_clamp.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* trim unused digits - * - * This is used to ensure that leading zero digits are - * trimed and the leading "used" digit will be non-zero - * Typically very fast. Also fixes the sign if there - * are no more leading digits - */ -void -mp_clamp (mp_int * a) -{ - while (a->used > 0 && a->dp[a->used - 1] == 0) { - --(a->used); - } - if (a->used == 0) { - a->sign = MP_ZPOS; - } -} - -/* End: bn_mp_clamp.c */ - -/* Start: bn_mp_clear.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* clear one (frees) */ -void -mp_clear (mp_int * a) -{ - if (a->dp != NULL) { - - /* first zero the digits */ - memset (a->dp, 0, sizeof (mp_digit) * a->used); - - /* free ram */ - XFREE (a->dp); - - /* reset members to make debugging easier */ - a->dp = NULL; - a->alloc = a->used = 0; - } -} - -/* End: bn_mp_clear.c */ - -/* Start: bn_mp_cmp.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare two ints (signed)*/ -int -mp_cmp (mp_int * a, mp_int * b) -{ - /* compare based on sign */ - if (a->sign == MP_NEG && b->sign == MP_ZPOS) { - return MP_LT; - } else if (a->sign == MP_ZPOS && b->sign == MP_NEG) { - return MP_GT; - } - return mp_cmp_mag (a, b); -} - -/* End: bn_mp_cmp.c */ - -/* Start: bn_mp_cmp_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare a digit */ -int -mp_cmp_d (mp_int * a, mp_digit b) -{ - - if (a->sign == MP_NEG) { - return MP_LT; - } - - if (a->used > 1) { - return MP_GT; - } - - if (a->dp[0] > b) { - return MP_GT; - } else if (a->dp[0] < b) { - return MP_LT; - } else { - return MP_EQ; - } -} - -/* End: bn_mp_cmp_d.c */ - -/* Start: bn_mp_cmp_mag.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* compare maginitude of two ints (unsigned) */ -int -mp_cmp_mag (mp_int * a, mp_int * b) -{ - int n; - - /* compare based on # of non-zero digits */ - if (a->used > b->used) { - return MP_GT; - } else if (a->used < b->used) { - return MP_LT; - } - - /* compare based on digits */ - for (n = a->used - 1; n >= 0; n--) { - if (a->dp[n] > b->dp[n]) { - return MP_GT; - } else if (a->dp[n] < b->dp[n]) { - return MP_LT; - } - } - return MP_EQ; -} - -/* End: bn_mp_cmp_mag.c */ - -/* Start: bn_mp_copy.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* copy, b = a */ -int -mp_copy (mp_int * a, mp_int * b) -{ - int res, n; - - /* if dst == src do nothing */ - if (a == b || a->dp == b->dp) { - return MP_OKAY; - } - - /* grow dest */ - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - - /* zero b and copy the parameters over */ - b->used = a->used; - b->sign = a->sign; - - { - register mp_digit *tmpa, *tmpb; - - /* point aliases */ - tmpa = a->dp; - tmpb = b->dp; - - /* copy all the digits */ - for (n = 0; n < a->used; n++) { - *tmpb++ = *tmpa++; - } - - /* clear high digits */ - for (; n < b->alloc; n++) { - *tmpb++ = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_copy.c */ - -/* Start: bn_mp_count_bits.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* returns the number of bits in an int */ -int -mp_count_bits (mp_int * a) -{ - int r; - mp_digit q; - - if (a->used == 0) { - return 0; - } - - r = (a->used - 1) * DIGIT_BIT; - q = a->dp[a->used - 1]; - while (q > ((mp_digit) 0)) { - ++r; - q >>= ((mp_digit) 1); - } - return r; -} - -/* End: bn_mp_count_bits.c */ - -/* Start: bn_mp_div.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] - * HAC pp.598 Algorithm 14.20 - * - * Note that the description in HAC is horribly incomplete. For example, - * it doesn't consider the case where digits are removed from 'x' in the inner - * loop. It also doesn't consider the case that y has fewer than three digits, etc.. - * - * The overall algorithm is as described as 14.20 from HAC but fixed to treat these cases. -*/ -int -mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - mp_int q, x, y, t1, t2; - int res, n, t, i, norm, neg; - - - /* is divisor zero ? */ - if (mp_iszero (b) == 1) { - return MP_VAL; - } - - /* if a < b then q=0, r = a */ - if (mp_cmp_mag (a, b) == MP_LT) { - if (d != NULL) { - res = mp_copy (a, d); - } else { - res = MP_OKAY; - } - if (c != NULL) { - mp_zero (c); - } - return res; - } - - if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { - return res; - } - q.used = a->used + 2; - - if ((res = mp_init (&t1)) != MP_OKAY) { - goto __Q; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - goto __T1; - } - - if ((res = mp_init_copy (&x, a)) != MP_OKAY) { - goto __T2; - } - - if ((res = mp_init_copy (&y, b)) != MP_OKAY) { - goto __X; - } - - /* fix the sign */ - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - x.sign = y.sign = MP_ZPOS; - - /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ - norm = mp_count_bits(&y) % DIGIT_BIT; - if (norm < (DIGIT_BIT-1)) { - norm = (DIGIT_BIT-1) - norm; - if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { - goto __Y; - } - } else { - norm = 0; - } - - /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ - n = x.used - 1; - t = y.used - 1; - - /* step 2. while (x >= y*b^n-t) do { q[n-t] += 1; x -= y*b^{n-t} } */ - if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ - goto __Y; - } - - while (mp_cmp (&x, &y) != MP_LT) { - ++(q.dp[n - t]); - if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { - goto __Y; - } - } - - /* reset y by shifting it back down */ - mp_rshd (&y, n - t); - - /* step 3. for i from n down to (t + 1) */ - for (i = n; i >= (t + 1); i--) { - if (i > x.used) - continue; - - /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ - if (x.dp[i] == y.dp[t]) { - q.dp[i - t - 1] = ((1UL << DIGIT_BIT) - 1UL); - } else { - mp_word tmp; - tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); - tmp |= ((mp_word) x.dp[i - 1]); - tmp /= ((mp_word) y.dp[t]); - if (tmp > (mp_word) MP_MASK) - tmp = MP_MASK; - q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); - } - - /* step 3.2 while (q{i-t-1} * (yt * b + y{t-1})) > xi * b^2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ - q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; - do { - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; - - /* find left hand */ - mp_zero (&t1); - t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; - t1.dp[1] = y.dp[t]; - t1.used = 2; - if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto __Y; - } - - /* find right hand */ - t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; - t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; - t2.dp[2] = x.dp[i]; - t2.used = 3; - } while (mp_cmp (&t1, &t2) == MP_GT); - - /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ - if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { - goto __Y; - } - - /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ - if (x.sign == MP_NEG) { - if ((res = mp_copy (&y, &t1)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { - goto __Y; - } - if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { - goto __Y; - } - - q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; - } - } - - /* now q is the quotient and x is the remainder [which we have to normalize] */ - /* get sign before writing to c */ - x.sign = a->sign; - - if (c != NULL) { - mp_clamp (&q); - mp_exch (&q, c); - c->sign = neg; - } - - if (d != NULL) { - mp_div_2d (&x, norm, &x, NULL); - mp_exch (&x, d); - } - - res = MP_OKAY; - -__Y:mp_clear (&y); -__X:mp_clear (&x); -__T2:mp_clear (&t2); -__T1:mp_clear (&t1); -__Q:mp_clear (&q); - return res; -} - -/* End: bn_mp_div.c */ - -/* Start: bn_mp_div_2.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = a/2 */ -int -mp_div_2 (mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* copy */ - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* source alias */ - tmpa = a->dp + b->used - 1; - - /* dest alias */ - tmpb = b->dp + b->used - 1; - - /* carry */ - r = 0; - for (x = b->used - 1; x >= 0; x--) { - /* get the carry for the next iteration */ - rr = *tmpa & 1; - - /* shift the current digit, add in carry and store */ - *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); - - /* forward carry to next iteration */ - r = rr; - } - - /* zero excess digits */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - mp_clamp (b); - return MP_OKAY; -} - -/* End: bn_mp_div_2.c */ - -/* Start: bn_mp_div_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift right by a certain bit count (store quotient in c, remainder in d) */ -int -mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) -{ - mp_digit D, r, rr; - int x, res; - mp_int t; - - - /* if the shift count is <= 0 then we do no work */ - if (b <= 0) { - res = mp_copy (a, c); - if (d != NULL) { - mp_zero (d); - } - return res; - } - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - /* get the remainder */ - if (d != NULL) { - if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { - mp_rshd (c, b / DIGIT_BIT); - } - - /* shift any bit count < DIGIT_BIT */ - D = (mp_digit) (b % DIGIT_BIT); - if (D != 0) { - register mp_digit *tmpc, mask; - - /* mask */ - mask = (1U << D) - 1U; - - /* alias */ - tmpc = c->dp + (c->used - 1); - - /* carry */ - r = 0; - for (x = c->used - 1; x >= 0; x--) { - /* get the lower bits of this word in a temp */ - rr = *tmpc & mask; - - /* shift the current word and mix in the carry bits from the previous word */ - *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); - --tmpc; - - /* set the carry to the carry bits of the current word found above */ - r = rr; - } - } - mp_clamp (c); - res = MP_OKAY; - if (d != NULL) { - mp_exch (&t, d); - } - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_div_2d.c */ - -/* Start: bn_mp_div_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit division */ -int -mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) -{ - mp_int t, t2; - int res; - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - mp_set (&t, b); - res = mp_div (a, &t, c, &t2); - - /* set remainder if not null */ - if (d != NULL) { - *d = t2.dp[0]; - } - - mp_clear (&t); - mp_clear (&t2); - return res; -} - -/* End: bn_mp_div_d.c */ - -/* Start: bn_mp_dr_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reduce "a" in place modulo "b" using the Diminished Radix algorithm. - * - * Based on algorithm from the paper - * - * "Generating Efficient Primes for Discrete Log Cryptosystems" - * Chae Hoon Lim, Pil Loong Lee, - * POSTECH Information Research Laboratories - * - * The modulus must be of a special format [see manual] - */ -int -mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp) -{ - int err, i, j, k; - mp_word r; - mp_digit mu, *tmpj, *tmpi; - - /* k = digits in modulus */ - k = b->used; - - /* ensure that "a" has at least 2k digits */ - if (a->alloc < k + k) { - if ((err = mp_grow (a, k + k)) != MP_OKAY) { - return err; - } - } - - /* alias for a->dp[i] */ - tmpi = a->dp + k + k - 1; - - /* for (i = 2k - 1; i >= k; i = i - 1) - * - * This is the main loop of the reduction. Note that at the end - * the words above position k are not zeroed as expected. The end - * result is that the digits from 0 to k-1 are the residue. So - * we have to clear those afterwards. - */ - for (i = k + k - 1; i >= k; i = i - 1) { - /* x[i - 1 : i - k] += x[i]*mp */ - - /* x[i] * mp */ - r = ((mp_word) *tmpi--) * ((mp_word) mp); - - /* now add r to x[i-1:i-k] - * - * First add it to the first digit x[i-k] then form the carry - * then enter the main loop - */ - j = i - k; - - /* alias for a->dp[j] */ - tmpj = a->dp + j; - - /* add digit */ - *tmpj += (mp_digit)(r & MP_MASK); - - /* this is the carry */ - mu = (r >> ((mp_word) DIGIT_BIT)) + (*tmpj >> DIGIT_BIT); - - /* clear carry from a->dp[j] */ - *tmpj++ &= MP_MASK; - - /* now add rest of the digits - * - * Note this is basically a simple single digit addition to - * a larger multiple digit number. This is optimized somewhat - * because the propagation of carries is not likely to move - * more than a few digits. - * - */ - for (++j; mu != 0 && j <= (i - 1); ++j) { - *tmpj += mu; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - } - - /* if final carry */ - if (mu != 0) { - /* add mp to this to correct */ - j = i - k; - tmpj = a->dp + j; - - *tmpj += mp; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - - /* now handle carries */ - for (++j; mu != 0 && j <= (i - 1); j++) { - *tmpj += mu; - mu = *tmpj >> DIGIT_BIT; - *tmpj++ &= MP_MASK; - } - } - } - - /* zero words above k */ - tmpi = a->dp + k; - for (i = k; i < a->used; i++) { - *tmpi++ = 0; - } - - /* clamp, sub and return */ - mp_clamp (a); - - if (mp_cmp_mag (a, b) != MP_LT) { - return s_mp_sub (a, b, a); - } - return MP_OKAY; -} - -/* determines if a number is a valid DR modulus */ -int mp_dr_is_modulus(mp_int *a) -{ - int ix; - - /* must be at least two digits */ - if (a->used < 2) { - return 0; - } - - for (ix = 1; ix < a->used; ix++) { - if (a->dp[ix] != MP_MASK) { - return 0; - } - } - return 1; -} - -/* determines the setup value */ -void mp_dr_setup(mp_int *a, mp_digit *d) -{ - *d = (1 << DIGIT_BIT) - a->dp[0]; -} - - -/* End: bn_mp_dr_reduce.c */ - -/* Start: bn_mp_exch.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* swap the elements of two integers, for cases where you can't simply swap the - * mp_int pointers around - */ -void -mp_exch (mp_int * a, mp_int * b) -{ - mp_int t; - - t = *a; - *a = *b; - *b = t; -} - -/* End: bn_mp_exch.c */ - -/* Start: bn_mp_exptmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -static int f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); - -/* this is a shell function that calls either the normal or Montgomery - * exptmod functions. Originally the call to the montgomery code was - * embedded in the normal function but that wasted alot of stack space - * for nothing (since 99% of the time the Montgomery code would be called) - */ -int -mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -{ - int dr; - - dr = mp_dr_is_modulus(P); - /* if the modulus is odd use the fast method */ - if (((mp_isodd (P) == 1 && P->used < MONTGOMERY_EXPT_CUTOFF) || dr == 1) && P->used > 4) { - return mp_exptmod_fast (G, X, P, Y, dr); - } else { - return f_mp_exptmod (G, X, P, Y); - } -} - -static int -f_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -{ - mp_int M[256], res, mu; - mp_digit buf; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - - /* init G array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { - for (y = 0; y < x; y++) { - mp_clear (&M[y]); - } - return err; - } - } - - /* create mu, used for Barrett reduction */ - if ((err = mp_init (&mu)) != MP_OKAY) { - goto __M; - } - if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { - goto __MU; - } - - /* create M table - * - * The M table contains powers of the input base, e.g. M[x] = G^x mod P - * - * The first half of the table is not computed though accept for M[0] and M[1] - */ - if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { - goto __MU; - } - - /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto __MU; - } - mp_set (&res, 1); - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; - digidx = X->used - 1; - bitcpy = bitbuf = 0; - - bitcnt = 1; - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) - continue; - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __MU; - } - - /* empty window and reset */ - bitcpy = bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -__RES:mp_clear (&res); -__MU:mp_clear (&mu); -__M: - for (x = 0; x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} - -/* End: bn_mp_exptmod.c */ - -/* Start: bn_mp_exptmod_fast.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes Y == G^X mod P, HAC pp.616, Algorithm 14.85 - * - * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. - * The value of k changes based on the size of the exponent. - * - * Uses Montgomery or Diminished Radix reduction [whichever appropriate] - */ -int -mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -{ - mp_int M[256], res; - mp_digit buf, mp; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - int (*redux)(mp_int*,mp_int*,mp_digit); - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - - /* init G array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init (&M[x])) != MP_OKAY) { - for (y = 0; y < x; y++) { - mp_clear (&M[y]); - } - return err; - } - } - - if (redmode == 0) { - /* now setup montgomery */ - if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { - goto __M; - } - redux = mp_montgomery_reduce; - } else { - /* setup DR reduction */ - mp_dr_setup(P, &mp); - redux = mp_dr_reduce; - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto __RES; - } - - /* create M table - * - * The M table contains powers of the input base, e.g. M[x] = G^x mod P - * - * The first half of the table is not computed though accept for M[0] and M[1] - */ - - if (redmode == 0) { - /* now we need R mod m */ - if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { - goto __RES; - } - - /* now set M[1] to G * R mod m */ - if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { - goto __RES; - } - } else { - mp_set(&res, 1); - if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { - goto __RES; - } - } - - /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __RES; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&M[x], P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 0; - buf = 0; - digidx = X->used - 1; - bitcpy = bitbuf = 0; - - bitcnt = 1; - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) - continue; - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - - /* empty window and reset */ - bitcpy = bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = redux (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - } - } - - if (redmode == 0) { - /* fixup result */ - if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { - goto __RES; - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -__RES:mp_clear (&res); -__M: - for (x = 0; x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} - -/* End: bn_mp_exptmod_fast.c */ - -/* Start: bn_mp_expt_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calculate c = a^b using a square-multiply algorithm */ -int -mp_expt_d (mp_int * a, mp_digit b, mp_int * c) -{ - int res, x; - mp_int g; - - if ((res = mp_init_copy (&g, a)) != MP_OKAY) { - return res; - } - - /* set initial result */ - mp_set (c, 1); - - for (x = 0; x < (int) DIGIT_BIT; x++) { - /* square */ - if ((res = mp_sqr (c, c)) != MP_OKAY) { - mp_clear (&g); - return res; - } - - /* if the bit is set multiply */ - if ((b & (mp_digit) (1 << (DIGIT_BIT - 1))) != 0) { - if ((res = mp_mul (c, &g, c)) != MP_OKAY) { - mp_clear (&g); - return res; - } - } - - /* shift to next bit */ - b <<= 1; - } - - mp_clear (&g); - return MP_OKAY; -} - -/* End: bn_mp_expt_d.c */ - -/* Start: bn_mp_gcd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] - */ -int -mp_gcd (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int u, v, t; - int k, res, neg; - - /* either zero than gcd is the largest */ - if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { - return mp_copy (b, c); - } - if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { - return mp_copy (a, c); - } - if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { - mp_set (c, 1); - return MP_OKAY; - } - - /* if both are negative they share (-1) as a common divisor */ - neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; - - if ((res = mp_init_copy (&u, a)) != MP_OKAY) { - return res; - } - - if ((res = mp_init_copy (&v, b)) != MP_OKAY) { - goto __U; - } - - /* must be positive for the remainder of the algorithm */ - u.sign = v.sign = MP_ZPOS; - - if ((res = mp_init (&t)) != MP_OKAY) { - goto __V; - } - - /* B1. Find power of two */ - k = 0; - while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { - ++k; - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __T; - } - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __T; - } - } - - /* B2. Initialize */ - if (mp_isodd(&u) == 1) { - /* t = -v */ - if ((res = mp_copy (&v, &t)) != MP_OKAY) { - goto __T; - } - t.sign = MP_NEG; - } else { - /* t = u */ - if ((res = mp_copy (&u, &t)) != MP_OKAY) { - goto __T; - } - } - - do { - /* B3 (and B4). Halve t, if even */ - while (t.used != 0 && mp_iseven(&t) == 1) { - if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { - goto __T; - } - } - - /* B5. if t>0 then u=t otherwise v=-t */ - if (t.used != 0 && t.sign != MP_NEG) { - if ((res = mp_copy (&t, &u)) != MP_OKAY) { - goto __T; - } - } else { - if ((res = mp_copy (&t, &v)) != MP_OKAY) { - goto __T; - } - v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; - } - - /* B6. t = u - v, if t != 0 loop otherwise terminate */ - if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { - goto __T; - } - } - while (t.used != 0); - - if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { - goto __T; - } - - mp_exch (&u, c); - c->sign = neg; - res = MP_OKAY; -__T:mp_clear (&t); -__V:mp_clear (&u); -__U:mp_clear (&v); - return res; -} - -/* End: bn_mp_gcd.c */ - -/* Start: bn_mp_grow.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* grow as required */ -int -mp_grow (mp_int * a, int size) -{ - int i, n; - - /* if the alloc size is smaller alloc more ram */ - if (a->alloc < size) { - /* ensure there are always at least MP_PREC digits extra on top */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); - - a->dp = OPT_CAST XREALLOC (a->dp, sizeof (mp_digit) * size); - if (a->dp == NULL) { - return MP_MEM; - } - - /* zero excess digits */ - n = a->alloc; - a->alloc = size; - for (i = n; i < a->alloc; i++) { - a->dp[i] = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_grow.c */ - -/* Start: bn_mp_init.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* init a new bigint */ -int -mp_init (mp_int * a) -{ - - /* allocate ram required and clear it */ - a->dp = OPT_CAST XCALLOC (sizeof (mp_digit), MP_PREC); - if (a->dp == NULL) { - return MP_MEM; - } - - /* set the used to zero, allocated digit to the default precision - * and sign to positive */ - a->used = 0; - a->alloc = MP_PREC; - a->sign = MP_ZPOS; - - return MP_OKAY; -} - -/* End: bn_mp_init.c */ - -/* Start: bn_mp_init_copy.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* creates "a" then copies b into it */ -int -mp_init_copy (mp_int * a, mp_int * b) -{ - int res; - - if ((res = mp_init (a)) != MP_OKAY) { - return res; - } - return mp_copy (b, a); -} - -/* End: bn_mp_init_copy.c */ - -/* Start: bn_mp_init_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* init a mp_init and grow it to a given size */ -int -mp_init_size (mp_int * a, int size) -{ - - /* pad size so there are always extra digits */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); - - /* alloc mem */ - a->dp = OPT_CAST XCALLOC (sizeof (mp_digit), size); - if (a->dp == NULL) { - return MP_MEM; - } - a->used = 0; - a->alloc = size; - a->sign = MP_ZPOS; - - return MP_OKAY; -} - -/* End: bn_mp_init_size.c */ - -/* Start: bn_mp_invmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -int -mp_invmod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x, y, u, v, A, B, C, D; - int res; - - /* b cannot be negative */ - if (b->sign == MP_NEG) { - return MP_VAL; - } - - /* if the modulus is odd we can use a faster routine instead */ - if (mp_iseven (b) == 0) { - return fast_mp_invmod (a, b, c); - } - - if ((res = mp_init (&x)) != MP_OKAY) { - goto __ERR; - } - - if ((res = mp_init (&y)) != MP_OKAY) { - goto __X; - } - - if ((res = mp_init (&u)) != MP_OKAY) { - goto __Y; - } - - if ((res = mp_init (&v)) != MP_OKAY) { - goto __U; - } - - if ((res = mp_init (&A)) != MP_OKAY) { - goto __V; - } - - if ((res = mp_init (&B)) != MP_OKAY) { - goto __A; - } - - if ((res = mp_init (&C)) != MP_OKAY) { - goto __B; - } - - if ((res = mp_init (&D)) != MP_OKAY) { - goto __C; - } - - /* x = a, y = b */ - if ((res = mp_copy (a, &x)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (b, &y)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_abs (&x, &x)) != MP_OKAY) { - goto __D; - } - - /* 2. [modified] if x,y are both even then return an error! */ - if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { - res = MP_VAL; - goto __D; - } - - /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ - if ((res = mp_copy (&x, &u)) != MP_OKAY) { - goto __D; - } - if ((res = mp_copy (&y, &v)) != MP_OKAY) { - goto __D; - } - mp_set (&A, 1); - mp_set (&D, 1); - - -top: - /* 4. while u is even do */ - while (mp_iseven (&u) == 1) { - /* 4.1 u = u/2 */ - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __D; - } - /* 4.2 if A or B is odd then */ - if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { - /* A = (A+y)/2, B = (B-x)/2 */ - if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { - goto __D; - } - if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __D; - } - } - /* A = A/2, B = B/2 */ - if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { - goto __D; - } - if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { - goto __D; - } - } - - - /* 5. while v is even do */ - while (mp_iseven (&v) == 1) { - /* 5.1 v = v/2 */ - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __D; - } - /* 5.2 if C,D are even then */ - if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { - /* C = (C+y)/2, D = (D-x)/2 */ - if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { - goto __D; - } - if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __D; - } - } - /* C = C/2, D = D/2 */ - if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { - goto __D; - } - if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { - goto __D; - } - } - - /* 6. if u >= v then */ - if (mp_cmp (&u, &v) != MP_LT) { - /* u = u - v, A = A - C, B = B - D */ - if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { - goto __D; - } - } else { - /* v - v - u, C = C - A, D = D - B */ - if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { - goto __D; - } - - if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { - goto __D; - } - } - - /* if not zero goto step 4 */ - if (mp_iszero (&u) == 0) - goto top; - - /* now a = C, b = D, gcd == g*v */ - - /* if v != 1 then there is no inverse */ - if (mp_cmp_d (&v, 1) != MP_EQ) { - res = MP_VAL; - goto __D; - } - - /* a is now the inverse */ - mp_exch (&C, c); - res = MP_OKAY; - -__D:mp_clear (&D); -__C:mp_clear (&C); -__B:mp_clear (&B); -__A:mp_clear (&A); -__V:mp_clear (&v); -__U:mp_clear (&u); -__Y:mp_clear (&y); -__X:mp_clear (&x); -__ERR: - return res; -} - -/* End: bn_mp_invmod.c */ - -/* Start: bn_mp_jacobi.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes the jacobi c = (a | n) (or Legendre if b is prime) - * HAC pp. 73 Algorithm 2.149 - */ -int -mp_jacobi (mp_int * a, mp_int * n, int *c) -{ - mp_int a1, n1, e; - int s, r, res; - mp_digit residue; - - /* step 1. if a == 0, return 0 */ - if (mp_iszero (a) == 1) { - *c = 0; - return MP_OKAY; - } - - /* step 2. if a == 1, return 1 */ - if (mp_cmp_d (a, 1) == MP_EQ) { - *c = 1; - return MP_OKAY; - } - - /* default */ - s = 0; - - /* step 3. write a = a1 * 2^e */ - if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&n1)) != MP_OKAY) { - goto __A1; - } - - if ((res = mp_init (&e)) != MP_OKAY) { - goto __N1; - } - - while (mp_iseven (&a1) == 1) { - if ((res = mp_add_d (&e, 1, &e)) != MP_OKAY) { - goto __E; - } - - if ((res = mp_div_2 (&a1, &a1)) != MP_OKAY) { - goto __E; - } - } - - /* step 4. if e is even set s=1 */ - if (mp_iseven (&e) == 1) { - s = 1; - } else { - /* else set s=1 if n = 1/7 (mod 8) or s=-1 if n = 3/5 (mod 8) */ - if ((res = mp_mod_d (n, 8, &residue)) != MP_OKAY) { - goto __E; - } - - if (residue == 1 || residue == 7) { - s = 1; - } else if (residue == 3 || residue == 5) { - s = -1; - } - } - - /* step 5. if n == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ - if ((res = mp_mod_d (n, 4, &residue)) != MP_OKAY) { - goto __E; - } - if (residue == 3) { - if ((res = mp_mod_d (&a1, 4, &residue)) != MP_OKAY) { - goto __E; - } - if (residue == 3) { - s = -s; - } - } - - /* if a1 == 1 we're done */ - if (mp_cmp_d (&a1, 1) == MP_EQ) { - *c = s; - } else { - /* n1 = n mod a1 */ - if ((res = mp_mod (n, &a1, &n1)) != MP_OKAY) { - goto __E; - } - if ((res = mp_jacobi (&n1, &a1, &r)) != MP_OKAY) { - goto __E; - } - *c = s * r; - } - - /* done */ - res = MP_OKAY; -__E:mp_clear (&e); -__N1:mp_clear (&n1); -__A1:mp_clear (&a1); - return res; -} - -/* End: bn_mp_jacobi.c */ - -/* Start: bn_mp_karatsuba_mul.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = |a| * |b| using Karatsuba Multiplication using three half size multiplications - * - * Let B represent the radix [e.g. 2**DIGIT_BIT] and let n represent half of the number of digits in the min(a,b) - * - * a = a1 * B^n + a0 - * b = b1 * B^n + b0 - * - * Then, a * b => a1b1 * B^2n + ((a1 - b1)(a0 - b0) + a0b0 + a1b1) * B + a0b0 - * - * Note that a1b1 and a0b0 are used twice and only need to be computed once. So in total - * three half size (half # of digit) multiplications are performed, a0b0, a1b1 and (a1-b1)(a0-b0) - * - * Note that a multiplication of half the digits requires 1/4th the number of single precision - * multiplications so in total after one call 25% of the single precision multiplications are saved. - * Note also that the call to mp_mul can end up back in this function if the a0, a1, b0, or b1 are above - * the threshold. This is known as divide-and-conquer and leads to the famous O(N^lg(3)) or O(N^1.584) work which - * is asymptopically lower than the standard O(N^2) that the baseline/comba methods use. Generally though the - * overhead of this method doesn't pay off until a certain size (N ~ 80) is reached. - */ -int -mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int x0, x1, y0, y1, t1, t2, x0y0, x1y1; - int B, err; - - err = MP_MEM; - - /* min # of digits */ - B = MIN (a->used, b->used); - - /* now divide in two */ - B = B / 2; - - /* init copy all the temps */ - if (mp_init_size (&x0, B) != MP_OKAY) - goto ERR; - if (mp_init_size (&x1, a->used - B) != MP_OKAY) - goto X0; - if (mp_init_size (&y0, B) != MP_OKAY) - goto X1; - if (mp_init_size (&y1, b->used - B) != MP_OKAY) - goto Y0; - - /* init temps */ - if (mp_init_size (&t1, B * 2) != MP_OKAY) - goto Y1; - if (mp_init_size (&t2, B * 2) != MP_OKAY) - goto T1; - if (mp_init_size (&x0y0, B * 2) != MP_OKAY) - goto T2; - if (mp_init_size (&x1y1, B * 2) != MP_OKAY) - goto X0Y0; - - /* now shift the digits */ - x0.sign = x1.sign = a->sign; - y0.sign = y1.sign = b->sign; - - x0.used = y0.used = B; - x1.used = a->used - B; - y1.used = b->used - B; - - { - register int x; - register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; - - /* we copy the digits directly instead of using higher level functions - * since we also need to shift the digits - */ - tmpa = a->dp; - tmpb = b->dp; - - tmpx = x0.dp; - tmpy = y0.dp; - for (x = 0; x < B; x++) { - *tmpx++ = *tmpa++; - *tmpy++ = *tmpb++; - } - - tmpx = x1.dp; - for (x = B; x < a->used; x++) { - *tmpx++ = *tmpa++; - } - - tmpy = y1.dp; - for (x = B; x < b->used; x++) { - *tmpy++ = *tmpb++; - } - } - - /* only need to clamp the lower words since by definition the upper words x1/y1 must - * have a known number of digits - */ - mp_clamp (&x0); - mp_clamp (&y0); - - /* now calc the products x0y0 and x1y1 */ - if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) - goto X1Y1; /* x0y0 = x0*y0 */ - if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) - goto X1Y1; /* x1y1 = x1*y1 */ - - /* now calc x1-x0 and y1-y0 */ - if (mp_sub (&x1, &x0, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x1 - x0 */ - if (mp_sub (&y1, &y0, &t2) != MP_OKAY) - goto X1Y1; /* t2 = y1 - y0 */ - if (mp_mul (&t1, &t2, &t1) != MP_OKAY) - goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ - - /* add x0y0 */ - if (mp_add (&x0y0, &x1y1, &t2) != MP_OKAY) - goto X1Y1; /* t2 = x0y0 + x1y1 */ - if (mp_sub (&t2, &t1, &t1) != MP_OKAY) - goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ - - /* shift by B */ - if (mp_lshd (&t1, B) != MP_OKAY) - goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< - -/* Karatsuba squaring, computes b = a*a using three half size squarings - * - * See comments of mp_karatsuba_mul for details. It is essentially the same algorithm - * but merely tuned to perform recursive squarings. - */ -int -mp_karatsuba_sqr (mp_int * a, mp_int * b) -{ - mp_int x0, x1, t1, t2, x0x0, x1x1; - int B, err; - - err = MP_MEM; - - /* min # of digits */ - B = a->used; - - /* now divide in two */ - B = B / 2; - - /* init copy all the temps */ - if (mp_init_size (&x0, B) != MP_OKAY) - goto ERR; - if (mp_init_size (&x1, a->used - B) != MP_OKAY) - goto X0; - - /* init temps */ - if (mp_init_size (&t1, a->used * 2) != MP_OKAY) - goto X1; - if (mp_init_size (&t2, a->used * 2) != MP_OKAY) - goto T1; - if (mp_init_size (&x0x0, B * 2) != MP_OKAY) - goto T2; - if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) - goto X0X0; - - { - register int x; - register mp_digit *dst, *src; - - src = a->dp; - - /* now shift the digits */ - dst = x0.dp; - for (x = 0; x < B; x++) { - *dst++ = *src++; - } - - dst = x1.dp; - for (x = B; x < a->used; x++) { - *dst++ = *src++; - } - } - - x0.used = B; - x1.used = a->used - B; - - mp_clamp (&x0); - - /* now calc the products x0*x0 and x1*x1 */ - if (mp_sqr (&x0, &x0x0) != MP_OKAY) - goto X1X1; /* x0x0 = x0*x0 */ - if (mp_sqr (&x1, &x1x1) != MP_OKAY) - goto X1X1; /* x1x1 = x1*x1 */ - - /* now calc x1-x0 and y1-y0 */ - if (mp_sub (&x1, &x0, &t1) != MP_OKAY) - goto X1X1; /* t1 = x1 - x0 */ - if (mp_sqr (&t1, &t1) != MP_OKAY) - goto X1X1; /* t1 = (x1 - x0) * (y1 - y0) */ - - /* add x0y0 */ - if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) - goto X1X1; /* t2 = x0y0 + x1y1 */ - if (mp_sub (&t2, &t1, &t1) != MP_OKAY) - goto X1X1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ - - /* shift by B */ - if (mp_lshd (&t1, B) != MP_OKAY) - goto X1X1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< - -/* computes least common multiple as a*b/(a, b) */ -int -mp_lcm (mp_int * a, mp_int * b, mp_int * c) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_mul (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - if ((res = mp_gcd (a, b, c)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - res = mp_div (&t, c, c, NULL); - mp_clear (&t); - return res; -} - -/* End: bn_mp_lcm.c */ - -/* Start: bn_mp_lshd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift left a certain amount of digits */ -int -mp_lshd (mp_int * a, int b) -{ - int x, res; - - - /* if its less than zero return */ - if (b <= 0) { - return MP_OKAY; - } - - /* grow to fit the new digits */ - if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { - return res; - } - - { - register mp_digit *tmpa, *tmpaa; - - /* increment the used by the shift amount than copy upwards */ - a->used += b; - - /* top */ - tmpa = a->dp + a->used - 1; - - /* base */ - tmpaa = a->dp + a->used - 1 - b; - - /* much like mp_rshd this is implemented using a sliding window - * except the window goes the otherway around. Copying from - * the bottom to the top. see bn_mp_rshd.c for more info. - */ - for (x = a->used - 1; x >= b; x--) { - *tmpa-- = *tmpaa--; - } - - /* zero the lower digits */ - tmpa = a->dp; - for (x = 0; x < b; x++) { - *tmpa++ = 0; - } - } - return MP_OKAY; -} - -/* End: bn_mp_lshd.c */ - -/* Start: bn_mp_mod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = a mod b, 0 <= c < b */ -int -mp_mod (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int t; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - if (t.sign == MP_NEG) { - res = mp_add (b, &t, c); - } else { - res = MP_OKAY; - mp_exch (&t, c); - } - - mp_clear (&t); - return res; -} - -/* End: bn_mp_mod.c */ - -/* Start: bn_mp_mod_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calc a value mod 2^b */ -int -mp_mod_2d (mp_int * a, int b, mp_int * c) -{ - int x, res; - - - /* if b is <= 0 then zero the int */ - if (b <= 0) { - mp_zero (c); - return MP_OKAY; - } - - /* if the modulus is larger than the value than return */ - if (b > (int) (a->used * DIGIT_BIT)) { - res = mp_copy (a, c); - return res; - } - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - - /* zero digits above the last digit of the modulus */ - for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { - c->dp[x] = 0; - } - /* clear the digit that is not completely outside/inside the modulus */ - c->dp[b / DIGIT_BIT] &= - (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mod_2d.c */ - -/* Start: bn_mp_mod_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -int -mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) -{ - mp_int t, t2; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - mp_clear (&t); - return res; - } - - mp_set (&t, b); - mp_div (a, &t, NULL, &t2); - - if (t2.sign == MP_NEG) { - if ((res = mp_add_d (&t2, b, &t2)) != MP_OKAY) { - mp_clear (&t); - mp_clear (&t2); - return res; - } - } - *c = t2.dp[0]; - mp_clear (&t); - mp_clear (&t2); - return MP_OKAY; -} - -/* End: bn_mp_mod_d.c */ - -/* Start: bn_mp_montgomery_calc_normalization.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* calculates a = B^n mod b for Montgomery reduction - * Where B is the base [e.g. 2^DIGIT_BIT]. - * B^n mod b is computed by first computing - * A = B^(n-1) which doesn't require a reduction but a simple OR. - * then C = A * B = B^n is computed by performing upto DIGIT_BIT - * shifts with subtractions when the result is greater than b. - * - * The method is slightly modified to shift B unconditionally upto just under - * the leading bit of b. This saves alot of multiple precision shifting. - */ -int -mp_montgomery_calc_normalization (mp_int * a, mp_int * b) -{ - int x, bits, res; - - /* how many bits of last digit does b use */ - bits = mp_count_bits (b) % DIGIT_BIT; - - /* compute A = B^(n-1) * 2^(bits-1) */ - if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { - return res; - } - - /* now compute C = A * B mod b */ - for (x = bits - 1; x < DIGIT_BIT; x++) { - if ((res = mp_mul_2 (a, a)) != MP_OKAY) { - return res; - } - if (mp_cmp_mag (a, b) != MP_LT) { - if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { - return res; - } - } - } - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_calc_normalization.c */ - -/* Start: bn_mp_montgomery_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes xR^-1 == x (mod N) via Montgomery Reduction */ -int -mp_montgomery_reduce (mp_int * a, mp_int * m, mp_digit mp) -{ - int ix, res, digs; - mp_digit ui; - - digs = m->used * 2 + 1; - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_mp_montgomery_reduce (a, m, mp); - } - - if (a->alloc < m->used * 2 + 1) { - if ((res = mp_grow (a, m->used * 2 + 1)) != MP_OKAY) { - return res; - } - } - a->used = m->used * 2 + 1; - - for (ix = 0; ix < m->used; ix++) { - /* ui = ai * m' mod b */ - ui = (a->dp[ix] * mp) & MP_MASK; - - /* a = a + ui * m * b^i */ - { - register int iy; - register mp_digit *tmpx, *tmpy, mu; - register mp_word r; - - /* aliases */ - tmpx = m->dp; - tmpy = a->dp + ix; - - mu = 0; - for (iy = 0; iy < m->used; iy++) { - r = ((mp_word) ui) * ((mp_word) * tmpx++) + ((mp_word) mu) + ((mp_word) * tmpy); - mu = (r >> ((mp_word) DIGIT_BIT)); - *tmpy++ = (r & ((mp_word) MP_MASK)); - } - /* propagate carries */ - while (mu) { - *tmpy += mu; - mu = (*tmpy >> DIGIT_BIT) & 1; - *tmpy++ &= MP_MASK; - } - } - } - - /* A = A/b^n */ - mp_rshd (a, m->used); - - /* if A >= m then A = A - m */ - if (mp_cmp_mag (a, m) != MP_LT) { - return s_mp_sub (a, m, a); - } - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_reduce.c */ - -/* Start: bn_mp_montgomery_setup.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* setups the montgomery reduction stuff */ -int -mp_montgomery_setup (mp_int * a, mp_digit * mp) -{ - unsigned long x, b; - -/* fast inversion mod 2^32 - * - * Based on the fact that - * - * XA = 1 (mod 2^n) => (X(2-XA)) A = 1 (mod 2^2n) - * => 2*X*A - X*X*A*A = 1 - * => 2*(1) - (1) = 1 - */ - b = a->dp[0]; - - if ((b & 1) == 0) { - return MP_VAL; - } - - x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2^4 */ - x *= 2 - b * x; /* here x*a==1 mod 2^8 */ - x *= 2 - b * x; /* here x*a==1 mod 2^16; each step doubles the nb of bits */ - x *= 2 - b * x; /* here x*a==1 mod 2^32 */ - - /* t = -1/m mod b */ - *mp = ((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - (x & MP_MASK); - - return MP_OKAY; -} - -/* End: bn_mp_montgomery_setup.c */ - -/* Start: bn_mp_mul.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level multiplication (handles sign) */ -int -mp_mul (mp_int * a, mp_int * b, mp_int * c) -{ - int res, neg; - neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; - if (MIN (a->used, b->used) > KARATSUBA_MUL_CUTOFF) { - res = mp_karatsuba_mul (a, b, c); - } else { - - /* can we use the fast multiplier? - * - * The fast multiplier can be used if the output will have less than - * 512 digits and the number of digits won't affect carry propagation - */ - int digs = a->used + b->used + 1; - - if ((digs < 512) - && digs < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - res = fast_s_mp_mul_digs (a, b, c, digs); - } else { - res = s_mp_mul (a, b, c); - } - - } - c->sign = neg; - return res; -} - -/* End: bn_mp_mul.c */ - -/* Start: bn_mp_mulmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a * b (mod c) */ -int -mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_mul (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_mulmod.c */ - -/* Start: bn_mp_mul_2.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = a*2 */ -int -mp_mul_2 (mp_int * a, mp_int * b) -{ - int x, res, oldused; - - /* Optimization: should copy and shift at the same time */ - - if (b->alloc < a->used) { - if ((res = mp_grow (b, a->used)) != MP_OKAY) { - return res; - } - } - - oldused = b->used; - b->used = a->used; - - /* shift any bit count < DIGIT_BIT */ - { - register mp_digit r, rr, *tmpa, *tmpb; - - /* alias for source */ - tmpa = a->dp; - - /* alias for dest */ - tmpb = b->dp; - - /* carry */ - r = 0; - for (x = 0; x < b->used; x++) { - - /* get what will be the *next* carry bit from the MSB of the current digit */ - rr = *tmpa >> (DIGIT_BIT - 1); - - /* now shift up this digit, add in the carry [from the previous] */ - *tmpb++ = ((*tmpa++ << 1) | r) & MP_MASK; - - /* copy the carry that would be from the source digit into the next iteration */ - r = rr; - } - - /* new leading digit? */ - if (r != 0) { - /* do we have to grow to accomodate the new digit? */ - if (b->alloc == b->used) { - if ((res = mp_grow (b, b->used + 1)) != MP_OKAY) { - return res; - } - - /* after the grow *tmpb is no longer valid so we have to reset it! - * (this bug took me about 17 minutes to find...!) - */ - tmpb = b->dp + b->used; - } - /* add a MSB which is always 1 at this point */ - *tmpb = 1; - ++b->used; - } - - /* now zero any excess digits on the destination that we didn't write to */ - tmpb = b->dp + b->used; - for (x = b->used; x < oldused; x++) { - *tmpb++ = 0; - } - } - b->sign = a->sign; - return MP_OKAY; -} - -/* End: bn_mp_mul_2.c */ - -/* Start: bn_mp_mul_2d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift left by a certain bit count */ -int -mp_mul_2d (mp_int * a, int b, mp_int * c) -{ - mp_digit d, r, rr; - int x, res; - - /* copy */ - if ((res = mp_copy (a, c)) != MP_OKAY) { - return res; - } - - if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { - return res; - } - - /* shift by as many digits in the bit count */ - if (b >= DIGIT_BIT) { - if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { - return res; - } - } - c->used = c->alloc; - - /* shift any bit count < DIGIT_BIT */ - d = (mp_digit) (b % DIGIT_BIT); - if (d != 0) { - register mp_digit *tmpc, mask; - - /* bitmask for carries */ - mask = (1U << d) - 1U; - - /* alias */ - tmpc = c->dp; - - /* carry */ - r = 0; - for (x = 0; x < c->used; x++) { - /* get the higher bits of the current word */ - rr = (*tmpc >> (DIGIT_BIT - d)) & mask; - - /* shift the current word and OR in the carry */ - *tmpc = ((*tmpc << d) | r) & MP_MASK; - ++tmpc; - - /* set the carry to the carry bits of the current word */ - r = rr; - } - } - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mul_2d.c */ - -/* Start: bn_mp_mul_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiply by a digit */ -int -mp_mul_d (mp_int * a, mp_digit b, mp_int * c) -{ - int res, pa, olduse; - - pa = a->used; - if (c->alloc < pa + 1) { - if ((res = mp_grow (c, pa + 1)) != MP_OKAY) { - return res; - } - } - - olduse = c->used; - c->used = pa + 1; - - { - register mp_digit u, *tmpa, *tmpc; - register mp_word r; - register int ix; - - tmpc = c->dp + c->used; - for (ix = c->used; ix < olduse; ix++) { - *tmpc++ = 0; - } - - tmpa = a->dp; - tmpc = c->dp; - - u = 0; - for (ix = 0; ix < pa; ix++) { - r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); - *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - *tmpc = u; - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_mp_mul_d.c */ - -/* Start: bn_mp_neg.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* b = -a */ -int -mp_neg (mp_int * a, mp_int * b) -{ - int res; - if ((res = mp_copy (a, b)) != MP_OKAY) { - return res; - } - b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; - return MP_OKAY; -} - -/* End: bn_mp_neg.c */ - -/* Start: bn_mp_n_root.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* find the n'th root of an integer - * - * Result found such that (c)^b <= a and (c+1)^b > a - * - * This algorithm uses Newton's approximation x[i+1] = x[i] - f(x[i])/f'(x[i]) - * which will find the root in log(N) time where each step involves a fair bit. This - * is not meant to find huge roots [square and cube at most]. - */ -int -mp_n_root (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t1, t2, t3; - int res, neg; - - /* input must be positive if b is even */ - if ((b & 1) == 0 && a->sign == MP_NEG) { - return MP_VAL; - } - - if ((res = mp_init (&t1)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&t2)) != MP_OKAY) { - goto __T1; - } - - if ((res = mp_init (&t3)) != MP_OKAY) { - goto __T2; - } - - /* if a is negative fudge the sign but keep track */ - neg = a->sign; - a->sign = MP_ZPOS; - - /* t2 = 2 */ - mp_set (&t2, 2); - - do { - /* t1 = t2 */ - if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { - goto __T3; - } - - /* t2 = t1 - ((t1^b - a) / (b * t1^(b-1))) */ - if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) */ - goto __T3; - } - - /* numerator */ - if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { /* t2 = t1^b */ - goto __T3; - } - - if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { /* t2 = t1^b - a */ - goto __T3; - } - - if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) * b */ - goto __T3; - } - - if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { /* t3 = (t1^b - a)/(b * t1^(b-1)) */ - goto __T3; - } - - if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { - goto __T3; - } - } - while (mp_cmp (&t1, &t2) != MP_EQ); - - /* result can be off by a few so check */ - for (;;) { - if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { - goto __T3; - } - - if (mp_cmp (&t2, a) == MP_GT) { - if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { - goto __T3; - } - } else { - break; - } - } - - /* reset the sign of a first */ - a->sign = neg; - - /* set the result */ - mp_exch (&t1, c); - - /* set the sign of the result */ - c->sign = neg; - - res = MP_OKAY; - -__T3:mp_clear (&t3); -__T2:mp_clear (&t2); -__T1:mp_clear (&t1); - return res; -} - -/* End: bn_mp_n_root.c */ - -/* Start: bn_mp_or.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* OR two ints together */ -int -mp_or (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] |= x->dp[ix]; - } - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_or.c */ - -/* Start: bn_mp_prime_fermat.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* performs one Fermat test. - * - * If "a" were prime then b^a == b (mod a) since the order of - * the multiplicative sub-group would be phi(a) = a-1. That means - * it would be the same as b^(a mod (a-1)) == b^1 == b (mod a). - * - * Sets result to 1 if the congruence holds, or zero otherwise. - */ -int -mp_prime_fermat (mp_int * a, mp_int * b, int *result) -{ - mp_int t; - int err; - - /* default to fail */ - *result = 0; - - /* init t */ - if ((err = mp_init (&t)) != MP_OKAY) { - return err; - } - - /* compute t = b^a mod a */ - if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { - goto __T; - } - - /* is it equal to b? */ - if (mp_cmp (&t, b) == MP_EQ) { - *result = 1; - } - - err = MP_OKAY; -__T:mp_clear (&t); - return err; -} - -/* End: bn_mp_prime_fermat.c */ - -/* Start: bn_mp_prime_is_divisible.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines if an integers is divisible by one of the first 256 primes or not - * - * sets result to 0 if not, 1 if yes - */ -int -mp_prime_is_divisible (mp_int * a, int *result) -{ - int err, ix; - mp_digit res; - - /* default to not */ - *result = 0; - - for (ix = 0; ix < 256; ix++) { - /* is it equal to the prime? */ - if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { - *result = 1; - return MP_OKAY; - } - - /* what is a mod __prime_tab[ix] */ - if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { - return err; - } - - /* is the residue zero? */ - if (res == 0) { - *result = 1; - return MP_OKAY; - } - } - - return MP_OKAY; -} - -/* End: bn_mp_prime_is_divisible.c */ - -/* Start: bn_mp_prime_is_prime.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* performs a variable number of rounds of Miller-Rabin - * - * Probability of error after t rounds is no more than - * (1/4)^t when 1 <= t <= 256 - * - * Sets result to 1 if probably prime, 0 otherwise - */ -int -mp_prime_is_prime (mp_int * a, int t, int *result) -{ - mp_int b; - int ix, err, res; - - /* default to no */ - *result = 0; - - /* valid value of t? */ - if (t < 1 || t > 256) { - return MP_VAL; - } - - /* first perform trial division */ - if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { - return err; - } - if (res == 1) { - return MP_OKAY; - } - - /* now perform the miller-rabin rounds */ - if ((err = mp_init (&b)) != MP_OKAY) { - return err; - } - - for (ix = 0; ix < t; ix++) { - /* set the prime */ - mp_set (&b, __prime_tab[ix]); - - if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { - goto __B; - } - - if (res == 0) { - goto __B; - } - } - - /* passed the test */ - *result = 1; -__B:mp_clear (&b); - return err; -} - -/* End: bn_mp_prime_is_prime.c */ - -/* Start: bn_mp_prime_miller_rabin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* Miller-Rabin test of "a" to the base of "b" as described in - * HAC pp. 139 Algorithm 4.24 - * - * Sets result to 0 if definitely composite or 1 if probably prime. - * Randomly the chance of error is no more than 1/4 and often - * very much lower. - */ -int -mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) -{ - mp_int n1, y, r; - int s, j, err; - - /* default */ - *result = 0; - - /* get n1 = a - 1 */ - if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { - return err; - } - if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { - goto __N1; - } - - /* set 2^s * r = n1 */ - if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { - goto __N1; - } - s = 0; - while (mp_iseven (&r) == 1) { - ++s; - if ((err = mp_div_2 (&r, &r)) != MP_OKAY) { - goto __R; - } - } - - /* compute y = b^r mod a */ - if ((err = mp_init (&y)) != MP_OKAY) { - goto __R; - } - if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { - goto __Y; - } - - /* if y != 1 and y != n1 do */ - if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { - j = 1; - /* while j <= s-1 and y != n1 */ - while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { - if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { - goto __Y; - } - - /* if y == 1 then composite */ - if (mp_cmp_d (&y, 1) == MP_EQ) { - goto __Y; - } - - ++j; - } - - /* if y != n1 then composite */ - if (mp_cmp (&y, &n1) != MP_EQ) { - goto __Y; - } - } - - /* probably prime now */ - *result = 1; -__Y:mp_clear (&y); -__R:mp_clear (&r); -__N1:mp_clear (&n1); - return err; -} - -/* End: bn_mp_prime_miller_rabin.c */ - -/* Start: bn_mp_prime_next_prime.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* finds the next prime after the number "a" using "t" trials - * of Miller-Rabin. - */ -int mp_prime_next_prime(mp_int *a, int t) -{ - int err, res; - - if (mp_iseven(a) == 1) { - /* force odd */ - if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { - return err; - } - } else { - /* force to next number */ - if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { - return err; - } - } - - for (;;) { - /* is this prime? */ - if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { - return err; - } - - if (res == 1) { - break; - } - - /* add two, next candidate */ - if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { - return err; - } - } - - return MP_OKAY; -} - - -/* End: bn_mp_prime_next_prime.c */ - -/* Start: bn_mp_rand.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* makes a pseudo-random int of a given size */ -int -mp_rand (mp_int * a, int digits) -{ - int res; - mp_digit d; - - mp_zero (a); - if (digits <= 0) { - return MP_OKAY; - } - - /* first place a random non-zero digit */ - do { - d = ((mp_digit) abs (rand ())); - } while (d == 0); - - if ((res = mp_add_d (a, d, a)) != MP_OKAY) { - return res; - } - - while (digits-- > 0) { - if ((res = mp_lshd (a, 1)) != MP_OKAY) { - return res; - } - - if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { - return res; - } - } - - return MP_OKAY; -} - -/* End: bn_mp_rand.c */ - -/* Start: bn_mp_read_signed_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* read signed bin, big endian, first byte is 0==positive or 1==negative */ -int -mp_read_signed_bin (mp_int * a, unsigned char *b, int c) -{ - int res; - - if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { - return res; - } - a->sign = ((b[0] == (unsigned char) 0) ? MP_ZPOS : MP_NEG); - return MP_OKAY; -} - -/* End: bn_mp_read_signed_bin.c */ - -/* Start: bn_mp_read_unsigned_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reads a unsigned char array, assumes the msb is stored first [big endian] */ -int -mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) -{ - int res; - mp_zero (a); - while (c-- > 0) { - if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { - return res; - } - - if (DIGIT_BIT != 7) { - a->dp[0] |= *b++; - a->used += 1; - } else { - a->dp[0] = (*b & MP_MASK); - a->dp[1] |= ((*b++ >> 7U) & 1); - a->used += 2; - } - } - mp_clamp (a); - return MP_OKAY; -} - -/* End: bn_mp_read_unsigned_bin.c */ - -/* Start: bn_mp_reduce.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* pre-calculate the value required for Barrett reduction - * For a given modulus "b" it calulates the value required in "a" - */ -int -mp_reduce_setup (mp_int * a, mp_int * b) -{ - int res; - - - if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { - return res; - } - res = mp_div (a, b, a, NULL); - return res; -} - -/* reduces x mod m, assumes 0 < x < m^2, mu is precomputed via mp_reduce_setup - * From HAC pp.604 Algorithm 14.42 - */ -int -mp_reduce (mp_int * x, mp_int * m, mp_int * mu) -{ - mp_int q; - int res, um = m->used; - - - if ((res = mp_init_copy (&q, x)) != MP_OKAY) { - return res; - } - - mp_rshd (&q, um - 1); /* q1 = x / b^(k-1) */ - - /* according to HAC this is optimization is ok */ - if (((unsigned long) m->used) > (1UL << (unsigned long) (DIGIT_BIT - 1UL))) { - if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { - goto CLEANUP; - } - } else { - if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { - goto CLEANUP; - } - } - - mp_rshd (&q, um + 1); /* q3 = q2 / b^(k+1) */ - - /* x = x mod b^(k+1), quick (no division) */ - if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { - goto CLEANUP; - } - - /* q = q * m mod b^(k+1), quick (no division) */ - if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { - goto CLEANUP; - } - - /* x = x - q */ - if ((res = mp_sub (x, &q, x)) != MP_OKAY) - goto CLEANUP; - - /* If x < 0, add b^(k+1) to it */ - if (mp_cmp_d (x, 0) == MP_LT) { - mp_set (&q, 1); - if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) - goto CLEANUP; - if ((res = mp_add (x, &q, x)) != MP_OKAY) - goto CLEANUP; - } - - /* Back off if it's too big */ - while (mp_cmp (x, m) != MP_LT) { - if ((res = s_mp_sub (x, m, x)) != MP_OKAY) - break; - } - -CLEANUP: - mp_clear (&q); - - return res; -} - -/* End: bn_mp_reduce.c */ - -/* Start: bn_mp_rshd.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shift right a certain amount of digits */ -void -mp_rshd (mp_int * a, int b) -{ - int x; - - /* if b <= 0 then ignore it */ - if (b <= 0) { - return; - } - - /* if b > used then simply zero it and return */ - if (a->used < b) { - mp_zero (a); - return; - } - - { - register mp_digit *tmpa, *tmpaa; - - /* shift the digits down */ - - /* base */ - tmpa = a->dp; - - /* offset into digits */ - tmpaa = a->dp + b; - - /* this is implemented as a sliding window where the window is b-digits long - * and digits from the top of the window are copied to the bottom - * - * e.g. - - b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> - /\ | ----> - \-------------------/ ----> - */ - for (x = 0; x < (a->used - b); x++) { - *tmpa++ = *tmpaa++; - } - - /* zero the top digits */ - for (; x < a->used; x++) { - *tmpa++ = 0; - } - } - mp_clamp (a); -} - -/* End: bn_mp_rshd.c */ - -/* Start: bn_mp_set.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set to a digit */ -void -mp_set (mp_int * a, mp_digit b) -{ - mp_zero (a); - a->dp[0] = b & MP_MASK; - a->used = (a->dp[0] != 0) ? 1 : 0; -} - -/* End: bn_mp_set.c */ - -/* Start: bn_mp_set_int.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set a 32-bit const */ -int -mp_set_int (mp_int * a, unsigned long b) -{ - int x, res; - - mp_zero (a); - - /* set four bits at a time, simplest solution to the what if DIGIT_BIT==7 case */ - for (x = 0; x < 8; x++) { - - /* shift the number up four bits */ - if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { - return res; - } - - /* OR in the top four bits of the source */ - a->dp[0] |= (b >> 28) & 15; - - /* shift the source up to the next four bits */ - b <<= 4; - - /* ensure that digits are not clamped off */ - a->used += 32 / DIGIT_BIT + 1; - } - - mp_clamp (a); - return MP_OKAY; -} - -/* End: bn_mp_set_int.c */ - -/* Start: bn_mp_shrink.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* shrink a bignum */ -int -mp_shrink (mp_int * a) -{ - if (a->alloc != a->used) { - if ((a->dp = OPT_CAST XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { - return MP_MEM; - } - a->alloc = a->used; - } - return MP_OKAY; -} - -/* End: bn_mp_shrink.c */ - -/* Start: bn_mp_signed_bin_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* get the size for an signed equivalent */ -int -mp_signed_bin_size (mp_int * a) -{ - return 1 + mp_unsigned_bin_size (a); -} - -/* End: bn_mp_signed_bin_size.c */ - -/* Start: bn_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* computes b = a*a */ -int -mp_sqr (mp_int * a, mp_int * b) -{ - int res; - if (a->used > KARATSUBA_SQR_CUTOFF) { - res = mp_karatsuba_sqr (a, b); - } else { - - /* can we use the fast multiplier? */ - if (((a->used * 2 + 1) < 512) - && a->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT) - 1))) { - res = fast_s_mp_sqr (a, b); - } else { - res = s_mp_sqr (a, b); - } - } - b->sign = MP_ZPOS; - return res; -} - -/* End: bn_mp_sqr.c */ - -/* Start: bn_mp_sqrmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* c = a * a (mod b) */ -int -mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_sqr (a, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, b, c); - mp_clear (&t); - return res; -} - -/* End: bn_mp_sqrmod.c */ - -/* Start: bn_mp_sub.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* high level subtraction (handles signs) */ -int -mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int sa, sb, res; - - - sa = a->sign; - sb = b->sign; - - /* handle four cases */ - if (sa == MP_ZPOS && sb == MP_ZPOS) { - /* both positive, a - b, but if b>a then we do -(b - a) */ - if (mp_cmp_mag (a, b) == MP_LT) { - /* b>a */ - res = s_mp_sub (b, a, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (a, b, c); - c->sign = MP_ZPOS; - } - } else if (sa == MP_ZPOS && sb == MP_NEG) { - /* a - -b == a + b */ - res = s_mp_add (a, b, c); - c->sign = MP_ZPOS; - } else if (sa == MP_NEG && sb == MP_ZPOS) { - /* -a - b == -(a + b) */ - res = s_mp_add (a, b, c); - c->sign = MP_NEG; - } else { - /* -a - -b == b - a, but if a>b == -(a - b) */ - if (mp_cmp_mag (a, b) == MP_GT) { - res = s_mp_sub (a, b, c); - c->sign = MP_NEG; - } else { - res = s_mp_sub (b, a, c); - c->sign = MP_ZPOS; - } - } - - return res; -} - -/* End: bn_mp_sub.c */ - -/* Start: bn_mp_submod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* d = a - b (mod c) */ -int -mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -{ - int res; - mp_int t; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - - if ((res = mp_sub (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); - return res; -} - -/* End: bn_mp_submod.c */ - -/* Start: bn_mp_sub_d.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* single digit subtraction */ -int -mp_sub_d (mp_int * a, mp_digit b, mp_int * c) -{ - mp_int t; - int res; - - - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } - mp_set (&t, b); - res = mp_sub (a, &t, c); - - mp_clear (&t); - return res; -} - -/* End: bn_mp_sub_d.c */ - -/* Start: bn_mp_to_signed_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* store in signed [big endian] format */ -int -mp_to_signed_bin (mp_int * a, unsigned char *b) -{ - int res; - - if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { - return res; - } - b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); - return MP_OKAY; -} - -/* End: bn_mp_to_signed_bin.c */ - -/* Start: bn_mp_to_unsigned_bin.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* store in unsigned [big endian] format */ -int -mp_to_unsigned_bin (mp_int * a, unsigned char *b) -{ - int x, res; - mp_int t; - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - x = 0; - while (mp_iszero (&t) == 0) { - if (DIGIT_BIT != 7) { - b[x++] = (unsigned char) (t.dp[0] & 255); - } else { - b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); - } - if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { - mp_clear (&t); - return res; - } - } - bn_reverse (b, x); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_to_unsigned_bin.c */ - -/* Start: bn_mp_unsigned_bin_size.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* get the size for an unsigned equivalent */ -int -mp_unsigned_bin_size (mp_int * a) -{ - int size = mp_count_bits (a); - return (size / 8 + ((size & 7) != 0 ? 1 : 0)); -} - -/* End: bn_mp_unsigned_bin_size.c */ - -/* Start: bn_mp_xor.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* XOR two ints together */ -int -mp_xor (mp_int * a, mp_int * b, mp_int * c) -{ - int res, ix, px; - mp_int t, *x; - - if (a->used > b->used) { - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - px = b->used; - x = b; - } else { - if ((res = mp_init_copy (&t, b)) != MP_OKAY) { - return res; - } - px = a->used; - x = a; - } - - for (ix = 0; ix < px; ix++) { - t.dp[ix] ^= x->dp[ix]; - } - mp_clamp (&t); - mp_exch (c, &t); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_mp_xor.c */ - -/* Start: bn_mp_zero.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* set to zero */ -void -mp_zero (mp_int * a) -{ - a->sign = MP_ZPOS; - a->used = 0; - memset (a->dp, 0, sizeof (mp_digit) * a->alloc); -} - -/* End: bn_mp_zero.c */ - -/* Start: bn_prime_tab.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include -const mp_digit __prime_tab[] = { - 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, - 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, - 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, - 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, - 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, - 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, - 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, - 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, - - 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, - 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, - 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, - 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, - 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, - 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, - 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, - 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, - - 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, - 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, - 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, - 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, - 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, - 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, - 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, - 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, - - 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, - 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, - 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, - 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, - 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, - 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, - 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, - 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 -}; - -/* End: bn_prime_tab.c */ - -/* Start: bn_radix.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* chars used in radix conversions */ -static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -/* read a string [ASCII] in a given radix */ -int -mp_read_radix (mp_int * a, char *str, int radix) -{ - int y, res, neg; - char ch; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - if (*str == '-') { - ++str; - neg = MP_NEG; - } else { - neg = MP_ZPOS; - } - - mp_zero (a); - while (*str) { - ch = (char) ((radix < 36) ? toupper (*str) : *str); - for (y = 0; y < 64; y++) { - if (ch == s_rmap[y]) { - break; - } - } - - if (y < radix) { - if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { - return res; - } - if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { - return res; - } - } else { - break; - } - ++str; - } - a->sign = neg; - return MP_OKAY; -} - -/* stores a bignum as a ASCII string in a given radix (2..64) */ -int -mp_toradix (mp_int * a, char *str, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - char *_s = str; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - if (t.sign == MP_NEG) { - ++_s; - *str++ = '-'; - t.sign = MP_ZPOS; - } - - digs = 0; - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return res; - } - *str++ = s_rmap[d]; - ++digs; - } - bn_reverse ((unsigned char *)_s, digs); - *str++ = '\0'; - mp_clear (&t); - return MP_OKAY; -} - -/* returns size of ASCII reprensentation */ -int -mp_radix_size (mp_int * a, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - - /* special case for binary */ - if (radix == 2) { - return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; - } - - if (radix < 2 || radix > 64) { - return 0; - } - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return 0; - } - - digs = 0; - if (t.sign == MP_NEG) { - ++digs; - t.sign = MP_ZPOS; - } - - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return 0; - } - ++digs; - } - mp_clear (&t); - return digs + 1; -} - -/* End: bn_radix.c */ - -/* Start: bn_reverse.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reverse an array, used for radix code */ -void -bn_reverse (unsigned char *s, int len) -{ - int ix, iy; - unsigned char t; - - ix = 0; - iy = len - 1; - while (ix < iy) { - t = s[ix]; - s[ix] = s[iy]; - s[iy] = t; - ++ix; - --iy; - } -} - -/* End: bn_reverse.c */ - -/* Start: bn_s_mp_add.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level addition, based on HAC pp.594, Algorithm 14.7 */ -int -s_mp_add (mp_int * a, mp_int * b, mp_int * c) -{ - mp_int *x; - int olduse, res, min, max; - - /* find sizes, we let |a| <= |b| which means we have to sort - * them. "x" will point to the input with the most digits - */ - if (a->used > b->used) { - min = b->used; - max = a->used; - x = a; - } else if (a->used < b->used) { - min = a->used; - max = b->used; - x = b; - } else { - min = max = a->used; - x = NULL; - } - - /* init result */ - if (c->alloc < max + 1) { - if ((res = mp_grow (c, max + 1)) != MP_OKAY) { - return res; - } - } - - olduse = c->used; - c->used = max + 1; - - /* add digits from lower part */ - - /* set the carry to zero */ - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - - /* first input */ - tmpa = a->dp; - - /* second input */ - tmpb = b->dp; - - /* destination */ - tmpc = c->dp; - - u = 0; - for (i = 0; i < min; i++) { - /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ - *tmpc = *tmpa++ + *tmpb++ + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, that is in A+B if A or B has more digits add those in */ - if (min != max) { - for (; i < max; i++) { - /* T[i] = X[i] + U */ - *tmpc = x->dp[i] + u; - - /* U = carry bit of T[i] */ - u = *tmpc >> DIGIT_BIT; - - /* take away carry bit from T[i] */ - *tmpc++ &= MP_MASK; - } - } - - /* add carry */ - *tmpc++ = u; - - /* clear digits above used (since we may not have grown result above) */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_s_mp_add.c */ - -/* Start: bn_s_mp_mul_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiplies |a| * |b| and only computes upto digs digits of result - * HAC pp. 595, Algorithm 14.12 Modified so you can control how many digits of - * output are created. - */ -int -s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - - if ((res = mp_init_size (&t, digs)) != MP_OKAY) { - return res; - } - t.used = digs; - - /* compute the digits of the product directly */ - pa = a->used; - for (ix = 0; ix < pa; ix++) { - /* set the carry to zero */ - u = 0; - - /* limit ourselves to making digs digits of output */ - pb = MIN (b->used, digs - ix); - - /* setup some aliases */ - tmpx = a->dp[ix]; - tmpt = &(t.dp[ix]); - tmpy = b->dp; - - /* compute the columns of the output and propagate the carry */ - for (iy = 0; iy < pb; iy++) { - /* compute the column as a mp_word */ - r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); - - /* the new column is the lower part of the result */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry word from the result */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - if (ix + iy < digs) - *tmpt = u; - } - - mp_clamp (&t); - mp_exch (&t, c); - - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_mul_digs.c */ - -/* Start: bn_s_mp_mul_high_digs.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiplies |a| * |b| and does not compute the lower digs digits - * [meant to get the higher part of the product] - */ -int -s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -{ - mp_int t; - int res, pa, pb, ix, iy; - mp_digit u; - mp_word r; - mp_digit tmpx, *tmpt, *tmpy; - - - /* can we use the fast multiplier? */ - if (((a->used + b->used + 1) < 512) - && MAX (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { - return fast_s_mp_mul_high_digs (a, b, c, digs); - } - - if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { - return res; - } - t.used = a->used + b->used + 1; - - pa = a->used; - pb = b->used; - for (ix = 0; ix < pa; ix++) { - /* clear the carry */ - u = 0; - - /* left hand side of A[ix] * B[iy] */ - tmpx = a->dp[ix]; - - /* alias to the address of where the digits will be stored */ - tmpt = &(t.dp[digs]); - - /* alias for where to read the right hand side from */ - tmpy = b->dp + (digs - ix); - - for (iy = digs - ix; iy < pb; iy++) { - /* calculate the double precision result */ - r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); - - /* get the lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* carry the carry */ - u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); - } - *tmpt = u; - } - mp_clamp (&t); - mp_exch (&t, c); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_mul_high_digs.c */ - -/* Start: bn_s_mp_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ -int -s_mp_sqr (mp_int * a, mp_int * b) -{ - mp_int t; - int res, ix, iy, pa; - mp_word r, u; - mp_digit tmpx, *tmpt; - - pa = a->used; - if ((res = mp_init_size (&t, pa + pa + 1)) != MP_OKAY) { - return res; - } - t.used = pa + pa + 1; - - for (ix = 0; ix < pa; ix++) { - /* first calculate the digit at 2*ix */ - /* calculate double precision result */ - r = ((mp_word) t.dp[ix + ix]) + ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); - - /* store lower part in result */ - t.dp[ix + ix] = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get the carry */ - u = (r >> ((mp_word) DIGIT_BIT)); - - /* left hand side of A[ix] * A[iy] */ - tmpx = a->dp[ix]; - - /* alias for where to store the results */ - tmpt = &(t.dp[ix + ix + 1]); - for (iy = ix + 1; iy < pa; iy++) { - /* first calculate the product */ - r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); - - /* now calculate the double precision result, note we use - * addition instead of *2 since its easier to optimize - */ - r = ((mp_word) * tmpt) + r + r + ((mp_word) u); - - /* store lower part */ - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - - /* get carry */ - u = (r >> ((mp_word) DIGIT_BIT)); - } - r = ((mp_word) * tmpt) + u; - *tmpt = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (r >> ((mp_word) DIGIT_BIT)); - /* propagate upwards */ - ++tmpt; - while (u != ((mp_word) 0)) { - r = ((mp_word) * tmpt) + ((mp_word) 1); - *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); - u = (r >> ((mp_word) DIGIT_BIT)); - } - } - - mp_clamp (&t); - mp_exch (&t, b); - mp_clear (&t); - return MP_OKAY; -} - -/* End: bn_s_mp_sqr.c */ - -/* Start: bn_s_mp_sub.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* low level subtraction (assumes a > b), HAC pp.595 Algorithm 14.9 */ -int -s_mp_sub (mp_int * a, mp_int * b, mp_int * c) -{ - int olduse, res, min, max; - - /* find sizes */ - min = b->used; - max = a->used; - - /* init result */ - if (c->alloc < max) { - if ((res = mp_grow (c, max)) != MP_OKAY) { - return res; - } - } - olduse = c->used; - c->used = max; - - /* sub digits from lower part */ - - { - register mp_digit u, *tmpa, *tmpb, *tmpc; - register int i; - - /* alias for digit pointers */ - tmpa = a->dp; - tmpb = b->dp; - tmpc = c->dp; - - /* set carry to zero */ - u = 0; - for (i = 0; i < min; i++) { - /* T[i] = A[i] - B[i] - U */ - *tmpc = *tmpa++ - *tmpb++ - u; - - /* U = carry bit of T[i] - * Note this saves performing an AND operation since - * if a carry does occur it will propagate all the way to the - * MSB. As a result a single shift is required to get the carry - */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* now copy higher words if any, e.g. if A has more digits than B */ - for (; i < max; i++) { - /* T[i] = A[i] - U */ - *tmpc = *tmpa++ - u; - - /* U = carry bit of T[i] */ - u = *tmpc >> (CHAR_BIT * sizeof (mp_digit) - 1); - - /* Clear carry from T[i] */ - *tmpc++ &= MP_MASK; - } - - /* clear digits above used (since we may not have grown result above) */ - for (i = c->used; i < olduse; i++) { - *tmpc++ = 0; - } - } - - mp_clamp (c); - return MP_OKAY; -} - -/* End: bn_s_mp_sub.c */ - - -/* EOF */ +/* Start: bn_fast_mp_invmod.c */ +#line 0 "bn_fast_mp_invmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include "mycrypt.h" +#include + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on mp_invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +int +fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto __ERR; + } + + /* we need y = |a| */ + if ((res = mp_abs (a, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! + * + * That is if gcd(x,y) = 2 * k then obviously there is no inverse. + */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_iseven (&B) == 0) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C,D are even then */ + if (mp_iseven (&D) == 0) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto __ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} + +/* End: bn_fast_mp_invmod.c */ + +/* Start: bn_fast_mp_montgomery_reduce.c */ +#line 0 "bn_fast_mp_montgomery_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of mp_montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + { + register mp_word *_W; + register mp_digit *tmpx; + + _W = W; + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (((mp_digit) (W[ix] & MP_MASK)) * rho) & MP_MASK; + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word) mu) * ((mp_word) * tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + _W1 = W + ix; + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + tmpx = x->dp; + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = *_W++ & ((mp_word) MP_MASK); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} + +/* End: bn_fast_mp_montgomery_reduce.c */ + +/* Start: bn_fast_s_mp_mul_digs.c */ +#line 0 "bn_fast_s_mp_mul_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +int +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix; + mp_word W[MP_WARRAY]; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* clear temp buf (the columns) */ + memset (W, 0, sizeof (mp_word) * digs); + + /* calculate the columns */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* this multiplier has been modified to allow you to + * control how many digits of output are produced. + * So at most we want to make upto "digs" digits of output. + * + * this adds products to distinct columns (at ix+iy) of W + * note that each step through the loop is not dependent on + * the previous which means the compiler can easily unroll + * the loop without scheduling problems + */ + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy, pb; + + /* alias for the the word on the left e.g. A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for the right side */ + tmpy = b->dp; + + /* alias for the columns, each step through the loop adds a new + term to each column + */ + _W = W + ix; + + /* the number of digits is limited by their placement. E.g. + we avoid multiplying digits that will end up above the # of + digits of precision requested + */ + pb = MIN (b->used, digs - ix); + + for (iy = 0; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + + } + + /* setup dest */ + olduse = c->used; + c->used = digs; + + { + register mp_digit *tmpc; + + /* At this point W[] contains the sums of each column. To get the + * correct result we must take the extra bits from each column and + * carry them down + * + * Note that while this adds extra code to the multiplier it + * saves time since the carry propagation is removed from the + * above nested loop.This has the effect of reducing the work + * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the + * cost of the shifting. On very small numbers this is slower + * but on most cryptographic size numbers it is faster. + */ + tmpc = c->dp; + for (ix = 1; ix < digs; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); + + /* clear unused */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_digs.c */ + +/* Start: bn_fast_s_mp_mul_high_digs.c */ +#line 0 "bn_fast_s_mp_mul_high_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* this is a modified version of fast_s_mp_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mp_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +int +fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int oldused, newused, res, pa, pb, ix; + mp_word W[MP_WARRAY]; + + /* calculate size of product and allocate more space if required */ + newused = a->used + b->used + 1; + if (c->alloc < newused) { + if ((res = mp_grow (c, newused)) != MP_OKAY) { + return res; + } + } + + /* like the other comba method we compute the columns first */ + pa = a->used; + pb = b->used; + memset (W + digs, 0, (pa + pb + 1 - digs) * sizeof (mp_word)); + for (ix = 0; ix < pa; ix++) { + { + register mp_digit tmpx, *tmpy; + register int iy; + register mp_word *_W; + + /* work todo, that is we only calculate digits that are at "digs" or above */ + iy = digs - ix; + + /* copy of word on the left of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = b->dp + iy; + + /* alias for the columns of output. Offset to be equal to or above the + * smallest digit place requested + */ + _W = W + digs; + + /* skip cases below zero where ix > digs */ + if (iy < 0) { + iy = abs(iy); + tmpy += iy; + _W += iy; + iy = 0; + } + + /* compute column products for digits above the minimum */ + for (; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + } + + /* setup dest */ + oldused = c->used; + c->used = newused; + + /* now convert the array W downto what we need */ + for (ix = digs + 1; ix < newused; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + c->dp[ix - 1] = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + c->dp[(pa + pb + 1) - 1] = (mp_digit) (W[(pa + pb + 1) - 1] & ((mp_word) MP_MASK)); + + for (; ix < oldused; ix++) { + c->dp[ix] = 0; + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_high_digs.c */ + +/* Start: bn_fast_s_mp_sqr.c */ +#line 0 "bn_fast_s_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* fast squaring + * + * This is the comba method where the columns of the product + * are computed first then the carries are computed. This + * has the effect of making a very simple inner loop that + * is executed the most + * + * W2 represents the outer products and W the inner. + * + * A further optimizations is made because the inner + * products are of the form "A * B * 2". The *2 part does + * not need to be computed until the end which is good + * because 64-bit shifts are slow! + * + * Based on Algorithm 14.16 on pp.597 of HAC. + * + */ +int +fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, newused, res, ix, pa; + mp_word W2[MP_WARRAY], W[MP_WARRAY]; + + /* calculate size of product and allocate as required */ + pa = a->used; + newused = pa + pa + 1; + if (b->alloc < newused) { + if ((res = mp_grow (b, newused)) != MP_OKAY) { + return res; + } + } + + /* zero temp buffer (columns) + * Note that there are two buffers. Since squaring requires + * a outter and inner product and the inner product requires + * computing a product and doubling it (a relatively expensive + * op to perform n**2 times if you don't have to) the inner and + * outer products are computed in different buffers. This way + * the inner product can be doubled using n doublings instead of + * n**2 + */ + memset (W, 0, newused * sizeof (mp_word)); + memset (W2, 0, newused * sizeof (mp_word)); + + /* This computes the inner product. To simplify the inner N**2 loop + * the multiplication by two is done afterwards in the N loop. + */ + for (ix = 0; ix < pa; ix++) { + /* compute the outer product + * + * Note that every outer product is computed + * for a particular column only once which means that + * there is no need todo a double precision addition + */ + W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); + + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy; + + /* copy of left side */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = a->dp + (ix + 1); + + /* the column to store the result in */ + _W = W + (ix + ix + 1); + + /* inner products */ + for (iy = ix + 1; iy < pa; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + } + + /* setup dest */ + olduse = b->used; + b->used = newused; + + /* now compute digits */ + { + register mp_digit *tmpb; + + /* double first value, since the inner products are + * half of what they should be + */ + W[0] += W[0] + W2[0]; + + tmpb = b->dp; + for (ix = 1; ix < newused; ix++) { + /* double/add next digit */ + W[ix] += W[ix] + W2[ix]; + + W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + /* set the last value. Note even if the carry is zero + * this is required since the next step will not zero + * it if b originally had a value at b->dp[2*a.used] + */ + *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); + + /* clear high digits */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_sqr.c */ + +/* Start: bn_mp_2expt.c */ +#line 0 "bn_mp_2expt.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + mp_zero (a); + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + a->used = b / DIGIT_BIT + 1; + a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); + + return MP_OKAY; +} + +/* End: bn_mp_2expt.c */ + +/* Start: bn_mp_abs.c */ +#line 0 "bn_mp_abs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + b->sign = MP_ZPOS; + return MP_OKAY; +} + +/* End: bn_mp_abs.c */ + +/* Start: bn_mp_add.c */ +#line 0 "bn_mp_add.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level addition (handles signs) */ +int +mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* End: bn_mp_add.c */ + +/* Start: bn_mp_add_d.c */ +#line 0 "bn_mp_add_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init_size(&t, 1)) != MP_OKAY) { + return res; + } + mp_set (&t, b); + res = mp_add (a, &t, c); + + mp_clear (&t); + return res; +} + +/* End: bn_mp_add_d.c */ + +/* Start: bn_mp_addmod.c */ +#line 0 "bn_mp_addmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a + b (mod c) */ +int +mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_add (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_addmod.c */ + +/* Start: bn_mp_and.c */ +#line 0 "bn_mp_and.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* AND two ints together */ +int +mp_and (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; + } + + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; + } + + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_and.c */ + +/* Start: bn_mp_clamp.c */ +#line 0 "bn_mp_clamp.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void +mp_clamp (mp_int * a) +{ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + +/* End: bn_mp_clamp.c */ + +/* Start: bn_mp_clear.c */ +#line 0 "bn_mp_clear.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + if (a->dp != NULL) { + + /* first zero the digits */ + memset (a->dp, 0, sizeof (mp_digit) * a->used); + + /* free ram */ + free (a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + } +} + +/* End: bn_mp_clear.c */ + +/* Start: bn_mp_cmp.c */ +#line 0 "bn_mp_cmp.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG && b->sign == MP_ZPOS) { + return MP_LT; + } + + if (a->sign == MP_ZPOS && b->sign == MP_NEG) { + return MP_GT; + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + +/* End: bn_mp_cmp.c */ + +/* Start: bn_mp_cmp_d.c */ +#line 0 "bn_mp_cmp_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare a digit */ +int +mp_cmp_d (mp_int * a, mp_digit b) +{ + + if (a->sign == MP_NEG) { + return MP_LT; + } + + if (a->used > 1) { + return MP_GT; + } + + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + +/* End: bn_mp_cmp_d.c */ + +/* Start: bn_mp_cmp_mag.c */ +#line 0 "bn_mp_cmp_mag.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare maginitude of two ints (unsigned) */ +int +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* compare based on digits */ + for (n = a->used - 1; n >= 0; n--) { + if (a->dp[n] > b->dp[n]) { + return MP_GT; + } + + if (a->dp[n] < b->dp[n]) { + return MP_LT; + } + } + return MP_EQ; +} + +/* End: bn_mp_cmp_mag.c */ + +/* Start: bn_mp_copy.c */ +#line 0 "bn_mp_copy.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + tmpa = a->dp; + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_copy.c */ + +/* Start: bn_mp_count_bits.c */ +#line 0 "bn_mp_count_bits.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + +/* End: bn_mp_count_bits.c */ + +/* Start: bn_mp_div.c */ +#line 0 "bn_mp_div.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly incomplete. For example, + * it doesn't consider the case where digits are removed from 'x' in the inner + * loop. It also doesn't consider the case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as 14.20 from HAC but fixed to treat these cases. +*/ +int +mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto __Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto __T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto __X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto __Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* step 2. while (x >= y*b^n-t) do { q[n-t] += 1; x -= y*b^{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b^{n-t} */ + goto __Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto __Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) + continue; + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* step 3.2 while (q{i-t-1} * (yt * b + y{t-1})) > xi * b^2 + xi-1 * b + xi-2 do q{i-t-1} -= 1; */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder [which we have to normalize] */ + /* get sign before writing to c */ + x.sign = a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +__Y:mp_clear (&y); +__X:mp_clear (&x); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); +__Q:mp_clear (&q); + return res; +} + +/* End: bn_mp_div.c */ + +/* Start: bn_mp_div_2.c */ +#line 0 "bn_mp_div_2.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a/2 */ +int +mp_div_2 (mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_mp_div_2.c */ + +/* Start: bn_mp_div_2d.c */ +#line 0 "bn_mp_div_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +int +mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_div_2d.c */ + +/* Start: bn_mp_div_3.c */ +#line 0 "bn_mp_div_3.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); + w -= (t << ((mp_word)1)) + t; + while (w >= 3) { + t += 1; + w -= 3; + } + } else { + t = 0; + } + q.dp[ix] = t; + } + + if (d != NULL) { + *d = w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +/* End: bn_mp_div_3.c */ + +/* Start: bn_mp_div_d.c */ +#line 0 "bn_mp_div_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit division (based on routine from MPI) */ +int +mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + int res, ix; + + if (b == 0) { + return MP_VAL; + } + + if (b == 3) { + return mp_div_3(a, c, d); + } + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= b) { + t = w / b; + w = w % b; + } else { + t = 0; + } + q.dp[ix] = t; + } + + if (d != NULL) { + *d = w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +/* End: bn_mp_div_d.c */ + +/* Start: bn_mp_dr_is_modulus.c */ +#line 0 "bn_mp_dr_is_modulus.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + + +/* End: bn_mp_dr_is_modulus.c */ + +/* Start: bn_mp_dr_reduce.c */ +#line 0 "bn_mp_dr_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Loong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + */ +int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < m + m) { + if ((err = mp_grow (x, m + m)) != MP_OKAY) { + return err; + } + } + +/* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + mp * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + *tmpx1++ = r & MP_MASK; + mu = r >> ((mp_word)DIGIT_BIT); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag (x, n) != MP_LT) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} + +/* End: bn_mp_dr_reduce.c */ + +/* Start: bn_mp_dr_setup.c */ +#line 0 "bn_mp_dr_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + + +/* End: bn_mp_dr_setup.c */ + +/* Start: bn_mp_exch.c */ +#line 0 "bn_mp_exch.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + +/* End: bn_mp_exch.c */ + +/* Start: bn_mp_expt_d.c */ +#line 0 "bn_mp_expt_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculate c = a**b using a square-multiply algorithm */ +int +mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, x; + mp_int g; + + if ((res = mp_init_copy (&g, a)) != MP_OKAY) { + return res; + } + + /* set initial result */ + mp_set (c, 1); + + for (x = 0; x < (int) DIGIT_BIT; x++) { + /* square */ + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + } + + /* shift to next bit */ + b <<= 1; + } + + mp_clear (&g); + return MP_OKAY; +} + +/* End: bn_mp_expt_d.c */ + +/* Start: bn_mp_exptmod.c */ +#line 0 "bn_mp_exptmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + dr = mp_dr_is_modulus(P); + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } + + /* if the modulus is odd use the fast method */ + if ((mp_isodd (P) == 1 || dr != 0) && P->used > 4) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { + return s_mp_exptmod (G, X, P, Y); + } +} + + +/* End: bn_mp_exptmod.c */ + +/* Start: bn_mp_exptmod_fast.c */ +#line 0 "bn_mp_exptmod_fast.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes Y == G^X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ +int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[256], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + + /* init G array */ + for (x = 0; x < (1 << winsize); x++) { + if ((err = mp_init (&M[x])) != MP_OKAY) { + for (y = 0; y < x; y++) { + mp_clear (&M[y]); + } + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto __M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else { + /* use slower baselien method */ + redux = mp_montgomery_reduce; + } + } else if (redmode == 1) { + /* setup DR reduction */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + /* setup 2k reduction */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto __M; + } + redux = mp_reduce_2k; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __RES; + } + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto __RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used */ + if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__M: + for (x = 0; x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_mp_exptmod_fast.c */ + +/* Start: bn_mp_gcd.c */ +#line 0 "bn_mp_gcd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] + */ +int +mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v, t; + int k, res, neg; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { + return mp_copy (b, c); + } + if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { + return mp_copy (a, c); + } + if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { + mp_set (c, 1); + return MP_OKAY; + } + + /* if both are negative they share (-1) as a common divisor */ + neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; + + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto __U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + if ((res = mp_init (&t)) != MP_OKAY) { + goto __V; + } + + /* B1. Find power of two */ + k = 0; + while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { + ++k; + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __T; + } + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __T; + } + } + + /* B2. Initialize */ + if (mp_isodd(&u) == 1) { + /* t = -v */ + if ((res = mp_copy (&v, &t)) != MP_OKAY) { + goto __T; + } + t.sign = MP_NEG; + } else { + /* t = u */ + if ((res = mp_copy (&u, &t)) != MP_OKAY) { + goto __T; + } + } + + do { + /* B3 (and B4). Halve t, if even */ + while (t.used != 0 && mp_iseven(&t) == 1) { + if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { + goto __T; + } + } + + /* B5. if t>0 then u=t otherwise v=-t */ + if (t.used != 0 && t.sign != MP_NEG) { + if ((res = mp_copy (&t, &u)) != MP_OKAY) { + goto __T; + } + } else { + if ((res = mp_copy (&t, &v)) != MP_OKAY) { + goto __T; + } + v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } + + /* B6. t = u - v, if t != 0 loop otherwise terminate */ + if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { + goto __T; + } + } while (mp_iszero(&t) == 0); + + /* multiply by 2^k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { + goto __T; + } + + mp_exch (&u, c); + c->sign = neg; + res = MP_OKAY; +__T:mp_clear (&t); +__V:mp_clear (&u); +__U:mp_clear (&v); + return res; +} + +/* End: bn_mp_gcd.c */ + +/* Start: bn_mp_grow.c */ +#line 0 "bn_mp_grow.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* grow as required */ +int +mp_grow (mp_int * a, int size) +{ + int i; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + + a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_grow.c */ + +/* Start: bn_mp_init.c */ +#line 0 "bn_mp_init.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init a new bigint */ +int +mp_init (mp_int * a) +{ + /* allocate ram required and clear it */ + a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init.c */ + +/* Start: bn_mp_init_copy.c */ +#line 0 "bn_mp_init_copy.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* creates "a" then copies b into it */ +int +mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + +/* End: bn_mp_init_copy.c */ + +/* Start: bn_mp_init_size.c */ +#line 0 "bn_mp_init_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init a mp_init and grow it to a given size */ +int +mp_init_size (mp_int * a, int size) +{ + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + + /* alloc mem */ + a->dp = OPT_CAST calloc (sizeof (mp_digit), size); + if (a->dp == NULL) { + return MP_MEM; + } + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init_size.c */ + +/* Start: bn_mp_invmod.c */ +#line 0 "bn_mp_invmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (mp_iseven (b) == 0) { + return fast_mp_invmod (a, b, c); + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_copy (a, &x)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_abs (&x, &x)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C,D are even then */ + if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* a is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} + +/* End: bn_mp_invmod.c */ + +/* Start: bn_mp_jacobi.c */ +#line 0 "bn_mp_jacobi.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int +mp_jacobi (mp_int * a, mp_int * n, int *c) +{ + mp_int a1, n1, e; + int s, r, res; + mp_digit residue; + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2^e */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&n1)) != MP_OKAY) { + goto __A1; + } + + if ((res = mp_init (&e)) != MP_OKAY) { + goto __N1; + } + + while (mp_iseven (&a1) == 1) { + if ((res = mp_add_d (&e, 1, &e)) != MP_OKAY) { + goto __E; + } + + if ((res = mp_div_2 (&a1, &a1)) != MP_OKAY) { + goto __E; + } + } + + /* step 4. if e is even set s=1 */ + if (mp_iseven (&e) == 1) { + s = 1; + } else { + /* else set s=1 if n = 1/7 (mod 8) or s=-1 if n = 3/5 (mod 8) */ + if ((res = mp_mod_d (n, 8, &residue)) != MP_OKAY) { + goto __E; + } + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if n == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ((res = mp_mod_d (n, 4, &residue)) != MP_OKAY) { + goto __E; + } + if (residue == 3) { + if ((res = mp_mod_d (&a1, 4, &residue)) != MP_OKAY) { + goto __E; + } + if (residue == 3) { + s = -s; + } + } + + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + if ((res = mp_mod (n, &a1, &n1)) != MP_OKAY) { + goto __E; + } + if ((res = mp_jacobi (&n1, &a1, &r)) != MP_OKAY) { + goto __E; + } + *c = s * r; + } + + /* done */ + res = MP_OKAY; +__E:mp_clear (&e); +__N1:mp_clear (&n1); +__A1:mp_clear (&a1); + return res; +} + +/* End: bn_mp_jacobi.c */ + +/* Start: bn_mp_karatsuba_mul.c */ +#line 0 "bn_mp_karatsuba_mul.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 - a0)(b1 - b0) + a0b0 + a1b1) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1-b1)(a0-b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +int +mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = MIN (a->used, b->used); + + /* now divide in two */ + B = B / 2; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + if (mp_init_size (&y0, B) != MP_OKAY) + goto X1; + if (mp_init_size (&y1, b->used - B) != MP_OKAY) + goto Y0; + + /* init temps */ + if (mp_init_size (&t1, B * 2) != MP_OKAY) + goto Y1; + if (mp_init_size (&x0y0, B * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x1y1, B * 2) != MP_OKAY) + goto X0Y0; + + /* now shift the digits */ + x0.sign = x1.sign = a->sign; + y0.sign = y1.sign = b->sign; + + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + register int x; + register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp (&x0); + mp_clamp (&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) + goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) + goto X1Y1; /* x1y1 = x1*y1 */ + + /* now calc x1-x0 and y1-y0 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x1 - x0 */ + if (mp_sub (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + + /* add x0y0 */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&x0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< + +/* Karatsuba squaring, computes b = a*a using three + * half size squarings + * + * See comments of mp_karatsuba_mul for details. It + * is essentially the same algorithm but merely + * tuned to perform recursive squarings. + */ +int +mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = B / 2; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size (&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size (&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + register int x; + register mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp (&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr (&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr (&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1-x0)**2 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr (&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (mp_sub (&t2, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + x1x1 - (x1-x0)*(x1-x0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))< + +/* computes least common multiple as a*b/(a, b) */ +int +mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if ((res = mp_gcd (a, b, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + res = mp_div (&t, c, c, NULL); + mp_clear (&t); + return res; +} + +/* End: bn_mp_lcm.c */ + +/* Start: bn_mp_lshd.c */ +#line 0 "bn_mp_lshd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift left a certain amount of digits */ +int +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_lshd.c */ + +/* Start: bn_mp_mod.c */ +#line 0 "bn_mp_mod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign == MP_NEG) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + +/* End: bn_mp_mod.c */ + +/* Start: bn_mp_mod_2d.c */ +#line 0 "bn_mp_mod_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calc a value mod 2^b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b > (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mod_2d.c */ + +/* Start: bn_mp_mod_d.c */ +#line 0 "bn_mp_mod_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} + +/* End: bn_mp_mod_d.c */ + +/* Start: bn_mp_montgomery_calc_normalization.c */ +#line 0 "bn_mp_montgomery_calc_normalization.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculates a = B^n mod b for Montgomery reduction + * Where B is the base [e.g. 2^DIGIT_BIT]. + * B^n mod b is computed by first computing + * A = B^(n-1) which doesn't require a reduction but a simple OR. + * then C = A * B = B^n is computed by performing upto DIGIT_BIT + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + /* compute A = B^(n-1) * 2^(bits-1) */ + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_calc_normalization.c */ + +/* Start: bn_mp_montgomery_reduce.c */ +#line 0 "bn_mp_montgomery_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mp_mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = n->used * 2 + 1; + if ((digs < MP_WARRAY) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b */ + mu = (x->dp[ix] * rho) & MP_MASK; + + /* a = a + mu * m * b**i */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register mp_word r; + + /* aliases */ + tmpn = n->dp; + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + r = ((mp_word) mu) * ((mp_word) * tmpn++) + + ((mp_word) u) + ((mp_word) * tmpx); + u = (r >> ((mp_word) DIGIT_BIT)); + *tmpx++ = (r & ((mp_word) MP_MASK)); + } + /* propagate carries */ + while (u) { + *tmpx += u; + u = *tmpx >> DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* x = x/b**n.used */ + mp_rshd (x, n->used); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_reduce.c */ + +/* Start: bn_mp_montgomery_setup.c */ +#line 0 "bn_mp_montgomery_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_setup.c */ + +/* Start: bn_mp_mul.c */ +#line 0 "bn_mp_mul.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level multiplication (handles sign) */ +int +mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else { + + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else { + res = s_mp_mul (a, b, c); + } + + } + c->sign = neg; + return res; +} + +/* End: bn_mp_mul.c */ + +/* Start: bn_mp_mul_2.c */ +#line 0 "bn_mp_mul_2.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a*2 */ +int +mp_mul_2 (mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++b->used; + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_mul_2.c */ + +/* Start: bn_mp_mul_2d.c */ +#line 0 "bn_mp_mul_2d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* NOTE: This routine requires updating. For instance the c->used = c->alloc bit + is wrong. We should just shift c->used digits then set the carry as c->dp[c->used] = carry + + To be fixed for LTM 0.18 + */ + +/* shift left by a certain bit count */ +int +mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + c->used = c->alloc; + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> (DIGIT_BIT - d)) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mul_2d.c */ + +/* Start: bn_mp_mul_d.c */ +#line 0 "bn_mp_mul_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, pa, olduse; + + /* make sure c is big enough to hold a*b */ + pa = a->used; + if (c->alloc < pa + 1) { + if ((res = mp_grow (c, pa + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the new temporary used count */ + c->used = pa + 1; + + { + register mp_digit u, *tmpa, *tmpc; + register mp_word r; + register int ix; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + for (ix = 0; ix < pa; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* store final carry [if any] */ + *tmpc++ = u; + + /* now zero digits above the top */ + for (; pa < olduse; pa++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mul_d.c */ + +/* Start: bn_mp_mulmod.c */ +#line 0 "bn_mp_mulmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a * b (mod c) */ +int +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_mulmod.c */ + +/* Start: bn_mp_multi.c */ +#line 0 "bn_mp_multi.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +#include + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} + +/* End: bn_mp_multi.c */ + +/* Start: bn_mp_n_root.c */ +#line 0 "bn_mp_n_root.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* find the n'th root of an integer + * + * Result found such that (c)^b <= a and (c+1)^b > a + * + * This algorithm uses Newton's approximation x[i+1] = x[i] - f(x[i])/f'(x[i]) + * which will find the root in log(N) time where each step involves a fair bit. This + * is not meant to find huge roots [square and cube at most]. + */ +int +mp_n_root (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t1, t2, t3; + int res, neg; + + /* input must be positive if b is even */ + if ((b & 1) == 0 && a->sign == MP_NEG) { + return MP_VAL; + } + + if ((res = mp_init (&t1)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init (&t3)) != MP_OKAY) { + goto __T2; + } + + /* if a is negative fudge the sign but keep track */ + neg = a->sign; + a->sign = MP_ZPOS; + + /* t2 = 2 */ + mp_set (&t2, 2); + + do { + /* t1 = t2 */ + if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { + goto __T3; + } + + /* t2 = t1 - ((t1^b - a) / (b * t1^(b-1))) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) */ + goto __T3; + } + + /* numerator */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { /* t2 = t1^b */ + goto __T3; + } + + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { /* t2 = t1^b - a */ + goto __T3; + } + + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) * b */ + goto __T3; + } + + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { /* t3 = (t1^b - a)/(b * t1^(b-1)) */ + goto __T3; + } + + if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { + goto __T3; + } + } + while (mp_cmp (&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + for (;;) { + if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { + goto __T3; + } + + if (mp_cmp (&t2, a) == MP_GT) { + if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { + goto __T3; + } + } else { + break; + } + } + + /* reset the sign of a first */ + a->sign = neg; + + /* set the result */ + mp_exch (&t1, c); + + /* set the sign of the result */ + c->sign = neg; + + res = MP_OKAY; + +__T3:mp_clear (&t3); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); + return res; +} + +/* End: bn_mp_n_root.c */ + +/* Start: bn_mp_neg.c */ +#line 0 "bn_mp_neg.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = -a */ +int +mp_neg (mp_int * a, mp_int * b) +{ + int res; + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + return MP_OKAY; +} + +/* End: bn_mp_neg.c */ + +/* Start: bn_mp_or.c */ +#line 0 "bn_mp_or.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* OR two ints together */ +int +mp_or (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] |= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_or.c */ + +/* Start: bn_mp_prime_fermat.c */ +#line 0 "bn_mp_prime_fermat.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs one Fermat test. + * + * If "a" were prime then b^a == b (mod a) since the order of + * the multiplicative sub-group would be phi(a) = a-1. That means + * it would be the same as b^(a mod (a-1)) == b^1 == b (mod a). + * + * Sets result to 1 if the congruence holds, or zero otherwise. + */ +int +mp_prime_fermat (mp_int * a, mp_int * b, int *result) +{ + mp_int t; + int err; + + /* default to fail */ + *result = 0; + + /* init t */ + if ((err = mp_init (&t)) != MP_OKAY) { + return err; + } + + /* compute t = b^a mod a */ + if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { + goto __T; + } + + /* is it equal to b? */ + if (mp_cmp (&t, b) == MP_EQ) { + *result = 1; + } + + err = MP_OKAY; +__T:mp_clear (&t); + return err; +} + +/* End: bn_mp_prime_fermat.c */ + +/* Start: bn_mp_prime_is_divisible.c */ +#line 0 "bn_mp_prime_is_divisible.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if an integers is divisible by one of the first 256 primes or not + * + * sets result to 0 if not, 1 if yes + */ +int +mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = 0; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* is it equal to the prime? */ + if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + + /* what is a mod __prime_tab[ix] */ + if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = 1; + return MP_OKAY; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_prime_is_divisible.c */ + +/* Start: bn_mp_prime_is_prime.c */ +#line 0 "bn_mp_prime_is_prime.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + * (1/4)^t when 1 <= t <= 256 + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int +mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = 0; + + /* valid value of t? */ + if (t < 1 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + if (res == 1) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, __prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto __B; + } + + if (res == 0) { + goto __B; + } + } + + /* passed the test */ + *result = 1; +__B:mp_clear (&b); + return err; +} + +/* End: bn_mp_prime_is_prime.c */ + +/* Start: bn_mp_prime_miller_rabin.c */ +#line 0 "bn_mp_prime_miller_rabin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +int +mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = 0; + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto __N1; + } + + /* set 2^s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto __N1; + } + s = 0; + while (mp_iseven (&r) == 1) { + ++s; + if ((err = mp_div_2 (&r, &r)) != MP_OKAY) { + goto __R; + } + } + + /* compute y = b^r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto __R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto __Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto __Y; + } + } + + /* probably prime now */ + *result = 1; +__Y:mp_clear (&y); +__R:mp_clear (&r); +__N1:mp_clear (&n1); + return err; +} + +/* End: bn_mp_prime_miller_rabin.c */ + +/* Start: bn_mp_prime_next_prime.c */ +#line 0 "bn_mp_prime_next_prime.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + */ +int mp_prime_next_prime(mp_int *a, int t) +{ + int err, res; + + if (mp_iseven(a) == 1) { + /* force odd */ + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { + return err; + } + } else { + /* force to next odd number */ + if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { + return err; + } + } + + for (;;) { + /* is this prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { + return err; + } + + if (res == 1) { + break; + } + + /* add two, next candidate */ + if ((err = mp_add_d(a, 2, a)) != MP_OKAY) { + return err; + } + } + + return MP_OKAY; +} + + +/* End: bn_mp_prime_next_prime.c */ + +/* Start: bn_mp_rand.c */ +#line 0 "bn_mp_rand.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* makes a pseudo-random int of a given size */ +int +mp_rand (mp_int * a, int digits) +{ + int res; + mp_digit d; + + mp_zero (a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + d = ((mp_digit) abs (rand ())); + } while (d == 0); + + if ((res = mp_add_d (a, d, a)) != MP_OKAY) { + return res; + } + + while (digits-- > 0) { + if ((res = mp_lshd (a, 1)) != MP_OKAY) { + return res; + } + + if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { + return res; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_rand.c */ + +/* Start: bn_mp_read_signed_bin.c */ +#line 0 "bn_mp_read_signed_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +int +mp_read_signed_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + + if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { + return res; + } + a->sign = ((b[0] == (unsigned char) 0) ? MP_ZPOS : MP_NEG); + return MP_OKAY; +} + +/* End: bn_mp_read_signed_bin.c */ + +/* Start: bn_mp_read_unsigned_bin.c */ +#line 0 "bn_mp_read_unsigned_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int +mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + mp_zero (a); + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + + if (DIGIT_BIT != 7) { + a->dp[0] |= *b++; + a->used += 1; + } else { + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; + } + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_read_unsigned_bin.c */ + +/* Start: bn_mp_reduce.c */ +#line 0 "bn_mp_reduce.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this is optimization is ok */ + if (((unsigned long) m->used) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { + if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + break; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + +/* End: bn_mp_reduce.c */ + +/* Start: bn_mp_reduce_2k.c */ +#line 0 "bn_mp_reduce_2k.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduces a modulo n where n is of the form 2**p - k */ +int +mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (k != 1) { + /* q = q * k */ + if ((res = mp_mul_d(&q, k, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* End: bn_mp_reduce_2k.c */ + +/* Start: bn_mp_reduce_2k_setup.c */ +#line 0 "bn_mp_reduce_2k_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +int +mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} + +/* End: bn_mp_reduce_2k_setup.c */ + +/* Start: bn_mp_reduce_is_2k.c */ +#line 0 "bn_mp_reduce_is_2k.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if mp_reduce_2k can be used */ +int +mp_reduce_is_2k(mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return 0; + } else if (a->used == 1) { + return 1; + } else if (a->used > 1) { + iy = mp_count_bits(a); + for (ix = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[ix/DIGIT_BIT] & ((mp_digit)1 << (mp_digit)(ix % DIGIT_BIT))) == 0) { + return 0; + } + } + } + return 1; +} + + +/* End: bn_mp_reduce_is_2k.c */ + +/* Start: bn_mp_reduce_setup.c */ +#line 0 "bn_mp_reduce_setup.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + +/* End: bn_mp_reduce_setup.c */ + +/* Start: bn_mp_rshd.c */ +#line 0 "bn_mp_rshd.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right a certain amount of digits */ +void +mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + +/* End: bn_mp_rshd.c */ + +/* Start: bn_mp_set.c */ +#line 0 "bn_mp_set.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to a digit */ +void +mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + +/* End: bn_mp_set.c */ + +/* Start: bn_mp_set_int.c */ +#line 0 "bn_mp_set_int.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set a 32-bit const */ +int +mp_set_int (mp_int * a, unsigned int b) +{ + int x, res; + + mp_zero (a); + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_set_int.c */ + +/* Start: bn_mp_shrink.c */ +#line 0 "bn_mp_shrink.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shrink a bignum */ +int +mp_shrink (mp_int * a) +{ + if (a->alloc != a->used) { + if ((a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->alloc = a->used; + } + return MP_OKAY; +} + +/* End: bn_mp_shrink.c */ + +/* Start: bn_mp_signed_bin_size.c */ +#line 0 "bn_mp_signed_bin_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an signed equivalent */ +int +mp_signed_bin_size (mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} + +/* End: bn_mp_signed_bin_size.c */ + +/* Start: bn_mp_sqr.c */ +#line 0 "bn_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + } else if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else { + + /* can we use the fast multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else { + res = s_mp_sqr (a, b); + } + } + b->sign = MP_ZPOS; + return res; +} + +/* End: bn_mp_sqr.c */ + +/* Start: bn_mp_sqrmod.c */ +#line 0 "bn_mp_sqrmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a * a (mod b) */ +int +mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} + +/* End: bn_mp_sqrmod.c */ + +/* Start: bn_mp_sub.c */ +#line 0 "bn_mp_sub.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* End: bn_mp_sub.c */ + +/* Start: bn_mp_sub_d.c */ +#line 0 "bn_mp_sub_d.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t; + int res; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + mp_set (&t, b); + res = mp_sub (a, &t, c); + + mp_clear (&t); + return res; +} + +/* End: bn_mp_sub_d.c */ + +/* Start: bn_mp_submod.c */ +#line 0 "bn_mp_submod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a - b (mod c) */ +int +mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_submod.c */ + +/* Start: bn_mp_to_signed_bin.c */ +#line 0 "bn_mp_to_signed_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in signed [big endian] format */ +int +mp_to_signed_bin (mp_int * a, unsigned char *b) +{ + int res; + + if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { + return res; + } + b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); + return MP_OKAY; +} + +/* End: bn_mp_to_signed_bin.c */ + +/* Start: bn_mp_to_unsigned_bin.c */ +#line 0 "bn_mp_to_unsigned_bin.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in unsigned [big endian] format */ +int +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { + if (DIGIT_BIT != 7) { + b[x++] = (unsigned char) (t.dp[0] & 255); + } else { + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); + } + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_to_unsigned_bin.c */ + +/* Start: bn_mp_toom_mul.c */ +#line 0 "bn_mp_toom_mul.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplication using Toom-Cook 3-way algorithm */ +int +mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B^2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B^2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL); + return res; +} + + +/* End: bn_mp_toom_mul.c */ + +/* Start: bn_mp_toom_sqr.c */ +#line 0 "bn_mp_toom_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* squaring using Toom-Cook 3-way algorithm */ +int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B^2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + + +/* End: bn_mp_toom_sqr.c */ + +/* Start: bn_mp_unsigned_bin_size.c */ +#line 0 "bn_mp_unsigned_bin_size.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an unsigned equivalent */ +int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +/* End: bn_mp_unsigned_bin_size.c */ + +/* Start: bn_mp_xor.c */ +#line 0 "bn_mp_xor.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* XOR two ints together */ +int +mp_xor (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] ^= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_xor.c */ + +/* Start: bn_mp_zero.c */ +#line 0 "bn_mp_zero.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to zero */ +void +mp_zero (mp_int * a) +{ + a->sign = MP_ZPOS; + a->used = 0; + memset (a->dp, 0, sizeof (mp_digit) * a->alloc); +} + +/* End: bn_mp_zero.c */ + +/* Start: bn_prime_tab.c */ +#line 0 "bn_prime_tab.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +const mp_digit __prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif +}; + +/* End: bn_prime_tab.c */ + +/* Start: bn_radix.c */ +#line 0 "bn_radix.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* chars used in radix conversions */ +static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* read a string [ASCII] in a given radix */ +int +mp_read_radix (mp_int * a, char *str, int radix) +{ + int y, res, neg; + char ch; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + mp_zero (a); + while (*str) { + ch = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == s_rmap[y]) { + break; + } + } + + if (y < radix) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + a->sign = neg; + return MP_OKAY; +} + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int +mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = s_rmap[d]; + ++digs; + } + bn_reverse ((unsigned char *)_s, digs); + *str++ = '\0'; + mp_clear (&t); + return MP_OKAY; +} + +/* returns size of ASCII reprensentation */ +int +mp_radix_size (mp_int * a, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + + /* special case for binary */ + if (radix == 2) { + return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + } + + if (radix < 2 || radix > 64) { + return 0; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return 0; + } + + digs = 0; + if (t.sign == MP_NEG) { + ++digs; + t.sign = MP_ZPOS; + } + + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return 0; + } + ++digs; + } + mp_clear (&t); + return digs + 1; +} + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + len = mp_radix_size(a, radix); + if (len == 0) { + return MP_VAL; + } + + buf = malloc(len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + free(buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + free(buf); + return MP_VAL; + } + } + + free(buf); + return MP_OKAY; +} + + +/* End: bn_radix.c */ + +/* Start: bn_reverse.c */ +#line 0 "bn_reverse.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + +/* End: bn_reverse.c */ + +/* Start: bn_s_mp_add.c */ +#line 0 "bn_s_mp_add.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_s_mp_add.c */ + +/* Start: bn_s_mp_exptmod.c */ +#line 0 "bn_s_mp_exptmod.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[256], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + for (x = 0; x < (1 << winsize); x++) { + if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { + for (y = 0; y < x; y++) { + mp_clear (&M[y]); + } + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto __M; + } + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto __MU; + } + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G**x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) + continue; + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __MU; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__MU:mp_clear (&mu); +__M: + for (x = 0; x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_s_mp_exptmod.c */ + +/* Start: bn_s_mp_mul_digs.c */ +#line 0 "bn_s_mp_mul_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +int +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word) *tmpt) + + ((mp_word) tmpx) * ((mp_word) * tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_digs.c */ + +/* Start: bn_s_mp_mul_high_digs.c */ +#line 0 "bn_s_mp_mul_high_digs.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + + /* can we use the fast multiplier? */ + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word) * tmpt) + ((mp_word) tmpx) * ((mp_word) * tmpy++) + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_high_digs.c */ + +/* Start: bn_s_mp_sqr.c */ +#line 0 "bn_s_mp_sqr.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, pa + pa + 1)) != MP_OKAY) { + return res; + } + t.used = pa + pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[ix + ix]) + + ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); + + /* store lower part in result */ + t.dp[ix + ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (ix + ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since its easier to optimize + */ + r = ((mp_word) * tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) * tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_sqr.c */ + +/* Start: bn_s_mp_sub.c */ +#line 0 "bn_s_mp_sub.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* End: bn_s_mp_sub.c */ + +/* Start: bncore.c */ +#line 0 "bncore.c" +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Known optimal configurations + + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 /GCC v3.2 / 70/ 108 + AMD Athlon XP /GCC v3.2 / 109/ 127 + +*/ + +/* configured for a AMD XP Thoroughbred core with etc/tune.c */ +int KARATSUBA_MUL_CUTOFF = 109, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 127, /* Min. number of digits before Karatsuba squaring is used. */ + + TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */ + TOOM_SQR_CUTOFF = 400; + +/* End: bncore.c */ + + +/* EOF */ diff --git a/mycrypt.h b/mycrypt.h index d72cb03..3a09a73 100644 --- a/mycrypt.h +++ b/mycrypt.h @@ -16,8 +16,8 @@ extern "C" { #endif /* version */ -#define CRYPT 0x0083 -#define SCRYPT "0.83" +#define CRYPT 0x0084 +#define SCRYPT "0.84" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 128 diff --git a/mycrypt_custom.h b/mycrypt_custom.h index 58203c4..ad6081f 100644 --- a/mycrypt_custom.h +++ b/mycrypt_custom.h @@ -1,14 +1,16 @@ /* This header is meant to be included before mycrypt.h in projects where - * you don't want to throw all the defines in a makefile. + * you don't want to throw all the defines in a makefile. */ #ifndef MYCRYPT_CUSTOM_H_ #define MYCRYPT_CUSTOM_H_ #ifdef CRYPT - #error mycrypt_custom.h should be included before mycrypt.h + #error mycrypt_custom.h should be included before mycrypt.h #endif +#define LTC_TEST + #define XMALLOC malloc #define XREALLOC realloc #define XCALLOC calloc diff --git a/noekeon.c b/noekeon.c index 52b5d32..8f4428e 100644 --- a/noekeon.c +++ b/noekeon.c @@ -169,6 +169,9 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k int noekeon_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const unsigned char key[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, @@ -193,13 +196,14 @@ int noekeon_test(void) } return CRYPT_OK; + #endif } int noekeon_keysize(int *desired_keysize) { _ARGCHK(desired_keysize != NULL); if (*desired_keysize < 16) { - return CRYPT_INVALID_KEYSIZE; + return CRYPT_INVALID_KEYSIZE; } else { *desired_keysize = 16; return CRYPT_OK; diff --git a/prime.c b/prime.c index 64e6e8e..b50baf2 100644 --- a/prime.c +++ b/prime.c @@ -2,144 +2,17 @@ #ifdef MPI -#define UPPER_LIMIT (sizeof(prime_tab) / sizeof(prime_tab[0])) - -static const mp_digit prime_tab[] = { - 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, - 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, - 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, - 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, - 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, - 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, - 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, - 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, - - 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, - 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, - 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, - 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, - 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, - 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, - 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, - 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, - - 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, - 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, - 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, - 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, - 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, - 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, - 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, - 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, - - 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, - 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, - 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, - 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, - 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, - 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, - 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, - 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 }; - +#define UPPER_LIMIT PRIME_SIZE /* figures out if a number is prime (MR test) */ -#ifdef CLEAN_STACK -static int _is_prime(mp_int *N, int *result) -#else -int is_prime(mp_int *N, int *result) -#endif -{ - long x, s, j; - int res; - mp_int n1, a, y, r; - mp_digit d; - - _ARGCHK(N != NULL); - _ARGCHK(result != NULL); - - /* default to answer of no */ - *result = 0; - - /* divisible by any of the first primes? */ - for (x = 0; x < (long)UPPER_LIMIT; x++) { - /* is N equal to a small prime? */ - if (mp_cmp_d(N, prime_tab[x]) == 0) { - *result = 1; - return CRYPT_OK; - } - - /* is N mod prime_tab[x] == 0, then its divisible by it */ - if (mp_mod_d(N, prime_tab[x], &d) != MP_OKAY) { - return CRYPT_MEM; - } - - if (d == 0) { - return CRYPT_OK; - } - } - - /* init variables */ - if (mp_init_multi(&r, &n1, &a, &y, NULL) != MP_OKAY) { - return CRYPT_MEM; - } - - /* n1 = N - 1 */ - if (mp_sub_d(N, 1, &n1) != MP_OKAY) { goto error; } - - /* r = N - 1 */ - if (mp_copy(&n1, &r) != MP_OKAY) { goto error; } - - /* find s such that N-1 = (2^s)r */ - s = 0; - while (mp_iseven(&r) != 0) { - ++s; - if (mp_div_2(&r, &r) != MP_OKAY) { - goto error; - } - } - - for (x = 0; x < 8; x++) { - /* choose a */ - mp_set(&a, prime_tab[x]); - - /* compute y = a^r mod n */ - if (mp_exptmod(&a, &r, N, &y) != MP_OKAY) { goto error; } - - /* (y != 1) AND (y != N-1) */ - if ((mp_cmp_d(&y, 1) != 0) && (mp_cmp(&y, &n1) != 0)) { - /* while j <= s-1 and y != n-1 */ - for (j = 1; (j <= (s-1)) && (mp_cmp(&y, &n1) != 0); j++) { - /* y = y^2 mod N */ - if (mp_sqrmod(&y, N, &y) != MP_OKAY) { goto error; } - - /* if y == 1 return false */ - if (mp_cmp_d(&y, 1) == 0) { goto ok; } - } - - /* if y != n-1 return false */ - if (mp_cmp(&y, &n1) != 0) { goto ok; } - } - } - *result = 1; -ok: - res = CRYPT_OK; - goto done; -error: - res = CRYPT_MEM; -done: - mp_clear_multi(&a, &y, &n1, &r, NULL); - return res; -} - -#ifdef CLEAN_STACK int is_prime(mp_int *N, int *result) { - int x; - x = _is_prime(N, result); - burn_stack(sizeof(long) * 3 + sizeof(int) + sizeof(mp_int) * 4 + sizeof(mp_digit)); - return x; -} -#endif + int err; + if ((err = mp_prime_is_prime(N, 8, result)) != MP_OKAY) { + return CRYPT_MEM; + } + return CRYPT_OK; +} static int next_prime(mp_int *N, mp_digit step) { @@ -152,7 +25,7 @@ static int next_prime(mp_int *N, mp_digit step) /* first find the residues */ for (x = 0; x < (long)UPPER_LIMIT; x++) { - if (mp_mod_d(N, prime_tab[x], &residues[x]) != MP_OKAY) { + if (mp_mod_d(N, __prime_tab[x], &residues[x]) != MP_OKAY) { return CRYPT_MEM; } } @@ -168,7 +41,7 @@ loop: dist = step; for (x = 0; (dist < (MP_DIGIT_MAX-step-1)) && (x < (long)UPPER_LIMIT); x++) { j = (long)residues[x] + (long)dist + total_dist; - if (j % (long)prime_tab[x] == 0) { + if (j % (long)__prime_tab[x] == 0) { dist += step; x = -1; } } @@ -195,7 +68,7 @@ loop: } for (x = 0; x < 8; x++) { /* choose a */ - mp_set(&a, prime_tab[x]); + mp_set(&a, __prime_tab[x]); /* compute y = a^r mod n */ if (mp_exptmod(&a, &r, N, &y) != MP_OKAY) { goto error; } diff --git a/rc2.c b/rc2.c index 869376f..faaf8ee 100644 --- a/rc2.c +++ b/rc2.c @@ -239,6 +239,9 @@ void rc2_ecb_decrypt( const unsigned char *cipher, int rc2_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[16], pt[8], ct[8]; @@ -276,6 +279,7 @@ int rc2_test(void) } } return CRYPT_OK; + #endif } int rc2_keysize(int *keysize) diff --git a/rc5.c b/rc5.c index ad2777c..dc2e577 100644 --- a/rc5.c +++ b/rc5.c @@ -152,6 +152,9 @@ void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key * int rc5_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { unsigned char key[16], pt[8], ct[8]; } tests[] = { @@ -194,6 +197,7 @@ int rc5_test(void) } } return CRYPT_OK; + #endif } int rc5_keysize(int *desired_keysize) diff --git a/rc6.c b/rc6.c index fa647ea..7f26c0b 100644 --- a/rc6.c +++ b/rc6.c @@ -156,6 +156,9 @@ void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key * int rc6_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[32], pt[16], ct[16]; @@ -214,6 +217,7 @@ int rc6_test(void) } } return CRYPT_OK; + #endif } int rc6_keysize(int *desired_keysize) diff --git a/rsa.c b/rsa.c index c811997..c60d22f 100644 --- a/rsa.c +++ b/rsa.c @@ -5,7 +5,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) { mp_int p, q, tmp1, tmp2, tmp3; - int res, err; + int res, err; _ARGCHK(key != NULL); @@ -16,7 +16,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) if ((e < 3) || ((e & 1) == 0)) { return CRYPT_INVALID_ARG; } - + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } @@ -34,7 +34,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) if (mp_sub_d(&p, 1, &tmp1) != MP_OKAY) { goto error; } /* tmp1 = p-1 */ if (mp_gcd(&tmp1, &tmp3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = gcd(p-1, e) */ } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides p-1 */ - + /* make prime "q" */ do { if (rand_prime(&q, size/2, prng, wprng) != CRYPT_OK) { res = CRYPT_ERROR; goto done; } @@ -48,7 +48,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) if (mp_lcm(&tmp1, &tmp2, &tmp1) != MP_OKAY) { goto error; } /* tmp1 = lcm(p-1, q-1) */ /* make key */ - if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) { goto error; } @@ -64,16 +64,16 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) if (mp_mod(&key->d, &tmp1, &key->dP) != MP_OKAY) { goto error2; } /* dP = d mod p-1 */ if (mp_mod(&key->d, &tmp2, &key->dQ) != MP_OKAY) { goto error2; } /* dQ = d mod q-1 */ - + if (mp_invmod(&q, &p, &key->qP) != MP_OKAY) { goto error2; } /* qP = 1/q mod p */ if (mp_mulmod(&key->qP, &q, &key->N, &key->qP)) { goto error2; } /* qP = q * (1/q mod p) mod N */ - if (mp_invmod(&p, &q, &key->pQ) != MP_OKAY) { goto error2; } /* pQ = 1/p mod q */ + if (mp_invmod(&p, &q, &key->pQ) != MP_OKAY) { goto error2; } /* pQ = 1/p mod q */ if (mp_mulmod(&key->pQ, &p, &key->N, &key->pQ)) { goto error2; } /* pQ = p * (1/p mod q) mod N */ if (mp_copy(&p, &key->p) != MP_OKAY) { goto error2; } if (mp_copy(&q, &key->q) != MP_OKAY) { goto error2; } - + /* shrink ram required */ if (mp_shrink(&key->e) != MP_OKAY) { goto error2; } if (mp_shrink(&key->d) != MP_OKAY) { goto error2; } @@ -84,12 +84,12 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) if (mp_shrink(&key->pQ) != MP_OKAY) { goto error2; } if (mp_shrink(&key->p) != MP_OKAY) { goto error2; } if (mp_shrink(&key->q) != MP_OKAY) { goto error2; } - + res = CRYPT_OK; key->type = PK_PRIVATE_OPTIMIZED; goto done; error2: - mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->qP, &key->pQ, &key->p, &key->q, NULL); error: res = CRYPT_MEM; @@ -101,7 +101,7 @@ done: void rsa_free(rsa_key *key) { _ARGCHK(key != NULL); - mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->pQ, &key->p, &key->q, NULL); } @@ -125,7 +125,7 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, /* init and copy into tmp */ if (mp_init_multi(&tmp, &tmpa, &tmpb, NULL) != MP_OKAY) { goto error; } if (mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int)inlen) != MP_OKAY) { goto error; } - + /* sanity check on the input */ if (mp_cmp(&key->N, &tmp) == MP_LT) { res = CRYPT_PK_INVALID_SIZE; @@ -158,7 +158,7 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, *outlen = x; /* convert it */ - (void)mp_to_unsigned_bin(&tmp, out); + if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY) { goto error; } /* clean up and return */ res = CRYPT_OK; @@ -170,7 +170,7 @@ done: return res; } -int rsa_signpad(const unsigned char *in, unsigned long inlen, +int rsa_signpad(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { unsigned long x, y; @@ -184,10 +184,10 @@ int rsa_signpad(const unsigned char *in, unsigned long inlen, } /* check inlen */ - if ((inlen <= 0) || inlen > 512) { + if (inlen > 512) { return CRYPT_PK_INVALID_SIZE; } - + for (y = x = 0; x < inlen; x++) out[y++] = (unsigned char)0xFF; for (x = 0; x < inlen; x++) @@ -198,8 +198,8 @@ int rsa_signpad(const unsigned char *in, unsigned long inlen, return CRYPT_OK; } -int rsa_pad(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, +int rsa_pad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int wprng, prng_state *prng) { unsigned char buf[1536]; @@ -211,17 +211,17 @@ int rsa_pad(const unsigned char *in, unsigned long inlen, _ARGCHK(outlen != NULL); /* is output big enough? */ - if (*outlen < (3 * inlen)) { + if (*outlen < (3 * inlen)) { return CRYPT_BUFFER_OVERFLOW; } /* get random padding required */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { - return err; + return err; } /* check inlen */ - if ((inlen <= 0) || inlen > 512) { + if (inlen > 512) { return CRYPT_PK_INVALID_SIZE; } @@ -229,14 +229,14 @@ int rsa_pad(const unsigned char *in, unsigned long inlen, return CRYPT_ERROR_READPRNG; } - /* pad it like a sandwitch (sp?) + /* pad it like a sandwhich * * Looks like 0xFF R1 M R2 0xFF - * - * Where R1/R2 are random and exactly equal to the length of M minus one byte. + * + * Where R1/R2 are random and exactly equal to the length of M minus one byte. */ - for (x = 0; x < inlen-1; x++) { - out[x+1] = buf[x]; + for (x = 0; x < inlen-1; x++) { + out[x+1] = buf[x]; } for (x = 0; x < inlen; x++) { @@ -258,7 +258,7 @@ int rsa_pad(const unsigned char *in, unsigned long inlen, return CRYPT_OK; } -int rsa_signdepad(const unsigned char *in, unsigned long inlen, +int rsa_signdepad(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { unsigned long x; @@ -267,7 +267,7 @@ int rsa_signdepad(const unsigned char *in, unsigned long inlen, _ARGCHK(out != NULL); _ARGCHK(outlen != NULL); - if (*outlen < inlen/3) { + if (*outlen < inlen/3) { return CRYPT_BUFFER_OVERFLOW; } @@ -277,13 +277,13 @@ int rsa_signdepad(const unsigned char *in, unsigned long inlen, return CRYPT_INVALID_PACKET; } } - for (x = 0; x < inlen/3; x++) + for (x = 0; x < inlen/3; x++) out[x] = in[x+(inlen/3)]; *outlen = inlen/3; return CRYPT_OK; } -int rsa_depad(const unsigned char *in, unsigned long inlen, +int rsa_depad(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { unsigned long x; @@ -292,10 +292,10 @@ int rsa_depad(const unsigned char *in, unsigned long inlen, _ARGCHK(out != NULL); _ARGCHK(outlen != NULL); - if (*outlen < inlen/3) { + if (*outlen < inlen/3) { return CRYPT_BUFFER_OVERFLOW; } - for (x = 0; x < inlen/3; x++) + for (x = 0; x < inlen/3; x++) out[x] = in[x+(inlen/3)]; *outlen = inlen/3; return CRYPT_OK; @@ -350,8 +350,8 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key _ARGCHK(key != NULL); /* type valid? */ - if (!(key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) && - (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED)) { + if (!(key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) && + (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED)) { return CRYPT_PK_INVALID_TYPE; } @@ -363,7 +363,7 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key /* output modulus */ OUTPUT_BIGNUM(&key->N, buf2, y, z); - + /* output public key */ OUTPUT_BIGNUM(&key->e, buf2, y, z); @@ -381,7 +381,7 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key } /* check size */ - if (*outlen < y) { + if (*outlen < y) { return CRYPT_BUFFER_OVERFLOW; } @@ -407,17 +407,18 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) _ARGCHK(in != NULL); _ARGCHK(key != NULL); - /* test packet header */ - if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { - return err; - } - + /* check length */ if (inlen < 1+PACKET_SIZE) { return CRYPT_INVALID_PACKET; } + /* test packet header */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + /* init key */ - if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, + if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) { return CRYPT_MEM; } @@ -446,7 +447,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) INPUT_BIGNUM(&key->p, in, x, y); INPUT_BIGNUM(&key->q, in, x, y); } - + /* free up ram not required */ if (key->type != PK_PRIVATE_OPTIMIZED) { mp_clear_multi(&key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); @@ -457,7 +458,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) return CRYPT_OK; error2: - mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); return err; } diff --git a/rsa_sys.c b/rsa_sys.c index 06e6584..4c562b8 100644 --- a/rsa_sys.c +++ b/rsa_sys.c @@ -69,7 +69,7 @@ int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *outkey, unsigned long *keylen, rsa_key *key) { - unsigned char sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; + unsigned char sym_key[MAXBLOCKSIZE], rsa_out[4096]; unsigned long x, y, z, i, rsa_size; int err; @@ -129,7 +129,6 @@ int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, #ifdef CLEAN_STACK /* clean up */ zeromem(sym_key, sizeof(sym_key)); - zeromem(rsa_in, sizeof(rsa_in)); zeromem(rsa_out, sizeof(rsa_out)); #endif *keylen = z; @@ -150,7 +149,7 @@ int rsa_sign_hash(const unsigned char *in, unsigned long inlen, _ARGCHK(key != NULL); /* reject nonsense sizes */ - if (inlen < 16) { + if (inlen > MAXBLOCKSIZE || inlen < 16) { return CRYPT_INVALID_ARG; } diff --git a/safer+.c b/safer+.c index b3bed1f..d42b254 100644 --- a/safer+.c +++ b/safer+.c @@ -407,6 +407,9 @@ void saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ke int saferp_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[32], pt[16], ct[16]; @@ -459,6 +462,7 @@ int saferp_test(void) } return CRYPT_OK; + #endif } int saferp_keysize(int *desired_keysize) diff --git a/safer.c b/safer.c index 9a06d46..87c7db9 100644 --- a/safer.c +++ b/safer.c @@ -344,6 +344,9 @@ int safer_128_keysize(int *keysize) int safer_k64_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const unsigned char k64_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, k64_key[] = { 8, 7, 6, 5, 4, 3, 2, 1 }, k64_ct[] = { 200, 242, 156, 221, 135, 120, 62, 217 }; @@ -364,11 +367,15 @@ int safer_k64_test(void) } return CRYPT_OK; + #endif } int safer_sk64_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const unsigned char sk64_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, sk64_key[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, sk64_ct[] = { 95, 206, 155, 162, 5, 132, 56, 199 }; @@ -390,10 +397,14 @@ int safer_sk64_test(void) } return CRYPT_OK; + #endif } int safer_sk128_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const unsigned char sk128_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, sk128_key[] = { 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -413,9 +424,8 @@ int safer_sk128_test(void) if (memcmp(buf[0], sk128_ct, 8) != 0 || memcmp(buf[1], sk128_pt, 8) != 0) { return CRYPT_FAIL_TESTVECTOR; } - - - return CRYPT_OK; + return CRYPT_OK; + #endif } #endif diff --git a/serpent.c b/serpent.c index 235ea11..8ea4a9c 100644 --- a/serpent.c +++ b/serpent.c @@ -588,6 +588,9 @@ void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k int serpent_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[32], pt[16], ct[16]; @@ -680,6 +683,7 @@ int serpent_test(void) } } return CRYPT_OK; + #endif } int serpent_keysize(int *desired_keysize) diff --git a/sha1.c b/sha1.c index 23f88aa..b273165 100644 --- a/sha1.c +++ b/sha1.c @@ -184,6 +184,9 @@ void sha1_done(hash_state * md, unsigned char *hash) int sha1_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[20]; @@ -213,6 +216,7 @@ int sha1_test(void) } } return CRYPT_OK; + #endif } #endif diff --git a/sha256.c b/sha256.c index 20f161a..33fd96f 100644 --- a/sha256.c +++ b/sha256.c @@ -34,8 +34,8 @@ static const unsigned long K[64] = { /* Various logical functions */ #define Ch(x,y,z) ((x & y) | (~x & z)) #define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR((x),(n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define S(x, n) ROR((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) @@ -180,6 +180,9 @@ void sha256_done(hash_state * md, unsigned char *hash) int sha256_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[32]; @@ -211,6 +214,7 @@ int sha256_test(void) } } return CRYPT_OK; + #endif } #endif diff --git a/sha384.c b/sha384.c index dcd9bb2..b07f4d6 100644 --- a/sha384.c +++ b/sha384.c @@ -51,6 +51,9 @@ void sha384_done(hash_state * md, unsigned char *hash) int sha384_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[48]; @@ -86,6 +89,7 @@ int sha384_test(void) } } return CRYPT_OK; + #endif } diff --git a/sha512.c b/sha512.c index 282733f..88317e4 100644 --- a/sha512.c +++ b/sha512.c @@ -209,6 +209,9 @@ void sha512_done(hash_state * md, unsigned char *hash) int sha512_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[64]; @@ -248,6 +251,7 @@ int sha512_test(void) } } return CRYPT_OK; + #endif } #ifdef SHA384 diff --git a/tiger.c b/tiger.c index 5dcd13b..cd0dd4c 100644 --- a/tiger.c +++ b/tiger.c @@ -687,6 +687,9 @@ void tiger_done(hash_state * md, unsigned char *hash) int tiger_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { char *msg; unsigned char hash[24]; @@ -731,6 +734,7 @@ int tiger_test(void) } } return CRYPT_OK; + #endif } #endif diff --git a/tommath.h b/tommath.h index d71a264..8e43f6c 100644 --- a/tommath.h +++ b/tommath.h @@ -1,19 +1,17 @@ /* LibTomMath, multiple-precision integer library -- Tom St Denis * - * LibTomMath is library that provides for multiple-precision + * LibTomMath is library that provides for multiple-precision * integer arithmetic as well as number theoretic functionality. - * + * * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. * * The library is free for all purposes without any express * guarantee it works. * * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org */ -#include - #ifndef BN_H_ #define BN_H_ @@ -36,18 +34,18 @@ extern "C" { #else -/* C on the other hand dosen't care */ -#define OPT_CAST +/* C on the other hand doesn't care */ +#define OPT_CAST #endif -/* some default configurations. +/* some default configurations. * - * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits - * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits * - * At the very least a mp_digit must be able to hold 7 bits - * [any size beyond that is ok provided it overflow the data type] + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] */ #ifdef MP_8BIT typedef unsigned char mp_digit; @@ -55,31 +53,50 @@ extern "C" { #elif defined(MP_16BIT) typedef unsigned short mp_digit; typedef unsigned long mp_word; -#else +#elif defined(MP_64BIT) + /* for GCC only on supported platforms */ #ifndef CRYPT - #ifdef _MSC_VER + typedef unsigned long long ulong64; + typedef signed long long long64; +#endif + + typedef ulong64 mp_digit; + typedef unsigned long mp_word __attribute__ ((mode(TI))); + + #define DIGIT_BIT 60 +#else + /* this is the default case, 28-bit digits */ + + /* this is to make porting into LibTomCrypt easier :-) */ +#ifndef CRYPT + #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ulong64; typedef signed __int64 long64; #else typedef unsigned long long ulong64; typedef signed long long long64; - #endif -#endif + #endif +#endif - /* default case */ typedef unsigned long mp_digit; typedef ulong64 mp_word; - - #define DIGIT_BIT 28 -#endif +#ifdef MP_31BIT + #define DIGIT_BIT 31 +#else + #define DIGIT_BIT 28 +#endif +#endif + +/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */ #ifndef DIGIT_BIT #define DIGIT_BIT ((CHAR_BIT * sizeof(mp_digit) - 1)) /* bits per digit */ #endif + #define MP_DIGIT_BIT DIGIT_BIT #define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) -#define MP_DIGIT_MAX MP_MASK +#define MP_DIGIT_MAX MP_MASK /* equalities */ #define MP_LT -1 /* less than */ @@ -99,9 +116,17 @@ typedef int mp_err; /* you'll have to tune these... */ extern int KARATSUBA_MUL_CUTOFF, KARATSUBA_SQR_CUTOFF, - MONTGOMERY_EXPT_CUTOFF; + TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF; -#define MP_PREC 64 /* default digits of precision */ +/* various build options */ +#define MP_PREC 64 /* default digits of precision (must be power of two) */ + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) typedef struct { int used, alloc, sign; @@ -120,6 +145,12 @@ int mp_init(mp_int *a); /* free a bignum */ void mp_clear(mp_int *a); +/* init a null terminated series of arguments */ +int mp_init_multi(mp_int *mp, ...); + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...); + /* exchange two ints */ void mp_exch(mp_int *a, mp_int *b); @@ -145,7 +176,7 @@ void mp_zero(mp_int *a); void mp_set(mp_int *a, mp_digit b); /* set a 32-bit const */ -int mp_set_int(mp_int *a, unsigned long b); +int mp_set_int(mp_int *a, unsigned int b); /* copy, b = a */ int mp_copy(mp_int *a, mp_int *b); @@ -164,22 +195,22 @@ void mp_rshd(mp_int *a, int b); /* left shift by "b" digits */ int mp_lshd(mp_int *a, int b); -/* c = a / 2^b */ +/* c = a / 2**b */ int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); /* b = a/2 */ int mp_div_2(mp_int *a, mp_int *b); -/* c = a * 2^b */ +/* c = a * 2**b */ int mp_mul_2d(mp_int *a, int b, mp_int *c); /* b = a*2 */ int mp_mul_2(mp_int *a, mp_int *b); -/* c = a mod 2^d */ +/* c = a mod 2**d */ int mp_mod_2d(mp_int *a, int b, mp_int *c); -/* computes a = 2^b */ +/* computes a = 2**b */ int mp_2expt(mp_int *a, int b); /* makes a pseudo-random int of a given size */ @@ -218,7 +249,7 @@ int mp_sub(mp_int *a, mp_int *b, mp_int *c); /* c = a * b */ int mp_mul(mp_int *a, mp_int *b, mp_int *c); -/* b = a^2 */ +/* b = a*a */ int mp_sqr(mp_int *a, mp_int *b); /* a/b => cb + d == a */ @@ -244,7 +275,10 @@ int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); /* a/b => cb + d == a */ int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); -/* c = a^b */ +/* a/3 => 3c + d == a */ +int mp_div_3(mp_int *a, mp_int *c, mp_digit *d); + +/* c = a**b */ int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); /* c = a mod b, 0 <= c < b */ @@ -273,7 +307,7 @@ int mp_gcd(mp_int *a, mp_int *b, mp_int *c); /* c = [a, b] or (a*b)/(a, b) */ int mp_lcm(mp_int *a, mp_int *b, mp_int *c); -/* finds one of the b'th root of a, such that |c|^b <= |a| +/* finds one of the b'th root of a, such that |c|**b <= |a| * * returns error if a < 0 and b is even */ @@ -290,7 +324,7 @@ int mp_reduce_setup(mp_int *a, mp_int *b); /* Barrett Reduction, computes a (mod b) with a precomputed value c * - * Assumes that 0 < a <= b^2, note if 0 > a > -(b^2) then you can merely + * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. */ int mp_reduce(mp_int *a, mp_int *b, mp_int *c); @@ -298,12 +332,12 @@ int mp_reduce(mp_int *a, mp_int *b, mp_int *c); /* setups the montgomery reduction */ int mp_montgomery_setup(mp_int *a, mp_digit *mp); -/* computes a = B^n mod b without division or multiplication useful for +/* computes a = B**n mod b without division or multiplication useful for * normalizing numbers in a Montgomery system. */ int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); -/* computes xR^-1 == x (mod N) via Montgomery Reduction */ +/* computes x/R == x (mod N) via Montgomery Reduction */ int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); /* returns 1 if a is a valid DR modulus */ @@ -315,32 +349,47 @@ void mp_dr_setup(mp_int *a, mp_digit *d); /* reduces a modulo b using the Diminished Radix method */ int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); -/* d = a^b (mod c) */ +/* returns true if a can be reduced with mp_reduce_2k */ +int mp_reduce_is_2k(mp_int *a); + +/* determines k value for 2k reduction */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k); + +/* d = a**b (mod c) */ int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); /* ---> Primes <--- */ -#define PRIME_SIZE 256 /* number of primes */ -/* table of first 256 primes */ +/* number of primes */ +#ifdef MP_8BIT + #define PRIME_SIZE 31 +#else + #define PRIME_SIZE 256 +#endif + +/* table of first PRIME_SIZE primes */ extern const mp_digit __prime_tab[]; -/* result=1 if a is divisible by one of the first 256 primes */ +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ int mp_prime_is_divisible(mp_int *a, int *result); -/* performs one Fermat test of "a" using base "b". - * Sets result to 0 if composite or 1 if probable prime +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime */ int mp_prime_fermat(mp_int *a, mp_int *b, int *result); /* performs one Miller-Rabin test of "a" using base "b". - * Sets result to 0 if composite or 1 if probable prime + * Sets result to 0 if composite or 1 if probable prime */ int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); /* performs t rounds of Miller-Rabin on "a" using the first * t prime bases. Also performs an initial sieve of trial * division. Determines if "a" is prime with probability - * of error no more than (1/4)^t. + * of error no more than (1/4)**t. * * Sets result to 1 if probably prime, 0 otherwise */ @@ -367,6 +416,9 @@ int mp_read_radix(mp_int *a, char *str, int radix); int mp_toradix(mp_int *a, char *str, int radix); int mp_radix_size(mp_int *a, int radix); +int mp_fread(mp_int *a, int radix, FILE *stream); +int mp_fwrite(mp_int *a, int radix, FILE *stream); + #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) #define mp_raw_size(mp) mp_signed_bin_size(mp) #define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) @@ -390,10 +442,13 @@ int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); int fast_s_mp_sqr(mp_int *a, mp_int *b); int s_mp_sqr(mp_int *a, mp_int *b); int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c); int mp_karatsuba_sqr(mp_int *a, mp_int *b); +int mp_toom_sqr(mp_int *a, mp_int *b); int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c); int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); void bn_reverse(unsigned char *s, int len); #ifdef __cplusplus diff --git a/twofish.c b/twofish.c index cfaa0d1..2d09589 100644 --- a/twofish.c +++ b/twofish.c @@ -633,6 +633,9 @@ void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k int twofish_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const struct { int keylen; unsigned char key[32], pt[16], ct[16]; @@ -682,6 +685,7 @@ int twofish_test(void) } } return CRYPT_OK; +#endif } int twofish_keysize(int *desired_keysize) diff --git a/xtea.c b/xtea.c index 21b0840..c0e4715 100644 --- a/xtea.c +++ b/xtea.c @@ -107,6 +107,9 @@ void xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key int xtea_test(void) { + #ifndef LTC_TEST + return CRYPT_NOP; + #else static const unsigned char key[16] = { 0x78, 0x56, 0x34, 0x12, 0xf0, 0xcd, 0xcb, 0x9a, 0x48, 0x37, 0x26, 0x15, 0xc0, 0xbf, 0xae, 0x9d }; @@ -129,6 +132,7 @@ int xtea_test(void) } return CRYPT_OK; + #endif } int xtea_keysize(int *desired_keysize)