From 0f999a4e9e5323b4369e7858bace19a68aaf2581 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Mon, 3 Mar 2003 01:03:50 +0000 Subject: [PATCH] added libtomcrypt-0.81 --- authors | 11 +- changes | 13 + config.pl | 324 +- crypt.pdf | Bin 337360 -> 337368 bytes demos/test.c | 2439 +++++++------ demos/test.c~ | 1427 ++++++++ ecc.c | 117 +- ecc_sys.c | 22 +- examples/ch2-01.c | 35 + legal.txt | 80 + makefile | 212 +- makefile.out | 24 + makefile.ps2 | 311 -- makefile.vc | 274 -- mpi-config.h | 87 - mpi-types.h | 16 - mpi.c | 8867 +++++++++++++++++++++++++-------------------- mpi.h | 227 -- mpi.old | 4216 --------------------- mycrypt.h | 8 +- mycrypt_cfg.h | 17 - mycrypt_custom.h | 76 + mycrypt_pk.h | 18 +- mycrypt_prng.h | 6 +- prime.c | 5 +- rsa.c | 1 - tommath.h | 352 ++ 27 files changed, 8697 insertions(+), 10488 deletions(-) create mode 100644 demos/test.c~ create mode 100644 examples/ch2-01.c create mode 100644 legal.txt create mode 100644 makefile.out delete mode 100644 makefile.ps2 delete mode 100644 makefile.vc delete mode 100644 mpi-config.h delete mode 100644 mpi-types.h delete mode 100644 mpi.h delete mode 100644 mpi.old create mode 100644 mycrypt_custom.h create mode 100644 tommath.h diff --git a/authors b/authors index 525e646..ba4ea6b 100644 --- a/authors +++ b/authors @@ -26,6 +26,9 @@ tomstdenis@yahoo.com. 6) Clay Culver Submitted a fix for "rsa.c" which cleaned up some code. Submited some other fixes too. :-) + Clay has helped find bugs in various pieces of code including the registry functions, base64 routines + and the make process. He is also now the primary author of the libtomcrypt reference manual and has plan + at making a HTML version. 7) Jason Klapste @@ -39,10 +42,14 @@ yarrow code can now default to any cipher/hash that is left after you remove the 9) Wayne Scott (wscott@bitmover.com) - Submitted base64 that complies with the RFC standards. + Submitted base64 that complies with the RFC standards. Submitted some ideas to improve the RSA key generation + as well. 10) Sky Schulz (sky@ogn.com) Has submitted a set of ideas to improve the library and make it more attractive for professional users. - \ No newline at end of file +11) Mike Frysinger + + Together with Clay came up with a more "unix friendly" makefile. Mike Frysinger has been keeping copies of + the library for the Gentoo linux distribution. \ No newline at end of file diff --git a/changes b/changes index c8bed88..d80dd95 100644 --- a/changes +++ b/changes @@ -1,3 +1,16 @@ +Jan 16th, 2003 +v0.81 -- Merged in new makefile from Clay Culver and Mike Frysinger + -- Sped up the ECC mulmod() routine by making the word size adapt to the input. Saves a whopping 9 point + operations on 521-bit keys now (translates to about 8ms on my Athlon XP). I also now use barrett reduction + as much as possible. This sped the routine up quite a bit. + -- Fixed a huge flaw in ecc_verify_hash() where it would return CRYPT_OK on error... Now fixed. + -- Fixed up config.pl by fixing an invalid query and the file is saved in non-windows [e.g. not CR/LF] format + (fix due to Mika Boström) + -- Merged in LibTomMath for kicks + -- Changed the build process so that by default "mycrypt_custom.h" is included and provided + The makefile doesn't include any build options anymore + -- Removed the PS2 and VC makefiles. + Dec 16th, 2002 v0.80 -- Found a change I made to the MPI that is questionable. Not quite a bug but definately not desired. Had todo with the digit shifting. In v0.79 I simply truncated without zeroing. It didn't cause problems during my diff --git a/config.pl b/config.pl index 2a03557..4f68282 100644 --- a/config.pl +++ b/config.pl @@ -1,162 +1,162 @@ -#!/usr/bin/perl -# -# Generates a makefile based on user input -# -# Tom St Denis, tomstdenis@yahoo.com, http://tom.iahu.ca - -@settings = ( - "CC,Compiler,gcc", - "AR,Archiver,ar", - "LD,Linker,ld", - "CFLAGS,Optimizations,-Os", - "CFLAGS,Warnings,-Wall -Wsign-compare -W -Wno-unused -Werror", - "CFLAGS,Include Paths,-I./", - "CFLAGS,Other compiler options,", - "CFLAGS,XMALLOC,-DXMALLOC=malloc", - "CFLAGS,XREALLOC,-DXREALLOC=realloc", - "CFLAGS,XCALLOC,-DXCALLOC=calloc", - "CFLAGS,XFREE,-DXFREE=free", - "CFLAGS,XCLOCK,-DXCLOCK=clock", - "CFLAGS,XCLOCKS_PER_SEC,-DXCLOCKS_PER_SEC=CLOCKS_PER_SEC", -); - -@opts = ( - "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", - - "BLOWFISH,Include Blowfish block cipher,y", - "RC2,Include RC2 block cipher,y", - "RC5,Include RC5 block cipher,y", - "RC6,Include RC6 block cipher,y", - "SERPENT,Include Serpent block cipher,y", - "SAFERP,Include Safer+ block cipher,y", - "SAFER,Include Safer-64 block ciphers,y", - "RIJNDAEL,Include Rijndael (AES) block cipher,y", - "XTEA,Include XTEA block cipher,y", - "TWOFISH,Include Twofish block cipher,y", - "TWOFISH_SMALL,Include Use a low ram variant of Twofish,n", - "TWOFISH_TABLES,Include Use precomputed tables to speed up the low-ram variant,n", - "DES,Include DES and 3DES block ciphers,y", - "CAST5,Include CAST5 (aka CAST-128) block cipher,y", - "NOEKEON,Include Noekeon block cipher,y", - - "CFB,Include CFB block mode of operation,y", - "OFB,Include OFB block mode of operation,y", - "ECB,Include ECB block mode of operation,y", - "CBC,Include CBC block mode of operation,y", - "CTR,Include CTR block mode of operation,y", - - "SHA512,Include SHA512 one-way hash,y", - "SHA384,Include SHA384 one-way hash (requires SHA512),y", - "SHA256,Include SHA256 one-way hash,y", - "TIGER,Include TIGER one-way hash,y", - "SHA1,Include SHA1 one-way hash,y", - "MD5,Include MD5 one-way hash,y", - "MD4,Include MD4 one-way hash,y", - "MD2,Include MD2 one-way hash,y", - "HMAC,Include Hash based Message Authentication Support,y", - - "BASE64,Include Base64 encoding support,y", - - "YARROW,Include Yarrow PRNG,y", - "SPRNG,Include Secure PRNG base on RNG code,y", - "RC4,Include RC4 PRNG,y", - "DEVRANDOM,Use /dev/random or /dev/urandom if available?,y", - "TRY_URANDOM_FIRST,Try /dev/urandom before /dev/random?,n", - - "MRSA,Include RSA public key support,y", - "MDH,Include Diffie-Hellman (over Z/pZ) public key support,y", - "MECC,Include Eliptic Curve public key crypto support,y", - "KR,Include Keyring support (groups all three PK systems),y", - - "DH768,768-bit DH key support,y", - "DH1024,1024-bit DH key support,y", - "DH1280,1280-bit DH key support,y", - "DH1536,1280-bit DH key support,y", - "DH1792,1792-bit DH key support,y", - "DH2048,2048-bit DH key support,y", - "DH2560,2560-bit DH key support,y", - "DH3072,3072-bit DH key support,y", - "DH4096,4096-bit DH key support,y", - - "ECC160,160-bit ECC key support,y", - "ECC192,192-bit ECC key support,y", - "ECC224,224-bit ECC key support,y", - "ECC256,256-bit ECC key support,y", - "ECC384,384-bit ECC key support,y", - "ECC521,521-bit ECC key support,y", - - "GF,Include GF(2^w) math support (not used internally),n", - - "MPI,Include MPI big integer math support (required by the public key code),y", - "MPI_FASTEXPT,Use the faster exponentiation code (uses some heap but is faster),y", - "MPI_FASTEXPT_LOWMEM,Use the low ram variant of the fast code\nRequires the fast code to enabled,n", -); - -# scan for switches and make variables -for (@settings) { - @m = split(",", $_); - print "@m[1]: [@m[2]] "; - $r = <>; $r = @m[2] if ($r eq "\n"); - chomp($r); - @vars{@m[0]} = @vars{@m[0]} . $r . " "; -} - -# scan for build flags -for (@opts) { - @m = split(",", $_); - print "@m[1]: [@m[2]]"; - $r = <>; @vars{'CFLAGS'} = @vars{'CFLAGS'} . "-D" . $m[0] . " " if (($r eq "y\n") || ($r eq "\n" && @m[2] eq "y")); -} - -# write header - -open(OUT,">mycrypt_custom.h"); -print OUT "/* This header is meant to be included before mycrypt.h in projects where\n"; -print OUT " * you don't want to throw all the defines in a makefile. \n"; -print OUT " */\n\n#ifndef MYCRYPT_CUSTOM_H_\n#define MYCRYPT_CUSTOM_H_\n\n#ifdef CRYPT\n\t#error mycrypt_custom.h should be included before mycrypt.h\n#endif\n\n"; - -@m = split(" ", @vars{'CFLAGS'}); -for (@m) { - if ($_ =~ /^-D/) { - $_ =~ s/-D//; - $_ =~ s/=/" "/ge; - print OUT "#define $_\n"; - } -} - -print OUT "\n\n#include \n\n#endif\n\n"; -close OUT; - -print "\n\nmycrypt_custom.h generated.\n"; - -open(OUT,">makefile.out"); -print OUT "#makefile generated with config.pl\n#\n#Tom St Denis (tomstdenis\@yahoo.com, http://tom.iahu.ca) \n\n"; - -# output unique vars first -for (@settings) { - @m = split(",", $_); - print OUT "@m[0] = @vars{@m[0]}\n" if (@vars{@m[0]} ne "" && @m[0] ne "CFLAGS"); - print OUT "CFLAGS += @vars{@m[0]}\n" if (@vars{@m[0]} ne "" && @m[0] eq "CFLAGS"); - @vars{@m[0]} = ""; -} - -# 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"; - -# some depends -print OUT "rsa.o: rsa_sys.c\ndh.o: dh_sys.c\necc.o: ecc_sys.c\n\n"; - -# targets -print OUT "library: \$(OBJECTS)\n\t \$(AR) r libtomcrypt.a \$(OBJECTS)\n\t ranlib libtomcrypt.a\n\n"; -print OUT "clean:\n\trm -f \$(OBJECTS) libtomcrypt.a \n\n"; - -close OUT; - -print "makefile.out generated.\n"; - -print "\nNow use makefile.out to build the library, e.g. `make -f makefile.out'\n"; -print "In your project just include mycrypt_custom.h (you don't have to include mycrypt.h \n"; -print "but if you do make sure mycrypt_custom.h appears first) your settings should be intact.\n"; \ No newline at end of file +#!/usr/bin/perl +# +# Generates a makefile based on user input +# +# Tom St Denis, tomstdenis@yahoo.com, http://tom.iahu.ca + +@settings = ( + "CC,Compiler,gcc", + "AR,Archiver,ar", + "LD,Linker,ld", + "CFLAGS,Optimizations,-Os", + "CFLAGS,Warnings,-Wall -Wsign-compare -W -Wno-unused -Werror", + "CFLAGS,Include Paths,-I./", + "CFLAGS,Other compiler options,", + "CFLAGS,XMALLOC,-DXMALLOC=malloc", + "CFLAGS,XREALLOC,-DXREALLOC=realloc", + "CFLAGS,XCALLOC,-DXCALLOC=calloc", + "CFLAGS,XFREE,-DXFREE=free", + "CFLAGS,XCLOCK,-DXCLOCK=clock", + "CFLAGS,XCLOCKS_PER_SEC,-DXCLOCKS_PER_SEC=CLOCKS_PER_SEC", +); + +@opts = ( + "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", + + "BLOWFISH,Include Blowfish block cipher,y", + "RC2,Include RC2 block cipher,y", + "RC5,Include RC5 block cipher,y", + "RC6,Include RC6 block cipher,y", + "SERPENT,Include Serpent block cipher,y", + "SAFERP,Include Safer+ block cipher,y", + "SAFER,Include Safer-64 block ciphers,y", + "RIJNDAEL,Include Rijndael (AES) block cipher,y", + "XTEA,Include XTEA block cipher,y", + "TWOFISH,Include Twofish block cipher,y", + "TWOFISH_SMALL,Include Use a low ram variant of Twofish,n", + "TWOFISH_TABLES,Include Use precomputed tables to speed up the low-ram variant,n", + "DES,Include DES and 3DES block ciphers,y", + "CAST5,Include CAST5 (aka CAST-128) block cipher,y", + "NOEKEON,Include Noekeon block cipher,y", + + "CFB,Include CFB block mode of operation,y", + "OFB,Include OFB block mode of operation,y", + "ECB,Include ECB block mode of operation,y", + "CBC,Include CBC block mode of operation,y", + "CTR,Include CTR block mode of operation,y", + + "SHA512,Include SHA512 one-way hash,y", + "SHA384,Include SHA384 one-way hash (requires SHA512),y", + "SHA256,Include SHA256 one-way hash,y", + "TIGER,Include TIGER one-way hash,y", + "SHA1,Include SHA1 one-way hash,y", + "MD5,Include MD5 one-way hash,y", + "MD4,Include MD4 one-way hash,y", + "MD2,Include MD2 one-way hash,y", + "HMAC,Include Hash based Message Authentication Support,y", + + "BASE64,Include Base64 encoding support,y", + + "YARROW,Include Yarrow PRNG,y", + "SPRNG,Include Secure PRNG base on RNG code,y", + "RC4,Include RC4 PRNG,y", + "DEVRANDOM,Use /dev/random or /dev/urandom if available?,y", + "TRY_URANDOM_FIRST,Try /dev/urandom before /dev/random?,n", + + "MRSA,Include RSA public key support,y", + "MDH,Include Diffie-Hellman (over Z/pZ) public key support,y", + "MECC,Include Eliptic Curve public key crypto support,y", + "KR,Include Keyring support (groups all three PK systems),y", + + "DH768,768-bit DH key support,y", + "DH1024,1024-bit DH key support,y", + "DH1280,1280-bit DH key support,y", + "DH1536,1536-bit DH key support,y", + "DH1792,1792-bit DH key support,y", + "DH2048,2048-bit DH key support,y", + "DH2560,2560-bit DH key support,y", + "DH3072,3072-bit DH key support,y", + "DH4096,4096-bit DH key support,y", + + "ECC160,160-bit ECC key support,y", + "ECC192,192-bit ECC key support,y", + "ECC224,224-bit ECC key support,y", + "ECC256,256-bit ECC key support,y", + "ECC384,384-bit ECC key support,y", + "ECC521,521-bit ECC key support,y", + + "GF,Include GF(2^w) math support (not used internally),n", + + "MPI,Include MPI big integer math support (required by the public key code),y", +); + +# scan for switches and make variables +for (@settings) { + @m = split(",", $_); + print "@m[1]: [@m[2]] "; + $r = <>; $r = @m[2] if ($r eq "\n"); + chomp($r); + @vars{@m[0]} = @vars{@m[0]} . $r . " "; +} + +# scan for build flags +for (@opts) { + @m = split(",", $_); + print "@m[1]: [@m[2]]"; + $r = <>; @vars{'CFLAGS'} = @vars{'CFLAGS'} . "-D" . $m[0] . " " if (($r eq "y\n") || ($r eq "\n" && @m[2] eq "y")); +} + +# write header + +open(OUT,">mycrypt_custom.h"); +print OUT "/* This header is meant to be included before mycrypt.h in projects where\n"; +print OUT " * you don't want to throw all the defines in a makefile. \n"; +print OUT " */\n\n#ifndef MYCRYPT_CUSTOM_H_\n#define MYCRYPT_CUSTOM_H_\n\n#ifdef CRYPT\n\t#error mycrypt_custom.h should be included before mycrypt.h\n#endif\n\n"; + +@m = split(" ", @vars{'CFLAGS'}); +for (@m) { + if ($_ =~ /^-D/) { + $_ =~ s/-D//; + $_ =~ s/=/" "/ge; + print OUT "#define $_\n"; + } +} + +print OUT "\n\n#include \n\n#endif\n\n"; +close OUT; + +print "\n\nmycrypt_custom.h generated.\n"; + +open(OUT,">makefile.out"); +print OUT "#makefile generated with config.pl\n#\n#Tom St Denis (tomstdenis\@yahoo.com, http://tom.iahu.ca) \n\n"; + +# output unique vars first +@vars{'CFLAGS'} =~ s/-D.+ /""/ge; + +for (@settings) { + @m = split(",", $_); + print OUT "@m[0] = @vars{@m[0]}\n" if (@vars{@m[0]} ne "" && @m[0] ne "CFLAGS"); + print OUT "CFLAGS += @vars{@m[0]}\n" if (@vars{@m[0]} ne "" && @m[0] eq "CFLAGS"); + @vars{@m[0]} = ""; +} + +# 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"; + +# some depends +print OUT "rsa.o: rsa_sys.c\ndh.o: dh_sys.c\necc.o: ecc_sys.c\n\n"; + +# targets +print OUT "library: \$(OBJECTS)\n\t \$(AR) r libtomcrypt.a \$(OBJECTS)\n\t ranlib libtomcrypt.a\n\n"; +print OUT "clean:\n\trm -f \$(OBJECTS) libtomcrypt.a \n\n"; + +close OUT; + +print "makefile.out generated.\n"; + +print "\nNow use makefile.out to build the library, e.g. `make -f makefile.out'\n"; +print "In your project just include mycrypt_custom.h (you don't have to include mycrypt.h \n"; +print "but if you do make sure mycrypt_custom.h appears first) your settings should be intact.\n"; diff --git a/crypt.pdf b/crypt.pdf index 976f7e2520587ba39c66d1f44c908abf0bae5ca6..6cd134fb1539cff5a39f820c774b07a185c21a9d 100644 GIT binary patch delta 77191 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 diff --git a/demos/test.c b/demos/test.c index cc1d217..c94a8b3 100644 --- a/demos/test.c +++ b/demos/test.c @@ -9,560 +9,763 @@ out the functionality of the library */ #include "../mycrypt.h" -int errno; +int errno; -int null_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +int +null_setup (const unsigned char *key, int keylen, int num_rounds, + symmetric_key * skey) { - return CRYPT_OK; + return CRYPT_OK; } -void null_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +void +null_ecb_encrypt (const unsigned char *pt, unsigned char *ct, + symmetric_key * key) { - memcpy(ct, pt, 8); + memcpy (ct, pt, 8); } -void null_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +void +null_ecb_decrypt (const unsigned char *ct, unsigned char *pt, + symmetric_key * key) { - memcpy(pt, ct, 8); + memcpy (pt, ct, 8); } -int null_test(void) +int +null_test (void) { - return CRYPT_OK; + return CRYPT_OK; } -int null_keysize(int *desired_keysize) +int +null_keysize (int *desired_keysize) { - return CRYPT_OK; -} + return CRYPT_OK; +} -const struct _cipher_descriptor null_desc = -{ - "memcpy()", - 255, - 8, 8, 8, 1, - &null_setup, - &null_ecb_encrypt, - &null_ecb_decrypt, - &null_test, - &null_keysize +const struct _cipher_descriptor null_desc = { + "memcpy()", + 255, + 8, 8, 8, 1, + &null_setup, + &null_ecb_encrypt, + &null_ecb_decrypt, + &null_test, + &null_keysize }; prng_state prng; -void store_tests(void) +void +store_tests (void) { - unsigned char buf[8]; - unsigned long L; - ulong64 LL; + unsigned char buf[8]; + unsigned long L; + ulong64 LL; - printf("LOAD32/STORE32 tests\n"); - L = 0x12345678UL; - STORE32L(L, &buf[0]); - L = 0; - LOAD32L(L, &buf[0]); - if (L != 0x12345678UL) { printf("LOAD/STORE32 Little don't work\n"); exit(-1); } - LL = CONST64(0x01020304050607); - STORE64L(LL, &buf[0]); - LL = 0; - LOAD64L(LL, &buf[0]) - if (LL != CONST64(0x01020304050607)) { printf("LOAD/STORE64 Little don't work\n"); exit(-1); } + printf ("LOAD32/STORE32 tests\n"); + L = 0x12345678UL; + STORE32L (L, &buf[0]); + L = 0; + LOAD32L (L, &buf[0]); + if (L != 0x12345678UL) { + printf ("LOAD/STORE32 Little don't work\n"); + exit (-1); + } + LL = CONST64 (0x01020304050607); + STORE64L (LL, &buf[0]); + LL = 0; + LOAD64L (LL, &buf[0]) + if (LL != CONST64 (0x01020304050607)) { + printf ("LOAD/STORE64 Little don't work\n"); + exit (-1); + } - L = 0x12345678UL; - STORE32H(L, &buf[0]); - L = 0; - LOAD32H(L, &buf[0]); - if (L != 0x12345678UL) { printf("LOAD/STORE32 High don't work\n"); exit(-1); } - LL = CONST64(0x01020304050607); - STORE64H(LL, &buf[0]); - LL = 0; - LOAD64H(LL, &buf[0]) - if (LL != CONST64(0x01020304050607)) { printf("LOAD/STORE64 High don't work\n"); exit(-1); } + L = 0x12345678UL; + STORE32H (L, &buf[0]); + L = 0; + LOAD32H (L, &buf[0]); + if (L != 0x12345678UL) { + printf ("LOAD/STORE32 High don't work\n"); + exit (-1); + } + LL = CONST64 (0x01020304050607); + STORE64H (LL, &buf[0]); + LL = 0; + LOAD64H (LL, &buf[0]) + if (LL != CONST64 (0x01020304050607)) { + printf ("LOAD/STORE64 High don't work\n"); + exit (-1); + } } -void cipher_tests(void) { - int x; +void +cipher_tests (void) +{ + int x; - printf("Ciphers compiled in\n"); - for (x = 0; cipher_descriptor[x].name != NULL; x++) { - printf(" %12s (%2d) Key Size: %4d to %4d, Block Size: %3d, Default # of rounds: %2d\n", cipher_descriptor[x].name, - cipher_descriptor[x].ID, - cipher_descriptor[x].min_key_length*8,cipher_descriptor[x].max_key_length*8, - cipher_descriptor[x].block_length*8, cipher_descriptor[x].default_rounds); - } + printf ("Ciphers compiled in\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf + (" %12s (%2d) Key Size: %4d to %4d, Block Size: %3d, Default # of rounds: %2d\n", + cipher_descriptor[x].name, cipher_descriptor[x].ID, + cipher_descriptor[x].min_key_length * 8, + cipher_descriptor[x].max_key_length * 8, + cipher_descriptor[x].block_length * 8, + cipher_descriptor[x].default_rounds); + } } -void ecb_tests(void) +void +ecb_tests (void) { - int x; + int x; - printf("ECB tests\n"); - for (x = 0; cipher_descriptor[x].name != NULL; x++) { - printf(" %12s: ", - cipher_descriptor[x].name); - if ((errno = cipher_descriptor[x].test()) != CRYPT_OK) { - printf(" **failed** Reason: %s\n", error_to_string(errno)); - exit(-1); - } else { - printf("passed\n"); - } - } + printf ("ECB tests\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf (" %12s: ", cipher_descriptor[x].name); + if ((errno = cipher_descriptor[x].test ()) != CRYPT_OK) { + printf (" **failed** Reason: %s\n", error_to_string (errno)); + exit (-1); + } else { + printf ("passed\n"); + } + } } #ifdef CBC -void cbc_tests(void) +void +cbc_tests (void) { - symmetric_CBC cbc; - int x, y; - unsigned char blk[32], ct[32], key[32], IV[32]; - const unsigned char test[] = { 0XFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + symmetric_CBC cbc; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + const unsigned char test[] = + { 0XFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - printf("CBC tests\n"); - /* ---- CBC ENCODING ---- */ - /* make up a block and IV */ - for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + printf ("CBC tests\n"); + /* ---- CBC ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) + blk[x] = IV[x] = x; - /* now lets start a cbc session */ - if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { - printf("CBC Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a cbc session */ + if ((errno = + cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cbc)) != CRYPT_OK) { + printf ("CBC Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets encode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = cbc_encrypt(blk+8*x, ct+8*x, &cbc)) != CRYPT_OK) { - printf("CBC encrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cbc_encrypt (blk + 8 * x, ct + 8 * x, &cbc)) != CRYPT_OK) { + printf ("CBC encrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - zeromem(blk, sizeof(blk)); + zeromem (blk, sizeof (blk)); - /* ---- CBC DECODING ---- */ - /* make up a IV */ - for (x = 0; x < 32; x++) IV[x] = x; + /* ---- CBC DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) + IV[x] = x; - /* now lets start a cbc session */ - if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { - printf("CBC Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a cbc session */ + if ((errno = + cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cbc)) != CRYPT_OK) { + printf ("CBC Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets decode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = cbc_decrypt(ct+8*x, blk+8*x, &cbc)) != CRYPT_OK) { - printf("CBC decrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cbc_decrypt (ct + 8 * x, blk + 8 * x, &cbc)) != CRYPT_OK) { + printf ("CBC decrypt: %s\n", error_to_string (errno)); + exit (-1); } - } - + } - /* print output */ - for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; - printf(" %s\n", y?"failed":"passed"); - /* lets actually check the bytes */ - memset(IV, 0, 8); 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 */ - 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 */ - if (memcmp(ct, test, 16)) { - printf("CBC failed logical testing.\n"); - for (x = 0; x < 16; x++) printf("%02x ", ct[x]); - printf("\n"); - exit(-1); - } else { - printf("CBC passed logical testing.\n"); - } + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + + /* lets actually check the bytes */ + memset (IV, 0, 8); + 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 */ + 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 */ + if (memcmp (ct, test, 16)) { + printf ("CBC failed logical testing.\n"); + for (x = 0; x < 16; x++) + printf ("%02x ", ct[x]); + printf ("\n"); + exit (-1); + } else { + printf ("CBC passed logical testing.\n"); + } } #else -void cbc_tests(void) { printf("CBC not compiled in\n"); } +void +cbc_tests (void) +{ + printf ("CBC not compiled in\n"); +} #endif #ifdef OFB -void ofb_tests(void) +void +ofb_tests (void) { - symmetric_OFB ofb; - int x, y; - unsigned char blk[32], ct[32], key[32], IV[32]; + symmetric_OFB ofb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; - printf("OFB tests\n"); - /* ---- ofb ENCODING ---- */ - /* make up a block and IV */ - for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + printf ("OFB tests\n"); + /* ---- ofb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) + blk[x] = IV[x] = x; - /* now lets start a ofb session */ - if ((errno = ofb_start(find_cipher("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { - printf("OFB Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a ofb session */ + if ((errno = + ofb_start (find_cipher ("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf ("OFB Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets encode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = ofb_encrypt(blk+8*x, ct+8*x, 8, &ofb)) != CRYPT_OK) { - printf("OFB encrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ofb_encrypt (blk + 8 * x, ct + 8 * x, 8, &ofb)) != CRYPT_OK) { + printf ("OFB encrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - zeromem(blk, sizeof(blk)); + zeromem (blk, sizeof (blk)); - /* ---- ofb DECODING ---- */ - /* make up a IV */ - for (x = 0; x < 32; x++) IV[x] = x; + /* ---- ofb DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) + IV[x] = x; - /* now lets start a ofb session */ - if ((errno = ofb_start(find_cipher("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { - printf("OFB setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a ofb session */ + if ((errno = + ofb_start (find_cipher ("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf ("OFB setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets decode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = ofb_decrypt(ct+8*x, blk+8*x, 8, &ofb)) != CRYPT_OK) { - printf("OFB decrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ofb_decrypt (ct + 8 * x, blk + 8 * x, 8, &ofb)) != CRYPT_OK) { + printf ("OFB decrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - /* print output */ - for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; - printf(" %s\n", y?"failed":"passed"); - if (y) exit(-1); + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); } #else -void ofb_tests(void) { printf("OFB not compiled in\n"); } +void +ofb_tests (void) +{ + printf ("OFB not compiled in\n"); +} #endif #ifdef CFB -void cfb_tests(void) +void +cfb_tests (void) { - symmetric_CFB cfb; - int x, y; - unsigned char blk[32], ct[32], key[32], IV[32]; + symmetric_CFB cfb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; - printf("CFB tests\n"); - /* ---- cfb ENCODING ---- */ - /* make up a block and IV */ - for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + printf ("CFB tests\n"); + /* ---- cfb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) + blk[x] = IV[x] = x; - /* now lets start a cfb session */ - if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { - printf("CFB setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a cfb session */ + if ((errno = + cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cfb)) != CRYPT_OK) { + printf ("CFB setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets encode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = cfb_encrypt(blk+8*x, ct+8*x, 8, &cfb)) != CRYPT_OK) { - printf("CFB encrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cfb_encrypt (blk + 8 * x, ct + 8 * x, 8, &cfb)) != CRYPT_OK) { + printf ("CFB encrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - zeromem(blk, sizeof(blk)); + zeromem (blk, sizeof (blk)); - /* ---- cfb DECODING ---- */ - /* make up ahash_descriptor[prng->yarrow.hash].hashsize IV */ - for (x = 0; x < 32; x++) IV[x] = x; + /* ---- cfb DECODING ---- */ + /* make up ahash_descriptor[prng->yarrow.hash].hashsize IV */ + for (x = 0; x < 32; x++) + IV[x] = x; - /* now lets start a cfb session */ - if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { - printf("CFB Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a cfb session */ + if ((errno = + cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cfb)) != CRYPT_OK) { + printf ("CFB Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets decode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = cfb_decrypt(ct+8*x, blk+8*x, 8, &cfb)) != CRYPT_OK) { - printf("CFB decrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cfb_decrypt (ct + 8 * x, blk + 8 * x, 8, &cfb)) != CRYPT_OK) { + printf ("CFB decrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - /* print output */ - for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; - printf(" %s\n", y?"failed":"passed"); - if (y) exit(-1); + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); } #else -void cfb_tests(void) { printf("CFB not compiled in\n"); } +void +cfb_tests (void) +{ + printf ("CFB not compiled in\n"); +} #endif #ifdef CTR -void ctr_tests(void) +void +ctr_tests (void) { - symmetric_CTR ctr; - int x, y; - unsigned char blk[32], ct[32], key[32], count[32]; - const unsigned char test[] = { 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }; + symmetric_CTR ctr; + int x, y; + unsigned char blk[32], ct[32], key[32], count[32]; + const unsigned char test[] = + { 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }; - printf("CTR tests\n"); - /* ---- CTR ENCODING ---- */ - /* make up a block and IV */ - for (x = 0; x < 32; x++) blk[x] = count[x] = x; + printf ("CTR tests\n"); + /* ---- CTR ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) + blk[x] = count[x] = x; - /* now lets start a ctr session */ - if ((errno = ctr_start(find_cipher("xtea"), count, key, 16, 0, &ctr)) != CRYPT_OK) { - printf("CTR Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a ctr session */ + if ((errno = + ctr_start (find_cipher ("xtea"), count, key, 16, 0, + &ctr)) != CRYPT_OK) { + printf ("CTR Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets encode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = ctr_encrypt(blk+8*x, ct+8*x, 8, &ctr)) != CRYPT_OK) { - printf("CTR encrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ctr_encrypt (blk + 8 * x, ct + 8 * x, 8, &ctr)) != CRYPT_OK) { + printf ("CTR encrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - zeromem(blk, sizeof(blk)); + zeromem (blk, sizeof (blk)); - /* ---- CTR DECODING ---- */ - /* make up a IV */ - for (x = 0; x < 32; x++) count[x] = x; + /* ---- CTR DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) + count[x] = x; - /* now lets start a cbc session */ - if ((errno = ctr_start(find_cipher("xtea"), count, key, 16, 0, &ctr)) != CRYPT_OK) { - printf("CTR Setup: %s\n", error_to_string(errno)); exit(-1); } + /* now lets start a cbc session */ + if ((errno = + ctr_start (find_cipher ("xtea"), count, key, 16, 0, + &ctr)) != CRYPT_OK) { + printf ("CTR Setup: %s\n", error_to_string (errno)); + exit (-1); + } - /* now lets decode 32 bytes */ - for (x = 0; x < 4; x++) { - if ((errno = ctr_decrypt(ct+8*x, blk+8*x, 8, &ctr)) != CRYPT_OK) { - printf("CTR decrypt: %s\n", error_to_string(errno)); exit(-1); + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ctr_decrypt (ct + 8 * x, blk + 8 * x, 8, &ctr)) != CRYPT_OK) { + printf ("CTR decrypt: %s\n", error_to_string (errno)); + exit (-1); } - } + } - /* print output */ - for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; - printf(" %s\n", y?"failed":"passed"); - if (y) exit(-1); + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); - /* lets actually check the bytes */ - memset(count, 0, 8); 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 */ - 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 */ - if (memcmp(ct, test, 16)) { - printf("CTR failed logical testing.\n"); - for (x = 0; x < 16; x++) printf("%02x ", ct[x]); - printf("\n"); - } else { - printf("CTR passed logical testing.\n"); - } + /* lets actually check the bytes */ + memset (count, 0, 8); + 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 */ + 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 */ + if (memcmp (ct, test, 16)) { + printf ("CTR failed logical testing.\n"); + for (x = 0; x < 16; x++) + printf ("%02x ", ct[x]); + printf ("\n"); + } else { + printf ("CTR passed logical testing.\n"); + } } #else -void ctr_tests(void) { printf("CTR not compiled in\n"); } +void +ctr_tests (void) +{ + printf ("CTR not compiled in\n"); +} #endif -void hash_tests(void) +void +hash_tests (void) { - int x; - printf("Hash tests\n"); - for (x = 0; hash_descriptor[x].name != NULL; x++) { - printf(" %10s (%2d) ", hash_descriptor[x].name, hash_descriptor[x].ID); - if ((errno = hash_descriptor[x].test()) != CRYPT_OK) - printf("**failed** Reason: %s\n", error_to_string(errno)); - else - printf("passed\n"); - } + int x; + printf ("Hash tests\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + printf (" %10s (%2d) ", hash_descriptor[x].name, hash_descriptor[x].ID); + if ((errno = hash_descriptor[x].test ()) != CRYPT_OK) + printf ("**failed** Reason: %s\n", error_to_string (errno)); + else + printf ("passed\n"); + } } #ifdef MRSA -void pad_test(void) +void +pad_test (void) { - unsigned char in[100], out[100]; - unsigned long x, y; - - /* make a dummy message */ - for (x = 0; x < 16; x++) in[x] = (unsigned char)x; + unsigned char in[100], out[100]; + unsigned long x, y; - /* pad the message so that random filler is placed before and after it */ - y = 100; - if ((errno = rsa_pad(in, 16, out, &y, find_prng("yarrow"), &prng)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); exit(-1); } + /* make a dummy message */ + for (x = 0; x < 16; x++) + in[x] = (unsigned char) x; - /* depad the message to get the original content */ - memset(in, 0, sizeof(in)); - x = 100; - if ((errno = rsa_depad(out, y, in, &x)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } + /* pad the message so that random filler is placed before and after it */ + y = 100; + if ((errno = + rsa_pad (in, 16, out, &y, find_prng ("yarrow"), &prng)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - /* check outcome */ - printf("rsa_pad: "); - if (x != 16) { printf("Failed. Wrong size.\n"); exit(-1); } - for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed. Expected %02lx and got %02x.\n", x, in[x]); exit(-1); } - printf("passed.\n"); + /* depad the message to get the original content */ + memset (in, 0, sizeof (in)); + x = 100; + if ((errno = rsa_depad (out, y, in, &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + + /* check outcome */ + printf ("rsa_pad: "); + if (x != 16) { + printf ("Failed. Wrong size.\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (in[x] != x) { + printf ("Failed. Expected %02lx and got %02x.\n", x, in[x]); + exit (-1); + } + printf ("passed.\n"); } -void rsa_test(void) +void +rsa_test (void) { - unsigned char in[4096], out[4096]; - unsigned long x, y, z, limit; - int stat; - rsa_key key; - clock_t t; + unsigned char in[4096], out[4096]; + unsigned long x, y, z, limit; + int stat; + rsa_key key; + clock_t t; - /* ---- SINGLE ENCRYPT ---- */ - /* encrypt a short 8 byte string */ - if ((errno = rsa_make_key(&prng, find_prng("yarrow"), 1024/8, 65537, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); exit(-1); } - for (x = 0; x < 8; x++) in[x] = (unsigned char)(x+1); - y = sizeof(in); - if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); exit(-1); } + /* ---- SINGLE ENCRYPT ---- */ + /* encrypt a short 8 byte string */ + if ((errno = + rsa_make_key (&prng, find_prng ("yarrow"), 1024 / 8, 65537, + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + for (x = 0; x < 8; x++) + in[x] = (unsigned char) (x + 1); + y = sizeof (in); + if ((errno = rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - /* decrypt it */ - zeromem(in, sizeof(in)); - x = sizeof(out); - if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); exit(-1); } + /* decrypt it */ + zeromem (in, sizeof (in)); + x = sizeof (out); + if ((errno = rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - /* compare */ - printf("RSA : "); - for (x = 0; x < 8; x++) if (in[x] != (x+1)) { printf("Failed. x==%02lx, in[%ld]==%02x\n", x, x, in[x]); exit(-1); } - printf("passed.\n"); + /* compare */ + printf ("RSA : "); + for (x = 0; x < 8; x++) + if (in[x] != (x + 1)) { + printf ("Failed. x==%02lx, in[%ld]==%02x\n", x, x, in[x]); + exit (-1); + } + printf ("passed.\n"); - /* test the rsa_encrypt_key functions */ - for (x = 0; x < 16; x++) in[x] = x; - y = sizeof(out); - if ((errno = rsa_encrypt_key(in, 16, out, &y, &prng, find_prng("yarrow"), &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - zeromem(in, sizeof(in)); - x = sizeof(in); - if ((errno = rsa_decrypt_key(out, y, in, &x, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("RSA en/de crypt key routines: "); - if (x != 16) { printf("Failed (length)\n"); exit(-1); } - for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed (contents)\n"); exit(-1); } - printf("Passed\n"); + /* test the rsa_encrypt_key functions */ + for (x = 0; x < 16; x++) + in[x] = x; + y = sizeof (out); + if ((errno = + rsa_encrypt_key (in, 16, out, &y, &prng, find_prng ("yarrow"), + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + zeromem (in, sizeof (in)); + x = sizeof (in); + if ((errno = rsa_decrypt_key (out, y, in, &x, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("RSA en/de crypt key routines: "); + if (x != 16) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (in[x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed\n"); - /* test sign_hash functions */ - for (x = 0; x < 16; x++) in[x] = x; - x = sizeof(in); - if ((errno = rsa_sign_hash(in, 16, out, &x, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("RSA signed hash: %lu bytes\n", x); - if ((errno = rsa_verify_hash(out, x, in, &stat, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("Verify hash: %s, ", stat?"passed":"failed"); - in[0] ^= 1; - if ((errno = rsa_verify_hash(out, x, in, &stat, &key)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("%s\n", (!stat)?"passed":"failed"); - if (stat) exit(-1); - rsa_free(&key); + /* test sign_hash functions */ + for (x = 0; x < 16; x++) + in[x] = x; + x = sizeof (in); + if ((errno = rsa_sign_hash (in, 16, out, &x, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("RSA signed hash: %lu bytes\n", x); + if ((errno = rsa_verify_hash (out, x, in, &stat, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("Verify hash: %s, ", stat ? "passed" : "failed"); + in[0] ^= 1; + if ((errno = rsa_verify_hash (out, x, in, &stat, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("%s\n", (!stat) ? "passed" : "failed"); + if (stat) + exit (-1); + rsa_free (&key); - /* make a RSA key */ + /* make a RSA key */ #ifdef SONY_PS2_NOPE - limit = 1024; + limit = 1024; #else - limit = 2048; + limit = 2048; #endif - for (z = 1024; z <= limit; z += 512) { - t = XCLOCK(); - if ((errno = rsa_make_key(&prng, find_prng("yarrow"), z/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t = XCLOCK() - t; - printf("Took %.0f ms to make a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); + { + int tt; - /* time encryption */ - y = sizeof(in); - t = XCLOCK(); - if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t = XCLOCK() - t; - printf("Took %.0f ms to encrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); + for (z = 1024; z <= limit; z += 512) { + t = XCLOCK (); + for (tt = 0; tt < 3; tt++) { + if ((errno = + rsa_make_key (&prng, find_prng ("yarrow"), z / 8, 65537, + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + 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); + + /* time encryption */ + t = XCLOCK (); + + for (tt = 0; tt < 100; tt++) { + y = sizeof (in); + if ((errno = + rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + 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); + + /* time decryption */ + t = XCLOCK (); + for (tt = 0; tt < 100; tt++) { + x = sizeof (out); + if ((errno = + rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + 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); + rsa_free (&key); + } + } - /* time decryption */ - x = sizeof(out); - t = XCLOCK(); - if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t = XCLOCK() - t; - printf("Took %.0f ms to decrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); - rsa_free(&key); - } - } #else -void pad_test(void) { printf("MRSA not compiled in\n"); } -void rsa_test(void) { printf("MRSA not compiled in\n"); } +void +pad_test (void) +{ + printf ("MRSA not compiled in\n"); +} + +void +rsa_test (void) +{ + printf ("MRSA not compiled in\n"); +} #endif #ifdef BASE64 -void base64_test(void) +void +base64_test (void) { - unsigned char buf[2][100]; - unsigned long x, y; + unsigned char buf[2][100]; + unsigned long x, y; - printf("Base64 tests\n"); - zeromem(buf, sizeof(buf)); - for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x; + printf ("Base64 tests\n"); + zeromem (buf, sizeof (buf)); + for (x = 0; x < 16; x++) + buf[0][x] = (unsigned char) x; - x = 100; - if (base64_encode(buf[0], 16, buf[1], &x) != CRYPT_OK) { - printf(" error: %s\n", error_to_string(errno)); - exit(-1); - } - printf(" encoded 16 bytes to %ld bytes...[%s]\n", x, buf[1]); - memset(buf[0], 0, 100); - y = 100; - if (base64_decode(buf[1], x, buf[0], &y) != CRYPT_OK) { - printf(" error: %s\n", error_to_string(errno)); - exit(-1); - } - printf(" decoded %ld bytes to %ld bytes\n", x, y); - for (x = 0; x < 16; x++) if (buf[0][x] != x) { - printf(" **failed**\n"); - exit(-1); - } - printf(" passed\n"); + x = 100; + if (base64_encode (buf[0], 16, buf[1], &x) != CRYPT_OK) { + printf (" error: %s\n", error_to_string (errno)); + exit (-1); + } + printf (" encoded 16 bytes to %ld bytes...[%s]\n", x, buf[1]); + memset (buf[0], 0, 100); + y = 100; + if (base64_decode (buf[1], x, buf[0], &y) != CRYPT_OK) { + printf (" error: %s\n", error_to_string (errno)); + exit (-1); + } + printf (" decoded %ld bytes to %ld bytes\n", x, y); + for (x = 0; x < 16; x++) + if (buf[0][x] != x) { + printf (" **failed**\n"); + exit (-1); + } + printf (" passed\n"); } #else -void base64_test(void) { printf("Base64 not compiled in\n"); } +void +base64_test (void) +{ + printf ("Base64 not compiled in\n"); +} #endif -void time_hash(void) +void +time_hash (void) { - clock_t t1; - int x, y; - unsigned long z; - unsigned char input[4096], out[MAXBLOCKSIZE]; - printf("Hash Time Trials (4KB blocks):\n"); - for (x = 0; hash_descriptor[x].name != NULL; x++) { - t1 = XCLOCK(); - z = sizeof(out); - y = 0; - while (XCLOCK() - t1 < (3 * XCLOCKS_PER_SEC)) { - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); - hash_memory(x, input, 4096, out, &z); y += 16; - } - 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); + clock_t t1; + int x, y; + unsigned long z; + unsigned char input[4096], out[MAXBLOCKSIZE]; + printf ("Hash Time Trials (4KB blocks):\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + t1 = XCLOCK (); + z = sizeof (out); + y = 0; + while (XCLOCK () - t1 < (3 * XCLOCKS_PER_SEC)) { + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + hash_memory (x, input, 4096, out, &z); + y += 16; } + 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); + } } -void time_ecb(void) +void +time_ecb (void) { - clock_t t1, t2; - long x, y1, y2; - unsigned char pt[32], key[32]; - symmetric_key skey; - void (*func)(const unsigned char *, unsigned char *, symmetric_key *); + clock_t t1, t2; + long x, y1, y2; + unsigned char pt[32], key[32]; + symmetric_key skey; + void (*func) (const unsigned char *, unsigned char *, symmetric_key *); - 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); + 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); #define DO1 func(pt,pt,&skey); #define DO2 DO1 DO1 @@ -572,27 +775,33 @@ void time_ecb(void) #define DO32 DO16 DO16 #define DO64 DO32 DO32 #define DO128 DO64 DO64 -#define DO256 DO128 DO128 +#define DO256 DO128 DO128 - func = cipher_descriptor[x].ecb_encrypt; - y1 = 0; - t1 = XCLOCK(); - while (XCLOCK() - t1 < 3*XCLOCKS_PER_SEC) { - DO256; y1 += 256; - } - t1 = XCLOCK() - t1; + func = cipher_descriptor[x].ecb_encrypt; + y1 = 0; + t1 = XCLOCK (); + while (XCLOCK () - t1 < 3 * XCLOCKS_PER_SEC) { + DO256; + y1 += 256; + } + t1 = XCLOCK () - t1; - func = cipher_descriptor[x].ecb_decrypt; - y2 = 0; - t2 = XCLOCK(); - while (XCLOCK() - t2 < 3*XCLOCKS_PER_SEC) { - DO256; y2 += 256; - } - t2 = XCLOCK() - t2; - printf("%-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, - ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y2 / ((double)t2 / (double)XCLOCKS_PER_SEC))) / 1000000.0); + func = cipher_descriptor[x].ecb_decrypt; + y2 = 0; + t2 = XCLOCK (); + while (XCLOCK () - t2 < 3 * XCLOCKS_PER_SEC) { + DO256; + y2 += 256; + } + t2 = XCLOCK () - t2; + printf + ("%-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, + ((8.0 * (double) cipher_descriptor[x].block_length) * + ((double) y2 / ((double) t2 / (double) XCLOCKS_PER_SEC))) / + 1000000.0); #undef DO256 #undef DO128 @@ -603,866 +812,936 @@ void time_ecb(void) #undef DO4 #undef DO2 #undef DO1 - } + } } #ifdef MDH -void dh_tests(void) +void +dh_tests (void) { - unsigned char buf[3][4096]; - unsigned long x, y, z; - int low, high, stat, stat2; - dh_key usera, userb; - clock_t t1; + unsigned char buf[3][4096]; + unsigned long x, y, z; + int low, high, stat, stat2; + dh_key usera, userb; + clock_t t1; /* if ((errno = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errno)); */ - dh_sizes(&low, &high); - printf("DH Keys from %d to %d supported.\n", low*8, high*8); + dh_sizes (&low, &high); + printf ("DH Keys from %d to %d supported.\n", low * 8, high * 8); - /* make up two keys */ - if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make up two keys */ + if ((errno = + dh_make_key (&prng, find_prng ("yarrow"), 96, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + if ((errno = + dh_make_key (&prng, find_prng ("yarrow"), 96, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - /* make the shared secret */ - x = 4096; - if ((errno = dh_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make the shared secret */ + x = 4096; + if ((errno = dh_shared_secret (&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - y = 4096; - if ((errno = dh_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - if (y != x) { printf("DH Shared keys are not same size.\n"); exit(-1); } - if (memcmp(buf[0], buf[1], x)) { printf("DH Shared keys not same contents.\n"); exit(-1); } + y = 4096; + if ((errno = dh_shared_secret (&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + if (y != x) { + printf ("DH Shared keys are not same size.\n"); + exit (-1); + } + if (memcmp (buf[0], buf[1], x)) { + printf ("DH Shared keys not same contents.\n"); + exit (-1); + } - /* now export userb */ - y = 4096; - if ((errno = dh_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - dh_free(&userb); + /* now export userb */ + y = 4096; + if ((errno = dh_export (buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + dh_free (&userb); - /* import and make the shared secret again */ - if ((errno = dh_import(buf[1], y, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - z = 4096; - if ((errno = dh_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* import and make the shared secret again */ + if ((errno = dh_import (buf[1], y, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + z = 4096; + if ((errno = dh_shared_secret (&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - printf("DH routines: "); - if (z != x) { printf("failed. Size don't match?\n"); exit(-1); } - if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); exit(-1); } - printf("Passed\n"); - dh_free(&usera); - dh_free(&userb); + printf ("DH routines: "); + if (z != x) { + printf ("failed. Size don't match?\n"); + exit (-1); + } + if (memcmp (buf[0], buf[2], x)) { + printf ("Failed. Content didn't match.\n"); + exit (-1); + } + printf ("Passed\n"); + dh_free (&usera); + dh_free (&userb); /* time stuff */ - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 96, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-768 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); + { + static int sizes[] = { 96, 128, 160, 192, 224, 256, 320, 384, 512 }; + int ii, tt; - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 128, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-1024 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); + for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { + t1 = XCLOCK (); + for (tt = 0; tt < 50; tt++) { + 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 / 50.0) / (double) XCLOCKS_PER_SEC)); + } + } -#ifndef SONY_PS2_NOPE - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 160, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-1280 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); - - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 192, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-1536 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); - - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 224, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-1792 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); - - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 256, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-2048 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); - - t1 = XCLOCK(); - dh_make_key(&prng, find_prng("yarrow"), 320, &usera); - t1 = XCLOCK() - t1; - printf("Make dh-2560 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - dh_free(&usera); -#endif - /* test encrypt_key */ - dh_make_key(&prng, find_prng("yarrow"), 96, &usera); - for (x = 0; x < 16; x++) buf[0][x] = x; - y = sizeof(buf[1]); - if ((errno = dh_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - zeromem(buf[0], sizeof(buf[0])); - x = sizeof(buf[0]); - if ((errno = dh_decrypt_key(buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("DH en/de crypt key routines: "); - if (x != 16) { printf("Failed (length)\n"); exit(-1); } - for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); exit(-1); } - printf("Passed (size %lu)\n", y); + dh_make_key (&prng, find_prng ("yarrow"), 96, &usera); + for (x = 0; x < 16; x++) + buf[0][x] = x; + y = sizeof (buf[1]); + if ((errno = + dh_encrypt_key (buf[0], 16, buf[1], &y, &prng, find_prng ("yarrow"), + find_hash ("md5"), &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + zeromem (buf[0], sizeof (buf[0])); + x = sizeof (buf[0]); + if ((errno = dh_decrypt_key (buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("DH en/de crypt key routines: "); + if (x != 16) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (buf[0][x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed (size %lu)\n", y); /* test sign_hash */ - for (x = 0; x < 16; x++) buf[0][x] = x; - x = sizeof(buf[1]); - if ((errno = dh_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - if (dh_verify_hash(buf[1], x, buf[0], 16, &stat, &usera)) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - buf[0][0] ^= 1; - if (dh_verify_hash(buf[1], x, buf[0], 16, &stat2, &usera)) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("dh_sign/verify_hash: %s (%d,%d), %lu\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2, x); - dh_free(&usera); + for (x = 0; x < 16; x++) + buf[0][x] = x; + x = sizeof (buf[1]); + if ((errno = + dh_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + if (dh_verify_hash (buf[1], x, buf[0], 16, &stat, &usera)) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + buf[0][0] ^= 1; + if (dh_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera)) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("dh_sign/verify_hash: %s (%d,%d), %lu\n", + ((stat == 1) + && (stat2 == 0)) ? "passed" : "failed", stat, stat2, x); + dh_free (&usera); } #else -void dh_tests(void) { printf("MDH not compiled in\n"); } +void +dh_tests (void) +{ + printf ("MDH not compiled in\n"); +} #endif -int callback_x = 0; -void callback(void) -{ - printf("%c\x08", "-\\|/"[++callback_x & 3]); +int callback_x = 0; +void +callback (void) +{ + printf ("%c\x08", "-\\|/"[++callback_x & 3]); #ifndef SONY_PS2 - fflush(stdout); + fflush (stdout); #endif } -void rng_tests(void) +void +rng_tests (void) { - unsigned char buf[16]; - clock_t t1; - int x, y; + unsigned char buf[16]; + clock_t t1; + int x, y; - printf("RNG tests\n"); - t1 = XCLOCK(); - x = rng_get_bytes(buf, sizeof(buf), &callback); - t1 = XCLOCK() - t1; - printf(" %f bytes per second...", - (double)x / ((double)t1 / (double)XCLOCKS_PER_SEC)); - printf("read %d bytes.\n ", x); - for (y = 0; y < x; y++) - printf("%02x ", buf[y]); - printf("\n"); + printf ("RNG tests\n"); + t1 = XCLOCK (); + x = rng_get_bytes (buf, sizeof (buf), &callback); + t1 = XCLOCK () - t1; + printf (" %f bytes per second...", + (double) x / ((double) t1 / (double) XCLOCKS_PER_SEC)); + printf ("read %d bytes.\n ", x); + for (y = 0; y < x; y++) + printf ("%02x ", buf[y]); + printf ("\n"); #ifdef YARROW - if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, &callback)) != CRYPT_OK) { - printf(" starting yarrow error: %s\n", error_to_string(errno)); - exit(-1); - } + if ((errno = + rng_make_prng (128, find_prng ("yarrow"), &prng, + &callback)) != CRYPT_OK) { + printf (" starting yarrow error: %s\n", error_to_string (errno)); + exit (-1); + } #endif } #ifdef MECC -void ecc_tests(void) +void +ecc_tests (void) { - unsigned char buf[4][4096]; - unsigned long x, y, z; - int stat, stat2, low, high; - ecc_key usera, userb; - clock_t t1; + unsigned char buf[4][4096]; + unsigned long x, y, z; + int stat, stat2, low, high; + ecc_key usera, userb; + clock_t t1; - if ((errno = ecc_test()) != CRYPT_OK) { printf("ecc Error: %s\n", error_to_string(errno)); exit(-1); } + if ((errno = ecc_test ()) != CRYPT_OK) { + printf ("ecc Error: %s\n", error_to_string (errno)); + exit (-1); + } - ecc_sizes(&low, &high); - printf("ecc Keys from %d to %d supported.\n", low*8, high*8); + ecc_sizes (&low, &high); + printf ("ecc Keys from %d to %d supported.\n", low * 8, high * 8); - /* make up two keys */ - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make up two keys */ + if ((errno = + ecc_make_key (&prng, find_prng ("yarrow"), 24, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + if ((errno = + ecc_make_key (&prng, find_prng ("yarrow"), 24, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - /* make the shared secret */ - x = 4096; - if ((errno = ecc_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make the shared secret */ + x = 4096; + if ((errno = ecc_shared_secret (&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - y = 4096; - if ((errno = ecc_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + y = 4096; + if ((errno = ecc_shared_secret (&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - if (y != x) { printf("ecc Shared keys are not same size.\n"); exit(-1); } + if (y != x) { + printf ("ecc Shared keys are not same size.\n"); + exit (-1); + } - if (memcmp(buf[0], buf[1], x)) { printf("ecc Shared keys not same contents.\n"); exit(-1); } + if (memcmp (buf[0], buf[1], x)) { + printf ("ecc Shared keys not same contents.\n"); + exit (-1); + } - /* now export userb */ - y = 4096; - if ((errno = ecc_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - ecc_free(&userb); - printf("ECC-192 export took %ld bytes\n", y); + /* now export userb */ + y = 4096; + if ((errno = ecc_export (buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + ecc_free (&userb); + printf ("ECC-192 export took %ld bytes\n", y); - /* import and make the shared secret again */ - if ((errno = ecc_import(buf[1], y, &userb)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + /* import and make the shared secret again */ + if ((errno = ecc_import (buf[1], y, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - z = 4096; - if ((errno = ecc_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } + z = 4096; + if ((errno = ecc_shared_secret (&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } - printf("ecc routines: "); - if (z != x) { printf("failed. Size don't match?\n"); exit(-1); } - if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); exit(-1); } - printf("Passed\n"); - ecc_free(&usera); - ecc_free(&userb); + printf ("ecc routines: "); + if (z != x) { + printf ("failed. Size don't match?\n"); + exit (-1); + } + if (memcmp (buf[0], buf[2], x)) { + printf ("Failed. Content didn't match.\n"); + exit (-1); + } + printf ("Passed\n"); + ecc_free (&usera); + ecc_free (&userb); /* time stuff */ - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 20, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-160 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); + { + static int sizes[] = { 20, 24, 28, 32, 48, 65 }; + int ii, tt; - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-192 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); - - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 28, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-224 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); - -#ifndef SONY_PS2 - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 32, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-256 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); - - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 48, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-384 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); - - t1 = XCLOCK(); - if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 65, &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } - t1 = XCLOCK() - t1; - printf("Make ECC-521 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); - ecc_free(&usera); -#endif + for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { + t1 = XCLOCK (); + for (tt = 0; tt < 25; tt++) { + if ((errno = + ecc_make_key (&prng, find_prng ("yarrow"), sizes[ii], + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + 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)); + } + } /* test encrypt_key */ - ecc_make_key(&prng, find_prng("yarrow"), 32, &usera); - for (x = 0; x < 16; x++) buf[0][x] = x; - y = sizeof(buf[1]); - if ((errno = ecc_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - zeromem(buf[0], sizeof(buf[0])); - x = sizeof(buf[0]); - if ((errno = ecc_decrypt_key(buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("ECC en/de crypt key routines: "); - if (x != 16) { printf("Failed (length)\n"); exit(-1); } - for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); exit(-1); } - printf("Passed (size: %lu)\n", y); + ecc_make_key (&prng, find_prng ("yarrow"), 65, &usera); + for (x = 0; x < 16; x++) + buf[0][x] = x; + y = sizeof (buf[1]); + if ((errno = + ecc_encrypt_key (buf[0], 16, buf[1], &y, &prng, find_prng ("yarrow"), + find_hash ("md5"), &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + zeromem (buf[0], sizeof (buf[0])); + x = sizeof (buf[0]); + if ((errno = ecc_decrypt_key (buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("ECC en/de crypt key routines: "); + if (x != 16) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (buf[0][x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed (size: %lu)\n", y); /* test sign_hash */ - for (x = 0; x < 16; x++) buf[0][x] = x; - x = sizeof(buf[1]); - if ((errno = ecc_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - if (ecc_verify_hash(buf[1], x, buf[0], 16, &stat, &usera)) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - buf[0][0] ^= 1; - if (ecc_verify_hash(buf[1], x, buf[0], 16, &stat2, &usera)) { - printf("Error: %s\n", error_to_string(errno)); - exit(-1); - } - printf("ecc_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); - ecc_free(&usera); + for (x = 0; x < 16; x++) + buf[0][x] = x; + x = sizeof (buf[1]); + if ((errno = + ecc_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + if (ecc_verify_hash (buf[1], x, buf[0], 16, &stat, &usera)) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + buf[0][0] ^= 1; + if (ecc_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera)) { + printf ("Error: %s\n", error_to_string (errno)); + exit (-1); + } + printf ("ecc_sign/verify_hash: %s (%d,%d)\n", + ((stat == 1) && (stat2 == 0)) ? "passed" : "failed", stat, stat2); + ecc_free (&usera); } #else -void ecc_tests(void) { printf("MECC not compiled in\n"); } +void +ecc_tests (void) +{ + printf ("MECC not compiled in\n"); +} #endif #ifdef GF -void gf_tests(void) +void +gf_tests (void) { - gf_int a, b, c, d; - int n; - unsigned char buf[1024]; + gf_int a, b, c, d; + int n; + unsigned char buf[1024]; - printf("GF tests\n"); - gf_zero(a);gf_zero(b);gf_zero(c);gf_zero(d); + printf ("GF tests\n"); + gf_zero (a); + gf_zero (b); + gf_zero (c); + gf_zero (d); - /* a == 0x18000000b */ - a[1] = 1; - a[0] = 0x8000000bUL; + /* a == 0x18000000b */ + a[1] = 1; + a[0] = 0x8000000bUL; - /* b == 0x012345678 */ - b[0] = 0x012345678UL; + /* b == 0x012345678 */ + b[0] = 0x012345678UL; - /* find 1/b mod a */ - gf_invmod(b,a,c); + /* find 1/b mod a */ + gf_invmod (b, a, c); - /* find 1/1/b mod a */ - gf_invmod(c,a,d); + /* find 1/1/b mod a */ + gf_invmod (c, a, d); - /* display them */ - printf(" %08lx %08lx\n", c[0], d[0]); + /* display them */ + printf (" %08lx %08lx\n", c[0], d[0]); - /* store as binary string */ - n = gf_size(a); - printf(" a takes %d bytes\n", n); - gf_toraw(a, buf); - gf_readraw(a, buf, n); - printf(" a == %08lx%08lx\n", a[1], a[0]); + /* store as binary string */ + n = gf_size (a); + printf (" a takes %d bytes\n", n); + gf_toraw (a, buf); + gf_readraw (a, buf, n); + printf (" a == %08lx%08lx\n", a[1], a[0]); - /* primality testing */ - gf_zero(a); - a[0] = 0x169; - printf(" GF prime: %s, ", gf_is_prime(a)?"passed":"failed"); - a[0] = 0x168; - printf(" %s\n", gf_is_prime(a)?"failed":"passed"); + /* primality testing */ + gf_zero (a); + a[0] = 0x169; + printf (" GF prime: %s, ", gf_is_prime (a) ? "passed" : "failed"); + a[0] = 0x168; + printf (" %s\n", gf_is_prime (a) ? "failed" : "passed"); - /* test sqrt code */ - gf_zero(a); - a[1] = 0x00000001; - a[0] = 0x8000000bUL; - gf_zero(b); - b[0] = 0x12345678UL; + /* test sqrt code */ + gf_zero (a); + a[1] = 0x00000001; + a[0] = 0x8000000bUL; + gf_zero (b); + b[0] = 0x12345678UL; - gf_sqrt(b, a, c); - gf_mulmod(c, c, a, b); - printf(" (%08lx)^2 = %08lx (mod %08lx%08lx) \n", c[0], b[0], a[1], a[0]); + gf_sqrt (b, a, c); + gf_mulmod (c, c, a, b); + printf (" (%08lx)^2 = %08lx (mod %08lx%08lx) \n", c[0], b[0], a[1], a[0]); } #else -void gf_tests(void) { printf("GF not compiled in\n"); } +void +gf_tests (void) +{ + printf ("GF not compiled in\n"); +} #endif #ifdef MPI -void test_prime(void) +void +test_prime (void) { - unsigned char buf[1024]; - mp_int a; - int x; - - /* make a 1024 bit prime */ - mp_init(&a); - rand_prime(&a, 128, &prng, find_prng("yarrow")); + unsigned char buf[1024]; + mp_int a; + int x; - /* dump it */ - mp_todecimal(&a, buf); - printf("1024-bit prime:\n"); - for (x = 0; x < (int)strlen(buf); ) { - printf("%c", buf[x]); - if (!(++x % 60)) printf("\\ \n"); - } - printf("\n\n"); + /* make a 1024 bit prime */ + mp_init (&a); + rand_prime (&a, 128, &prng, find_prng ("yarrow")); - mp_clear(&a); + /* dump it */ + mp_todecimal (&a, buf); + printf ("1024-bit prime:\n"); + for (x = 0; x < (int) strlen (buf);) { + printf ("%c", buf[x]); + if (!(++x % 60)) + printf ("\\ \n"); + } + printf ("\n\n"); + + mp_clear (&a); } #else -void test_prime(void) { printf("MPI not compiled in\n"); } +void +test_prime (void) +{ + printf ("MPI not compiled in\n"); +} #endif -void register_all_algs(void) +void +register_all_algs (void) { #ifdef BLOWFISH - register_cipher(&blowfish_desc); + register_cipher (&blowfish_desc); #endif #ifdef XTEA - register_cipher(&xtea_desc); + register_cipher (&xtea_desc); #endif #ifdef RC5 - register_cipher(&rc5_desc); + register_cipher (&rc5_desc); #endif #ifdef RC6 - register_cipher(&rc6_desc); + register_cipher (&rc6_desc); #endif #ifdef SAFERP - register_cipher(&saferp_desc); + register_cipher (&saferp_desc); #endif #ifdef SERPENT - register_cipher(&serpent_desc); + register_cipher (&serpent_desc); #endif #ifdef RIJNDAEL - register_cipher(&aes_desc); + register_cipher (&aes_desc); #endif #ifdef TWOFISH - register_cipher(&twofish_desc); + register_cipher (&twofish_desc); #endif #ifdef SAFER - register_cipher(&safer_k64_desc); - register_cipher(&safer_sk64_desc); - register_cipher(&safer_k128_desc); - register_cipher(&safer_sk128_desc); + register_cipher (&safer_k64_desc); + register_cipher (&safer_sk64_desc); + register_cipher (&safer_k128_desc); + register_cipher (&safer_sk128_desc); #endif #ifdef RC2 - register_cipher(&rc2_desc); + register_cipher (&rc2_desc); #endif #ifdef DES - register_cipher(&des_desc); - register_cipher(&des3_desc); + register_cipher (&des_desc); + register_cipher (&des3_desc); #endif #ifdef CAST5 - register_cipher(&cast5_desc); + register_cipher (&cast5_desc); #endif #ifdef NOEKEON - register_cipher(&noekeon_desc); + register_cipher (&noekeon_desc); #endif - register_cipher(&null_desc); + register_cipher (&null_desc); #ifdef SHA256 - register_hash(&sha256_desc); + register_hash (&sha256_desc); #endif #ifdef TIGER - register_hash(&tiger_desc); + register_hash (&tiger_desc); #endif #ifdef SHA1 - register_hash(&sha1_desc); + register_hash (&sha1_desc); #endif #ifdef MD5 - register_hash(&md5_desc); + register_hash (&md5_desc); #endif #ifdef SHA384 - register_hash(&sha384_desc); + register_hash (&sha384_desc); #endif #ifdef SHA512 - register_hash(&sha512_desc); + register_hash (&sha512_desc); #endif #ifdef MD4 - register_hash(&md4_desc); + register_hash (&md4_desc); #endif #ifdef MD2 - register_hash(&md2_desc); + register_hash (&md2_desc); #endif #ifdef YARROW - register_prng(&yarrow_desc); + register_prng (&yarrow_desc); #endif #ifdef SPRNG - register_prng(&sprng_desc); + register_prng (&sprng_desc); #endif } -void kr_display(pk_key *kr) +void +kr_display (pk_key * kr) { - static const char *system[] = { "NON-KEY", "RSA", "DH", "ECC" }; - static const char *type[] = { "PRIVATE", "PUBLIC", "PRIVATE_OPTIMIZED" }; + static const char *system[] = { "NON-KEY", "RSA", "DH", "ECC" }; + static const char *type[] = { "PRIVATE", "PUBLIC", "PRIVATE_OPTIMIZED" }; - while (kr->system != NON_KEY) { - printf("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, system[kr->system], type[kr->key_type], kr->name, kr->email, kr->description); - kr = kr->next; - } - printf("\n"); + while (kr->system != NON_KEY) { + printf ("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, + system[kr->system], type[kr->key_type], kr->name, kr->email, + kr->description); + kr = kr->next; + } + printf ("\n"); } -void kr_test_makekeys(pk_key **kr) +void +kr_test_makekeys (pk_key ** kr) { - if ((errno = kr_init(kr)) != CRYPT_OK) { - printf("KR init error %s\n", error_to_string(errno)); - exit(-1); - } + if ((errno = kr_init (kr)) != CRYPT_OK) { + printf ("KR init error %s\n", error_to_string (errno)); + exit (-1); + } - /* make a DH key */ - printf("KR: Making DH key...\n"); - if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), DH_KEY, 128, "dhkey", "dh@dh.dh", "dhkey one")) != CRYPT_OK) { - printf("Make key error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make a DH key */ + printf ("KR: Making DH key...\n"); + if ((errno = + kr_make_key (*kr, &prng, find_prng ("yarrow"), DH_KEY, 128, "dhkey", + "dh@dh.dh", "dhkey one")) != CRYPT_OK) { + printf ("Make key error: %s\n", error_to_string (errno)); + exit (-1); + } - /* make a ECC key */ - printf("KR: Making ECC key...\n"); - if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), ECC_KEY, 20, "ecckey", "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { - printf("Make key error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make a ECC key */ + printf ("KR: Making ECC key...\n"); + if ((errno = + kr_make_key (*kr, &prng, find_prng ("yarrow"), ECC_KEY, 20, "ecckey", + "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { + printf ("Make key error: %s\n", error_to_string (errno)); + exit (-1); + } - /* make a RSA key */ - printf("KR: Making RSA key...\n"); - if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), RSA_KEY, 128, "rsakey", "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { - printf("Make key error: %s\n", error_to_string(errno)); - exit(-1); - } + /* make a RSA key */ + printf ("KR: Making RSA key...\n"); + if ((errno = + kr_make_key (*kr, &prng, find_prng ("yarrow"), RSA_KEY, 128, "rsakey", + "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { + printf ("Make key error: %s\n", error_to_string (errno)); + exit (-1); + } } -void kr_test(void) +void +kr_test (void) { - pk_key *kr, *_kr; - unsigned char buf[8192], buf2[8192], buf3[8192]; - unsigned long len; - int i, j, stat; -#ifndef NO_FILE - FILE *f; + pk_key *kr, *_kr; + unsigned char buf[8192], buf2[8192], buf3[8192]; + unsigned long len; + int i, j, stat; +#ifndef NO_FILE + FILE *f; #endif - kr_test_makekeys(&kr); + kr_test_makekeys (&kr); - printf("The original list:\n"); - kr_display(kr); + printf ("The original list:\n"); + kr_display (kr); - for (i = 0; i < 3; i++) { - len = sizeof(buf); - if ((errno = kr_export(kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) { - printf("Error exporting key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - printf("Exported key was: %lu bytes\n", len); - if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { - printf("Error deleting key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - kr_display(kr); - if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { - printf("Error importing key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - kr_display(kr); - } + for (i = 0; i < 3; i++) { + len = sizeof (buf); + if ((errno = kr_export (kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + printf ("Exported key was: %lu bytes\n", len); + if ((errno = kr_del (&kr, kr->ID)) != CRYPT_OK) { + printf ("Error deleting key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + kr_display (kr); + if ((errno = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + kr_display (kr); + } - for (i = 0; i < 3; i++) { - len = sizeof(buf); - if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { - printf("Error exporting key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - printf("Exported key was: %lu bytes\n", len); - if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { - printf("Error deleting key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - kr_display(kr); - if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { - printf("Error importing key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - kr_display(kr); - } + for (i = 0; i < 3; i++) { + len = sizeof (buf); + if ((errno = kr_export (kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + printf ("Exported key was: %lu bytes\n", len); + if ((errno = kr_del (&kr, kr->ID)) != CRYPT_OK) { + printf ("Error deleting key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + kr_display (kr); + if ((errno = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + kr_display (kr); + } - if ((errno = kr_clear(&kr)) != CRYPT_OK) { - printf("Error clearing ring: %s\n", error_to_string(errno)); - exit(-1); - } + if ((errno = kr_clear (&kr)) != CRYPT_OK) { + printf ("Error clearing ring: %s\n", error_to_string (errno)); + exit (-1); + } /* TEST output to file */ #ifndef NO_FILE - if ((errno = kr_init(&kr)) != CRYPT_OK) { - printf("KR init error %s\n", error_to_string(errno)); - exit(-1); - } - kr_test_makekeys(&kr); + if ((errno = kr_init (&kr)) != CRYPT_OK) { + printf ("KR init error %s\n", error_to_string (errno)); + exit (-1); + } + kr_test_makekeys (&kr); - /* save to file */ - f = fopen("ring.dat", "wb"); - if ((errno = kr_save(kr, f, NULL)) != CRYPT_OK) { - printf("kr_save error %s\n", error_to_string(errno)); - exit(-1); - } - fclose(f); + /* save to file */ + f = fopen ("ring.dat", "wb"); + if ((errno = kr_save (kr, f, NULL)) != CRYPT_OK) { + printf ("kr_save error %s\n", error_to_string (errno)); + exit (-1); + } + fclose (f); - /* delete and load */ - if ((errno = kr_clear(&kr)) != CRYPT_OK) { - printf("clear error: %s\n", error_to_string(errno)); - exit(-1); - } + /* delete and load */ + if ((errno = kr_clear (&kr)) != CRYPT_OK) { + printf ("clear error: %s\n", error_to_string (errno)); + exit (-1); + } - f = fopen("ring.dat", "rb"); - if ((errno = kr_load(&kr, f, NULL)) != CRYPT_OK) { - printf("kr_load error %s\n", error_to_string(errno)); - exit(-1); - } - fclose(f); - remove("ring.dat"); - printf("After load and save...\n"); - kr_display(kr); - - if ((errno = kr_clear(&kr)) != CRYPT_OK) { - printf("clear error: %s\n", error_to_string(errno)); - exit(-1); - } + f = fopen ("ring.dat", "rb"); + if ((errno = kr_load (&kr, f, NULL)) != CRYPT_OK) { + printf ("kr_load error %s\n", error_to_string (errno)); + exit (-1); + } + fclose (f); + remove ("ring.dat"); + printf ("After load and save...\n"); + kr_display (kr); + if ((errno = kr_clear (&kr)) != CRYPT_OK) { + printf ("clear error: %s\n", error_to_string (errno)); + exit (-1); + } #endif /* test the packet encryption/sign stuff */ - for (i = 0; i < 32; i++) buf[i] = i; - kr_test_makekeys(&kr); - _kr = kr; - for (i = 0; i < 3; i++) { - printf("Testing a key with system %d, type %d:\t", _kr->system, _kr->key_type); - len = sizeof(buf2); - if ((errno = 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(errno)); - exit(-1); - } - len = sizeof(buf3); - if ((errno = kr_decrypt_key(kr, buf2, buf3, &len)) != CRYPT_OK) { - printf("decrypt error, %d, %s\n", i, error_to_string(errno)); - exit(-1); - } - if (len != 16 || memcmp(buf3, buf, 16)) { - printf("kr_decrypt_key failed, %i, %lu\n", i, len); - exit(-1); - } - printf("kr_encrypt_key passed, "); - - len = sizeof(buf2); - if ((errno = 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(errno)); - exit(-1); - } - printf("kr_sign_hash: "); - if ((errno = kr_verify_hash(kr, buf2, buf, 32, &stat)) != CRYPT_OK) { - printf("kr_sign_hash failed, %i, %s\n", i, error_to_string(errno)); - exit(-1); - } - printf("%s, ", stat?"passed":"failed"); - buf[15] ^= 1; - if ((errno = kr_verify_hash(kr, buf2, buf, 32, &stat)) != CRYPT_OK) { - printf("kr_sign_hash failed, %i, %s\n", i, error_to_string(errno)); - exit(-1); - } - printf("%s\n", (!stat)?"passed":"failed"); - buf[15] ^= 1; - - len = sizeof(buf); - if ((errno = kr_fingerprint(kr, _kr->ID, find_hash("sha1"), buf, &len)) != CRYPT_OK) { - printf("kr_fingerprint failed, %i, %lu\n", i, len); - exit(-1); - } - printf("Fingerprint: "); - for (j = 0; j < 20; j++) { - printf("%02x", buf[j]); - if (j < 19) printf(":"); - } - printf("\n\n"); - - _kr = _kr->next; + for (i = 0; i < 32; i++) + buf[i] = i; + kr_test_makekeys (&kr); + _kr = kr; + for (i = 0; i < 3; i++) { + printf ("Testing a key with system %d, type %d:\t", _kr->system, + _kr->key_type); + len = sizeof (buf2); + if ((errno = + 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 (errno)); + exit (-1); } + len = sizeof (buf3); + if ((errno = kr_decrypt_key (kr, buf2, buf3, &len)) != CRYPT_OK) { + printf ("decrypt error, %d, %s\n", i, error_to_string (errno)); + exit (-1); + } + if (len != 16 || memcmp (buf3, buf, 16)) { + printf ("kr_decrypt_key failed, %i, %lu\n", i, len); + exit (-1); + } + printf ("kr_encrypt_key passed, "); + + len = sizeof (buf2); + if ((errno = + 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 (errno)); + exit (-1); + } + printf ("kr_sign_hash: "); + if ((errno = kr_verify_hash (kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errno)); + exit (-1); + } + printf ("%s, ", stat ? "passed" : "failed"); + buf[15] ^= 1; + if ((errno = kr_verify_hash (kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errno)); + exit (-1); + } + printf ("%s\n", (!stat) ? "passed" : "failed"); + buf[15] ^= 1; + + len = sizeof (buf); + if ((errno = + kr_fingerprint (kr, _kr->ID, find_hash ("sha1"), buf, + &len)) != CRYPT_OK) { + printf ("kr_fingerprint failed, %i, %lu\n", i, len); + exit (-1); + } + printf ("Fingerprint: "); + for (j = 0; j < 20; j++) { + printf ("%02x", buf[j]); + if (j < 19) + printf (":"); + } + printf ("\n\n"); + + _kr = _kr->next; + } /* Test encrypting/decrypting to a public key */ /* first dump the other two keys */ - kr_del(&kr, kr->ID); - kr_del(&kr, kr->ID); - kr_display(kr); + kr_del (&kr, kr->ID); + kr_del (&kr, kr->ID); + kr_display (kr); - /* now export it as public and private */ - len = sizeof(buf); - if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { - printf("Error exporting key %d, %s\n", i, error_to_string(errno)); - exit(-1); - } + /* now export it as public and private */ + len = sizeof (buf); + if ((errno = kr_export (kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errno)); + exit (-1); + } - /* check boundaries */ - memset(buf+len, 0, sizeof(buf)-len); + /* check boundaries */ + memset (buf + len, 0, sizeof (buf) - len); - len = sizeof(buf2); - if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) { - printf("Error exporting key %s\n", error_to_string(errno)); - exit(-1); - } + len = sizeof (buf2); + if ((errno = kr_export (kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) { + printf ("Error exporting key %s\n", error_to_string (errno)); + exit (-1); + } - /* check boundaries */ - memset(buf2+len, 0, sizeof(buf2)-len); + /* check boundaries */ + memset (buf2 + len, 0, sizeof (buf2) - len); - /* delete the key and import the public */ - kr_clear(&kr); - kr_init(&kr); - kr_display(kr); - if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { - printf("Error importing key %s\n", error_to_string(errno)); - exit(-1); - } - kr_display(kr); - - /* now encrypt a buffer */ - for (i = 0; i < 16; i++) buf[i] = i; - len = sizeof(buf3); - if ((errno = kr_encrypt_key(kr, kr->ID, buf, 16, buf3, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) { - printf("Encrypt error, %d, %s\n", i, error_to_string(errno)); - exit(-1); - } + /* delete the key and import the public */ + kr_clear (&kr); + kr_init (&kr); + kr_display (kr); + if ((errno = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %s\n", error_to_string (errno)); + exit (-1); + } + kr_display (kr); - /* now delete the key and import the private one */ - kr_clear(&kr); - kr_init(&kr); - kr_display(kr); - if ((errno = kr_import(kr, buf2, len)) != CRYPT_OK) { - printf("Error importing key %s\n", error_to_string(errno)); - exit(-1); - } - kr_display(kr); + /* now encrypt a buffer */ + for (i = 0; i < 16; i++) + buf[i] = i; + len = sizeof (buf3); + if ((errno = + kr_encrypt_key (kr, kr->ID, buf, 16, buf3, &len, &prng, + find_prng ("yarrow"), + find_hash ("md5"))) != CRYPT_OK) { + printf ("Encrypt error, %d, %s\n", i, error_to_string (errno)); + exit (-1); + } - /* now decrypt */ - len = sizeof(buf2); - if ((errno = kr_decrypt_key(kr, buf3, buf2, &len)) != CRYPT_OK) { - printf("decrypt error, %s\n", error_to_string(errno)); - exit(-1); - } + /* now delete the key and import the private one */ + kr_clear (&kr); + kr_init (&kr); + kr_display (kr); + if ((errno = kr_import (kr, buf2, len)) != CRYPT_OK) { + printf ("Error importing key %s\n", error_to_string (errno)); + exit (-1); + } + kr_display (kr); - printf("KR encrypt to public, decrypt with private: "); - if (len == 16 && !memcmp(buf2, buf, 16)) { - printf("passed\n"); - } else { - printf("failed\n"); - } + /* now decrypt */ + len = sizeof (buf2); + if ((errno = kr_decrypt_key (kr, buf3, buf2, &len)) != CRYPT_OK) { + printf ("decrypt error, %s\n", error_to_string (errno)); + exit (-1); + } - kr_clear(&kr); + printf ("KR encrypt to public, decrypt with private: "); + if (len == 16 && !memcmp (buf2, buf, 16)) { + printf ("passed\n"); + } else { + printf ("failed\n"); + } -} + kr_clear (&kr); -void test_errs(void) +} + +void +test_errs (void) { - #define ERR(x) printf("%25s => %s\n", #x, error_to_string(x)); +#define ERR(x) printf("%25s => %s\n", #x, error_to_string(x)); - ERR(CRYPT_OK); - ERR(CRYPT_ERROR); + ERR (CRYPT_OK); + ERR (CRYPT_ERROR); - ERR(CRYPT_INVALID_KEYSIZE); - ERR(CRYPT_INVALID_ROUNDS); - ERR(CRYPT_FAIL_TESTVECTOR); + ERR (CRYPT_INVALID_KEYSIZE); + ERR (CRYPT_INVALID_ROUNDS); + ERR (CRYPT_FAIL_TESTVECTOR); - ERR(CRYPT_BUFFER_OVERFLOW); - ERR(CRYPT_INVALID_PACKET); + ERR (CRYPT_BUFFER_OVERFLOW); + ERR (CRYPT_INVALID_PACKET); - ERR(CRYPT_INVALID_PRNGSIZE); - ERR(CRYPT_ERROR_READPRNG); + ERR (CRYPT_INVALID_PRNGSIZE); + ERR (CRYPT_ERROR_READPRNG); - ERR(CRYPT_INVALID_CIPHER); - ERR(CRYPT_INVALID_HASH); - ERR(CRYPT_INVALID_PRNG); + ERR (CRYPT_INVALID_CIPHER); + ERR (CRYPT_INVALID_HASH); + ERR (CRYPT_INVALID_PRNG); - ERR(CRYPT_MEM); + ERR (CRYPT_MEM); - ERR(CRYPT_PK_TYPE_MISMATCH); - ERR(CRYPT_PK_NOT_PRIVATE); + ERR (CRYPT_PK_TYPE_MISMATCH); + ERR (CRYPT_PK_NOT_PRIVATE); - ERR(CRYPT_INVALID_ARG); + ERR (CRYPT_INVALID_ARG); - ERR(CRYPT_PK_INVALID_TYPE); - ERR(CRYPT_PK_INVALID_SYSTEM); - ERR(CRYPT_PK_DUP); - ERR(CRYPT_PK_NOT_FOUND); - ERR(CRYPT_PK_INVALID_SIZE); + ERR (CRYPT_PK_INVALID_TYPE); + ERR (CRYPT_PK_INVALID_SYSTEM); + ERR (CRYPT_PK_DUP); + ERR (CRYPT_PK_NOT_FOUND); + ERR (CRYPT_PK_INVALID_SIZE); - ERR(CRYPT_INVALID_PRIME_SIZE); -} + ERR (CRYPT_INVALID_PRIME_SIZE); +} -int main(void) +int +main (void) { #ifdef SONY_PS2 - TIMER_Init(); + TIMER_Init (); #endif - register_all_algs(); + register_all_algs (); - if ((errno = yarrow_start(&prng)) != CRYPT_OK) { - printf("yarrow_start: %s\n", error_to_string(errno)); - } - if ((errno = yarrow_add_entropy("hello", 5, &prng)) != CRYPT_OK) { - printf("yarrow_add_entropy: %s\n", error_to_string(errno)); - } - if ((errno = yarrow_ready(&prng)) != CRYPT_OK) { - printf("yarrow_ready: %s\n", error_to_string(errno)); - } - - printf(crypt_build_settings); - test_errs(); + if ((errno = yarrow_start (&prng)) != CRYPT_OK) { + printf ("yarrow_start: %s\n", error_to_string (errno)); + } + if ((errno = yarrow_add_entropy ("hello", 5, &prng)) != CRYPT_OK) { + printf ("yarrow_add_entropy: %s\n", error_to_string (errno)); + } + if ((errno = yarrow_ready (&prng)) != CRYPT_OK) { + printf ("yarrow_ready: %s\n", error_to_string (errno)); + } + + printf (crypt_build_settings); + test_errs (); #ifdef HMAC - printf("HMAC: %s\n", hmac_test() == CRYPT_OK ? "passed" : "failed"); + printf ("HMAC: %s\n", hmac_test () == CRYPT_OK ? "passed" : "failed"); #endif - store_tests(); - cipher_tests(); - hash_tests(); + store_tests (); + cipher_tests (); + hash_tests (); - ecb_tests(); - cbc_tests(); - ctr_tests(); - ofb_tests(); - cfb_tests(); + ecb_tests (); + cbc_tests (); + ctr_tests (); + ofb_tests (); + cfb_tests (); - rng_tests(); - //test_prime(); + rng_tests (); + //test_prime(); - kr_test(); - rsa_test(); - pad_test(); - ecc_tests(); - dh_tests(); + kr_test (); + rsa_test (); + pad_test (); + ecc_tests (); + dh_tests (); - gf_tests(); - base64_test(); + gf_tests (); + base64_test (); - time_ecb(); - time_hash(); + time_ecb (); + time_hash (); #ifdef SONY_PS2 - TIMER_Shutdown(); + TIMER_Shutdown (); #endif - return 0; + return 0; } diff --git a/demos/test.c~ b/demos/test.c~ new file mode 100644 index 0000000..2426dc2 --- /dev/null +++ b/demos/test.c~ @@ -0,0 +1,1427 @@ +/* This is the worst code you have ever seen written on purpose.... this code is just a big hack to test +out the functionality of the library */ + +#ifdef SONY_PS2 +#include +#include +#include "timer.h" +#endif + +#include "../mycrypt.h" + +int errno; + + +int null_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + return CRYPT_OK; +} + +void null_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + memcpy(ct, pt, 8); +} + +void null_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + memcpy(pt, ct, 8); +} + +int null_test(void) +{ + return CRYPT_OK; +} + +int null_keysize(int *desired_keysize) +{ + return CRYPT_OK; +} + +const struct _cipher_descriptor null_desc = +{ + "memcpy()", + 255, + 8, 8, 8, 1, + &null_setup, + &null_ecb_encrypt, + &null_ecb_decrypt, + &null_test, + &null_keysize +}; + + +prng_state prng; + +void store_tests(void) +{ + unsigned char buf[8]; + unsigned long L; + ulong64 LL; + + printf("LOAD32/STORE32 tests\n"); + L = 0x12345678UL; + STORE32L(L, &buf[0]); + L = 0; + LOAD32L(L, &buf[0]); + if (L != 0x12345678UL) { printf("LOAD/STORE32 Little don't work\n"); exit(-1); } + LL = CONST64(0x01020304050607); + STORE64L(LL, &buf[0]); + LL = 0; + LOAD64L(LL, &buf[0]) + if (LL != CONST64(0x01020304050607)) { printf("LOAD/STORE64 Little don't work\n"); exit(-1); } + + L = 0x12345678UL; + STORE32H(L, &buf[0]); + L = 0; + LOAD32H(L, &buf[0]); + if (L != 0x12345678UL) { printf("LOAD/STORE32 High don't work\n"); exit(-1); } + LL = CONST64(0x01020304050607); + STORE64H(LL, &buf[0]); + LL = 0; + LOAD64H(LL, &buf[0]) + if (LL != CONST64(0x01020304050607)) { printf("LOAD/STORE64 High don't work\n"); exit(-1); } +} + +void cipher_tests(void) { + int x; + + printf("Ciphers compiled in\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf(" %12s (%2d) Key Size: %4d to %4d, Block Size: %3d, Default # of rounds: %2d\n", cipher_descriptor[x].name, + cipher_descriptor[x].ID, + cipher_descriptor[x].min_key_length*8,cipher_descriptor[x].max_key_length*8, + cipher_descriptor[x].block_length*8, cipher_descriptor[x].default_rounds); + } + +} + +void ecb_tests(void) +{ + int x; + + printf("ECB tests\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf(" %12s: ", + cipher_descriptor[x].name); + if ((errno = cipher_descriptor[x].test()) != CRYPT_OK) { + printf(" **failed** Reason: %s\n", error_to_string(errno)); + exit(-1); + } else { + printf("passed\n"); + } + } +} + +#ifdef CBC +void cbc_tests(void) +{ + symmetric_CBC cbc; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + const unsigned char test[] = { 0XFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + printf("CBC tests\n"); + /* ---- CBC ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a cbc session */ + if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { + printf("CBC Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cbc_encrypt(blk+8*x, ct+8*x, &cbc)) != CRYPT_OK) { + printf("CBC encrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + zeromem(blk, sizeof(blk)); + + /* ---- CBC DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a cbc session */ + if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { + printf("CBC Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cbc_decrypt(ct+8*x, blk+8*x, &cbc)) != CRYPT_OK) { + printf("CBC decrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + + /* lets actually check the bytes */ + memset(IV, 0, 8); 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 */ + 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 */ + if (memcmp(ct, test, 16)) { + printf("CBC failed logical testing.\n"); + for (x = 0; x < 16; x++) printf("%02x ", ct[x]); + printf("\n"); + exit(-1); + } else { + printf("CBC passed logical testing.\n"); + } +} +#else +void cbc_tests(void) { printf("CBC not compiled in\n"); } +#endif + +#ifdef OFB +void ofb_tests(void) +{ + symmetric_OFB ofb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + + printf("OFB tests\n"); + /* ---- ofb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a ofb session */ + if ((errno = ofb_start(find_cipher("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf("OFB Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ofb_encrypt(blk+8*x, ct+8*x, 8, &ofb)) != CRYPT_OK) { + printf("OFB encrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + zeromem(blk, sizeof(blk)); + + /* ---- ofb DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a ofb session */ + if ((errno = ofb_start(find_cipher("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf("OFB setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ofb_decrypt(ct+8*x, blk+8*x, 8, &ofb)) != CRYPT_OK) { + printf("OFB decrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + if (y) exit(-1); +} +#else +void ofb_tests(void) { printf("OFB not compiled in\n"); } +#endif + +#ifdef CFB +void cfb_tests(void) +{ + symmetric_CFB cfb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + + printf("CFB tests\n"); + /* ---- cfb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a cfb session */ + if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { + printf("CFB setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cfb_encrypt(blk+8*x, ct+8*x, 8, &cfb)) != CRYPT_OK) { + printf("CFB encrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + zeromem(blk, sizeof(blk)); + + /* ---- cfb DECODING ---- */ + /* make up ahash_descriptor[prng->yarrow.hash].hashsize IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a cfb session */ + if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { + printf("CFB Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = cfb_decrypt(ct+8*x, blk+8*x, 8, &cfb)) != CRYPT_OK) { + printf("CFB decrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + if (y) exit(-1); +} +#else +void cfb_tests(void) { printf("CFB not compiled in\n"); } +#endif + +#ifdef CTR +void ctr_tests(void) +{ + symmetric_CTR ctr; + int x, y; + unsigned char blk[32], ct[32], key[32], count[32]; + const unsigned char test[] = { 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }; + + printf("CTR tests\n"); + /* ---- CTR ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = count[x] = x; + + /* now lets start a ctr session */ + if ((errno = ctr_start(find_cipher("xtea"), count, key, 16, 0, &ctr)) != CRYPT_OK) { + printf("CTR Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ctr_encrypt(blk+8*x, ct+8*x, 8, &ctr)) != CRYPT_OK) { + printf("CTR encrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + zeromem(blk, sizeof(blk)); + + /* ---- CTR DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) count[x] = x; + + /* now lets start a cbc session */ + if ((errno = ctr_start(find_cipher("xtea"), count, key, 16, 0, &ctr)) != CRYPT_OK) { + printf("CTR Setup: %s\n", error_to_string(errno)); exit(-1); } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errno = ctr_decrypt(ct+8*x, blk+8*x, 8, &ctr)) != CRYPT_OK) { + printf("CTR decrypt: %s\n", error_to_string(errno)); exit(-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + if (y) exit(-1); + + /* lets actually check the bytes */ + memset(count, 0, 8); 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 */ + 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 */ + if (memcmp(ct, test, 16)) { + printf("CTR failed logical testing.\n"); + for (x = 0; x < 16; x++) printf("%02x ", ct[x]); + printf("\n"); + } else { + printf("CTR passed logical testing.\n"); + } + +} +#else +void ctr_tests(void) { printf("CTR not compiled in\n"); } +#endif + +void hash_tests(void) +{ + int x; + printf("Hash tests\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + printf(" %10s (%2d) ", hash_descriptor[x].name, hash_descriptor[x].ID); + if ((errno = hash_descriptor[x].test()) != CRYPT_OK) + printf("**failed** Reason: %s\n", error_to_string(errno)); + else + printf("passed\n"); + } +} + +#ifdef MRSA +void pad_test(void) +{ + unsigned char in[100], out[100]; + unsigned long x, y; + + /* make a dummy message */ + for (x = 0; x < 16; x++) in[x] = (unsigned char)x; + + /* pad the message so that random filler is placed before and after it */ + y = 100; + if ((errno = rsa_pad(in, 16, out, &y, find_prng("yarrow"), &prng)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); exit(-1); } + + /* depad the message to get the original content */ + memset(in, 0, sizeof(in)); + x = 100; + if ((errno = rsa_depad(out, y, in, &x)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); exit(-1); } + + /* check outcome */ + printf("rsa_pad: "); + if (x != 16) { printf("Failed. Wrong size.\n"); exit(-1); } + for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed. Expected %02lx and got %02x.\n", x, in[x]); exit(-1); } + printf("passed.\n"); +} + +void rsa_test(void) +{ + unsigned char in[4096], out[4096]; + unsigned long x, y, z, limit; + int stat; + rsa_key key; + clock_t t; + + /* ---- SINGLE ENCRYPT ---- */ + /* encrypt a short 8 byte string */ + if ((errno = rsa_make_key(&prng, find_prng("yarrow"), 1024/8, 65537, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); exit(-1); } + for (x = 0; x < 8; x++) in[x] = (unsigned char)(x+1); + y = sizeof(in); + if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); exit(-1); } + + /* decrypt it */ + zeromem(in, sizeof(in)); + x = sizeof(out); + if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); exit(-1); } + + /* compare */ + printf("RSA : "); + for (x = 0; x < 8; x++) if (in[x] != (x+1)) { printf("Failed. x==%02lx, in[%ld]==%02x\n", x, x, in[x]); exit(-1); } + printf("passed.\n"); + + /* test the rsa_encrypt_key functions */ + for (x = 0; x < 16; x++) in[x] = x; + y = sizeof(out); + if ((errno = rsa_encrypt_key(in, 16, out, &y, &prng, find_prng("yarrow"), &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + zeromem(in, sizeof(in)); + x = sizeof(in); + if ((errno = rsa_decrypt_key(out, y, in, &x, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("RSA en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); exit(-1); } + for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed (contents)\n"); exit(-1); } + printf("Passed\n"); + + /* test sign_hash functions */ + for (x = 0; x < 16; x++) in[x] = x; + x = sizeof(in); + if ((errno = rsa_sign_hash(in, 16, out, &x, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("RSA signed hash: %lu bytes\n", x); + if ((errno = rsa_verify_hash(out, x, in, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("Verify hash: %s, ", stat?"passed":"failed"); + in[0] ^= 1; + if ((errno = rsa_verify_hash(out, x, in, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("%s\n", (!stat)?"passed":"failed"); + if (stat) exit(-1); + rsa_free(&key); + + /* make a RSA key */ +#ifdef SONY_PS2_NOPE + limit = 1024; +#else + limit = 2048; +#endif + + { int tt; + + for (z = 1024; z <= limit; z += 512) { + t = XCLOCK(); + for (tt = 0; tt < 3; tt++) { + if ((errno = rsa_make_key(&prng, find_prng("yarrow"), z/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); 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); + + /* time encryption */ + t = XCLOCK(); + + for (tt = 0; tt < 100; tt++) { + y = sizeof(in); + if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); 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); + + /* time decryption */ + t = XCLOCK(); + for (tt = 0; tt < 100; tt++) { + x = sizeof(out); + if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); 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); + rsa_free(&key); + } + } + + + +} +#else +void pad_test(void) { printf("MRSA not compiled in\n"); } +void rsa_test(void) { printf("MRSA not compiled in\n"); } +#endif + +#ifdef BASE64 +void base64_test(void) +{ + unsigned char buf[2][100]; + unsigned long x, y; + + printf("Base64 tests\n"); + zeromem(buf, sizeof(buf)); + for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x; + + x = 100; + if (base64_encode(buf[0], 16, buf[1], &x) != CRYPT_OK) { + printf(" error: %s\n", error_to_string(errno)); + exit(-1); + } + printf(" encoded 16 bytes to %ld bytes...[%s]\n", x, buf[1]); + memset(buf[0], 0, 100); + y = 100; + if (base64_decode(buf[1], x, buf[0], &y) != CRYPT_OK) { + printf(" error: %s\n", error_to_string(errno)); + exit(-1); + } + printf(" decoded %ld bytes to %ld bytes\n", x, y); + for (x = 0; x < 16; x++) if (buf[0][x] != x) { + printf(" **failed**\n"); + exit(-1); + } + printf(" passed\n"); +} +#else +void base64_test(void) { printf("Base64 not compiled in\n"); } +#endif + +void time_hash(void) +{ + clock_t t1; + int x, y; + unsigned long z; + unsigned char input[4096], out[MAXBLOCKSIZE]; + printf("Hash Time Trials (4KB blocks):\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + t1 = XCLOCK(); + z = sizeof(out); + y = 0; + while (XCLOCK() - t1 < (3 * XCLOCKS_PER_SEC)) { + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); y += 16; + } + 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); + } +} + +void time_ecb(void) +{ + clock_t t1, t2; + long x, y1, y2; + unsigned char pt[32], key[32]; + symmetric_key skey; + void (*func)(const unsigned char *, unsigned char *, symmetric_key *); + + 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); + +#define DO1 func(pt,pt,&skey); +#define DO2 DO1 DO1 +#define DO4 DO2 DO2 +#define DO8 DO4 DO4 +#define DO16 DO8 DO8 +#define DO32 DO16 DO16 +#define DO64 DO32 DO32 +#define DO128 DO64 DO64 +#define DO256 DO128 DO128 + + func = cipher_descriptor[x].ecb_encrypt; + y1 = 0; + t1 = XCLOCK(); + while (XCLOCK() - t1 < 3*XCLOCKS_PER_SEC) { + DO256; y1 += 256; + } + t1 = XCLOCK() - t1; + + func = cipher_descriptor[x].ecb_decrypt; + y2 = 0; + t2 = XCLOCK(); + while (XCLOCK() - t2 < 3*XCLOCKS_PER_SEC) { + DO256; y2 += 256; + } + t2 = XCLOCK() - t2; + printf("%-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, + ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y2 / ((double)t2 / (double)XCLOCKS_PER_SEC))) / 1000000.0); + +#undef DO256 +#undef DO128 +#undef DO64 +#undef DO32 +#undef DO16 +#undef DO8 +#undef DO4 +#undef DO2 +#undef DO1 + } +} + +#ifdef MDH +void dh_tests(void) +{ + unsigned char buf[3][4096]; + unsigned long x, y, z; + int low, high, stat, stat2; + dh_key usera, userb; + clock_t t1; + +/* if ((errno = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errno)); */ + + dh_sizes(&low, &high); + printf("DH Keys from %d to %d supported.\n", low*8, high*8); + + /* make up two keys */ + if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make the shared secret */ + x = 4096; + if ((errno = dh_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + y = 4096; + if ((errno = dh_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + if (y != x) { printf("DH Shared keys are not same size.\n"); exit(-1); } + if (memcmp(buf[0], buf[1], x)) { printf("DH Shared keys not same contents.\n"); exit(-1); } + + /* now export userb */ + y = 4096; + if ((errno = dh_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + dh_free(&userb); + + /* import and make the shared secret again */ + if ((errno = dh_import(buf[1], y, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + z = 4096; + if ((errno = dh_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + printf("DH routines: "); + if (z != x) { printf("failed. Size don't match?\n"); exit(-1); } + if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); exit(-1); } + printf("Passed\n"); + dh_free(&usera); + dh_free(&userb); + +/* time stuff */ + { + static int sizes[] = { 96, 128, 160, 192, 224, 256, 320, 384, 512 }; + int ii, tt; + + for (ii = 0; ii < (int)(sizeof(sizes)/sizeof(sizes[0])); ii++) { + t1 = XCLOCK(); + for (tt = 0; tt < 50; tt++) { + 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 / 50.0) / (double)XCLOCKS_PER_SEC)); + } + } + +/* test encrypt_key */ + dh_make_key(&prng, find_prng("yarrow"), 96, &usera); + for (x = 0; x < 16; x++) buf[0][x] = x; + y = sizeof(buf[1]); + if ((errno = dh_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + zeromem(buf[0], sizeof(buf[0])); + x = sizeof(buf[0]); + if ((errno = dh_decrypt_key(buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("DH en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); exit(-1); } + for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); exit(-1); } + printf("Passed (size %lu)\n", y); + +/* test sign_hash */ + for (x = 0; x < 16; x++) buf[0][x] = x; + x = sizeof(buf[1]); + if ((errno = dh_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + if (dh_verify_hash(buf[1], x, buf[0], 16, &stat, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + buf[0][0] ^= 1; + if (dh_verify_hash(buf[1], x, buf[0], 16, &stat2, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("dh_sign/verify_hash: %s (%d,%d), %lu\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2, x); + dh_free(&usera); +} +#else +void dh_tests(void) { printf("MDH not compiled in\n"); } +#endif + +int callback_x = 0; +void callback(void) +{ + printf("%c\x08", "-\\|/"[++callback_x & 3]); +#ifndef SONY_PS2 + fflush(stdout); +#endif +} + +void rng_tests(void) +{ + unsigned char buf[16]; + clock_t t1; + int x, y; + + printf("RNG tests\n"); + t1 = XCLOCK(); + x = rng_get_bytes(buf, sizeof(buf), &callback); + t1 = XCLOCK() - t1; + printf(" %f bytes per second...", + (double)x / ((double)t1 / (double)XCLOCKS_PER_SEC)); + printf("read %d bytes.\n ", x); + for (y = 0; y < x; y++) + printf("%02x ", buf[y]); + printf("\n"); + +#ifdef YARROW + if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, &callback)) != CRYPT_OK) { + printf(" starting yarrow error: %s\n", error_to_string(errno)); + exit(-1); + } +#endif +} + +#ifdef MECC +void ecc_tests(void) +{ + unsigned char buf[4][4096]; + unsigned long x, y, z; + int stat, stat2, low, high; + ecc_key usera, userb; + clock_t t1; + + if ((errno = ecc_test()) != CRYPT_OK) { printf("ecc Error: %s\n", error_to_string(errno)); exit(-1); } + + ecc_sizes(&low, &high); + printf("ecc Keys from %d to %d supported.\n", low*8, high*8); + + /* make up two keys */ + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make the shared secret */ + x = 4096; + if ((errno = ecc_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + y = 4096; + if ((errno = ecc_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + if (y != x) { printf("ecc Shared keys are not same size.\n"); exit(-1); } + + if (memcmp(buf[0], buf[1], x)) { printf("ecc Shared keys not same contents.\n"); exit(-1); } + + /* now export userb */ + y = 4096; + if ((errno = ecc_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + ecc_free(&userb); + printf("ECC-192 export took %ld bytes\n", y); + + /* import and make the shared secret again */ + if ((errno = ecc_import(buf[1], y, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + z = 4096; + if ((errno = ecc_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + + printf("ecc routines: "); + if (z != x) { printf("failed. Size don't match?\n"); exit(-1); } + if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); exit(-1); } + printf("Passed\n"); + ecc_free(&usera); + ecc_free(&userb); + +/* time stuff */ + { + static int sizes[] = { 20, 24, 28, 32, 48, 65 }; + int ii, tt; + + for (ii = 0; ii < (int)(sizeof(sizes)/sizeof(sizes[0])); ii++) { + t1 = XCLOCK(); + for (tt = 0; tt < 25; tt++) { + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), sizes[ii], &usera)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); 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)); + } + } + +/* test encrypt_key */ + ecc_make_key(&prng, find_prng("yarrow"), 65, &usera); + for (x = 0; x < 16; x++) buf[0][x] = x; + y = sizeof(buf[1]); + if ((errno = ecc_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + zeromem(buf[0], sizeof(buf[0])); + x = sizeof(buf[0]); + if ((errno = ecc_decrypt_key(buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("ECC en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); exit(-1); } + for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); exit(-1); } + printf("Passed (size: %lu)\n", y); +/* test sign_hash */ + for (x = 0; x < 16; x++) buf[0][x] = x; + x = sizeof(buf[1]); + if ((errno = ecc_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + if (ecc_verify_hash(buf[1], x, buf[0], 16, &stat, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + buf[0][0] ^= 1; + if (ecc_verify_hash(buf[1], x, buf[0], 16, &stat2, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + exit(-1); + } + printf("ecc_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); + ecc_free(&usera); +} +#else +void ecc_tests(void) { printf("MECC not compiled in\n"); } +#endif + +#ifdef GF +void gf_tests(void) +{ + gf_int a, b, c, d; + int n; + unsigned char buf[1024]; + + printf("GF tests\n"); + gf_zero(a);gf_zero(b);gf_zero(c);gf_zero(d); + + /* a == 0x18000000b */ + a[1] = 1; + a[0] = 0x8000000bUL; + + /* b == 0x012345678 */ + b[0] = 0x012345678UL; + + /* find 1/b mod a */ + gf_invmod(b,a,c); + + /* find 1/1/b mod a */ + gf_invmod(c,a,d); + + /* display them */ + printf(" %08lx %08lx\n", c[0], d[0]); + + /* store as binary string */ + n = gf_size(a); + printf(" a takes %d bytes\n", n); + gf_toraw(a, buf); + gf_readraw(a, buf, n); + printf(" a == %08lx%08lx\n", a[1], a[0]); + + /* primality testing */ + gf_zero(a); + a[0] = 0x169; + printf(" GF prime: %s, ", gf_is_prime(a)?"passed":"failed"); + a[0] = 0x168; + printf(" %s\n", gf_is_prime(a)?"failed":"passed"); + + /* test sqrt code */ + gf_zero(a); + a[1] = 0x00000001; + a[0] = 0x8000000bUL; + gf_zero(b); + b[0] = 0x12345678UL; + + gf_sqrt(b, a, c); + gf_mulmod(c, c, a, b); + printf(" (%08lx)^2 = %08lx (mod %08lx%08lx) \n", c[0], b[0], a[1], a[0]); +} +#else +void gf_tests(void) { printf("GF not compiled in\n"); } +#endif + +#ifdef MPI +void test_prime(void) +{ + unsigned char buf[1024]; + mp_int a; + int x; + + /* make a 1024 bit prime */ + mp_init(&a); + rand_prime(&a, 128, &prng, find_prng("yarrow")); + + /* dump it */ + mp_todecimal(&a, buf); + printf("1024-bit prime:\n"); + for (x = 0; x < (int)strlen(buf); ) { + printf("%c", buf[x]); + if (!(++x % 60)) printf("\\ \n"); + } + printf("\n\n"); + + mp_clear(&a); +} +#else +void test_prime(void) { printf("MPI not compiled in\n"); } +#endif + +void register_all_algs(void) +{ +#ifdef BLOWFISH + register_cipher(&blowfish_desc); +#endif +#ifdef XTEA + register_cipher(&xtea_desc); +#endif +#ifdef RC5 + register_cipher(&rc5_desc); +#endif +#ifdef RC6 + register_cipher(&rc6_desc); +#endif +#ifdef SAFERP + register_cipher(&saferp_desc); +#endif +#ifdef SERPENT + register_cipher(&serpent_desc); +#endif +#ifdef RIJNDAEL + register_cipher(&aes_desc); +#endif +#ifdef TWOFISH + register_cipher(&twofish_desc); +#endif +#ifdef SAFER + register_cipher(&safer_k64_desc); + register_cipher(&safer_sk64_desc); + register_cipher(&safer_k128_desc); + register_cipher(&safer_sk128_desc); +#endif +#ifdef RC2 + register_cipher(&rc2_desc); +#endif +#ifdef DES + register_cipher(&des_desc); + register_cipher(&des3_desc); +#endif +#ifdef CAST5 + register_cipher(&cast5_desc); +#endif +#ifdef NOEKEON + register_cipher(&noekeon_desc); +#endif + + register_cipher(&null_desc); + +#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 +#ifdef SHA384 + register_hash(&sha384_desc); +#endif +#ifdef SHA512 + register_hash(&sha512_desc); +#endif +#ifdef MD4 + register_hash(&md4_desc); +#endif +#ifdef MD2 + register_hash(&md2_desc); +#endif + +#ifdef YARROW + register_prng(&yarrow_desc); +#endif +#ifdef SPRNG + register_prng(&sprng_desc); +#endif +} + +void kr_display(pk_key *kr) +{ + static const char *system[] = { "NON-KEY", "RSA", "DH", "ECC" }; + static const char *type[] = { "PRIVATE", "PUBLIC", "PRIVATE_OPTIMIZED" }; + + while (kr->system != NON_KEY) { + printf("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, system[kr->system], type[kr->key_type], kr->name, kr->email, kr->description); + kr = kr->next; + } + printf("\n"); +} + +void kr_test_makekeys(pk_key **kr) +{ + if ((errno = kr_init(kr)) != CRYPT_OK) { + printf("KR init error %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a DH key */ + printf("KR: Making DH key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), DH_KEY, 128, "dhkey", "dh@dh.dh", "dhkey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a ECC key */ + printf("KR: Making ECC key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), ECC_KEY, 20, "ecckey", "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a RSA key */ + printf("KR: Making RSA key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), RSA_KEY, 128, "rsakey", "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } + +} + +void kr_test(void) +{ + pk_key *kr, *_kr; + unsigned char buf[8192], buf2[8192], buf3[8192]; + unsigned long len; + int i, j, stat; +#ifndef NO_FILE + FILE *f; +#endif + + kr_test_makekeys(&kr); + + printf("The original list:\n"); + kr_display(kr); + + for (i = 0; i < 3; i++) { + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("Exported key was: %lu bytes\n", len); + if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { + printf("Error deleting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { + printf("Error importing key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + } + + for (i = 0; i < 3; i++) { + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("Exported key was: %lu bytes\n", len); + if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { + printf("Error deleting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { + printf("Error importing key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + } + + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("Error clearing ring: %s\n", error_to_string(errno)); + exit(-1); + } + + +/* TEST output to file */ +#ifndef NO_FILE + + if ((errno = kr_init(&kr)) != CRYPT_OK) { + printf("KR init error %s\n", error_to_string(errno)); + exit(-1); + } + kr_test_makekeys(&kr); + + /* save to file */ + f = fopen("ring.dat", "wb"); + if ((errno = kr_save(kr, f, NULL)) != CRYPT_OK) { + printf("kr_save error %s\n", error_to_string(errno)); + exit(-1); + } + fclose(f); + + /* delete and load */ + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("clear error: %s\n", error_to_string(errno)); + exit(-1); + } + + f = fopen("ring.dat", "rb"); + if ((errno = kr_load(&kr, f, NULL)) != CRYPT_OK) { + printf("kr_load error %s\n", error_to_string(errno)); + exit(-1); + } + fclose(f); + remove("ring.dat"); + printf("After load and save...\n"); + kr_display(kr); + + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("clear error: %s\n", error_to_string(errno)); + exit(-1); + } + +#endif + +/* test the packet encryption/sign stuff */ + for (i = 0; i < 32; i++) buf[i] = i; + kr_test_makekeys(&kr); + _kr = kr; + for (i = 0; i < 3; i++) { + printf("Testing a key with system %d, type %d:\t", _kr->system, _kr->key_type); + len = sizeof(buf2); + if ((errno = 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(errno)); + exit(-1); + } + len = sizeof(buf3); + if ((errno = kr_decrypt_key(kr, buf2, buf3, &len)) != CRYPT_OK) { + printf("decrypt error, %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + if (len != 16 || memcmp(buf3, buf, 16)) { + printf("kr_decrypt_key failed, %i, %lu\n", i, len); + exit(-1); + } + printf("kr_encrypt_key passed, "); + + len = sizeof(buf2); + if ((errno = 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(errno)); + exit(-1); + } + printf("kr_sign_hash: "); + if ((errno = kr_verify_hash(kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf("kr_sign_hash failed, %i, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("%s, ", stat?"passed":"failed"); + buf[15] ^= 1; + if ((errno = kr_verify_hash(kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf("kr_sign_hash failed, %i, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("%s\n", (!stat)?"passed":"failed"); + buf[15] ^= 1; + + len = sizeof(buf); + if ((errno = kr_fingerprint(kr, _kr->ID, find_hash("sha1"), buf, &len)) != CRYPT_OK) { + printf("kr_fingerprint failed, %i, %lu\n", i, len); + exit(-1); + } + printf("Fingerprint: "); + for (j = 0; j < 20; j++) { + printf("%02x", buf[j]); + if (j < 19) printf(":"); + } + printf("\n\n"); + + _kr = _kr->next; + } + +/* Test encrypting/decrypting to a public key */ +/* first dump the other two keys */ + kr_del(&kr, kr->ID); + kr_del(&kr, kr->ID); + kr_display(kr); + + /* now export it as public and private */ + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + + /* check boundaries */ + memset(buf+len, 0, sizeof(buf)-len); + + len = sizeof(buf2); + if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) { + printf("Error exporting key %s\n", error_to_string(errno)); + exit(-1); + } + + /* check boundaries */ + memset(buf2+len, 0, sizeof(buf2)-len); + + /* delete the key and import the public */ + kr_clear(&kr); + kr_init(&kr); + kr_display(kr); + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { + printf("Error importing key %s\n", error_to_string(errno)); + exit(-1); + } + kr_display(kr); + + /* now encrypt a buffer */ + for (i = 0; i < 16; i++) buf[i] = i; + len = sizeof(buf3); + if ((errno = kr_encrypt_key(kr, kr->ID, buf, 16, buf3, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) { + printf("Encrypt error, %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + + /* now delete the key and import the private one */ + kr_clear(&kr); + kr_init(&kr); + kr_display(kr); + if ((errno = kr_import(kr, buf2, len)) != CRYPT_OK) { + printf("Error importing key %s\n", error_to_string(errno)); + exit(-1); + } + kr_display(kr); + + /* now decrypt */ + len = sizeof(buf2); + if ((errno = kr_decrypt_key(kr, buf3, buf2, &len)) != CRYPT_OK) { + printf("decrypt error, %s\n", error_to_string(errno)); + exit(-1); + } + + printf("KR encrypt to public, decrypt with private: "); + if (len == 16 && !memcmp(buf2, buf, 16)) { + printf("passed\n"); + } else { + printf("failed\n"); + } + + kr_clear(&kr); + +} + +void test_errs(void) +{ + #define ERR(x) printf("%25s => %s\n", #x, error_to_string(x)); + + ERR(CRYPT_OK); + ERR(CRYPT_ERROR); + + ERR(CRYPT_INVALID_KEYSIZE); + ERR(CRYPT_INVALID_ROUNDS); + ERR(CRYPT_FAIL_TESTVECTOR); + + ERR(CRYPT_BUFFER_OVERFLOW); + ERR(CRYPT_INVALID_PACKET); + + ERR(CRYPT_INVALID_PRNGSIZE); + ERR(CRYPT_ERROR_READPRNG); + + ERR(CRYPT_INVALID_CIPHER); + ERR(CRYPT_INVALID_HASH); + ERR(CRYPT_INVALID_PRNG); + + ERR(CRYPT_MEM); + + ERR(CRYPT_PK_TYPE_MISMATCH); + ERR(CRYPT_PK_NOT_PRIVATE); + + ERR(CRYPT_INVALID_ARG); + + ERR(CRYPT_PK_INVALID_TYPE); + ERR(CRYPT_PK_INVALID_SYSTEM); + ERR(CRYPT_PK_DUP); + ERR(CRYPT_PK_NOT_FOUND); + ERR(CRYPT_PK_INVALID_SIZE); + + ERR(CRYPT_INVALID_PRIME_SIZE); +} + + + +int main(void) +{ +#ifdef SONY_PS2 + TIMER_Init(); +#endif + + register_all_algs(); + + if ((errno = yarrow_start(&prng)) != CRYPT_OK) { + printf("yarrow_start: %s\n", error_to_string(errno)); + } + if ((errno = yarrow_add_entropy("hello", 5, &prng)) != CRYPT_OK) { + printf("yarrow_add_entropy: %s\n", error_to_string(errno)); + } + if ((errno = yarrow_ready(&prng)) != CRYPT_OK) { + printf("yarrow_ready: %s\n", error_to_string(errno)); + } + + printf(crypt_build_settings); + test_errs(); + +#ifdef HMAC + printf("HMAC: %s\n", hmac_test() == CRYPT_OK ? "passed" : "failed"); +#endif + + store_tests(); + cipher_tests(); + hash_tests(); + + ecb_tests(); + cbc_tests(); + ctr_tests(); + ofb_tests(); + cfb_tests(); + + rng_tests(); + //test_prime(); + + kr_test(); + rsa_test(); + pad_test(); + ecc_tests(); + dh_tests(); + + gf_tests(); + base64_test(); + + time_ecb(); + time_hash(); + +#ifdef SONY_PS2 + TIMER_Shutdown(); +#endif + + return 0; +} diff --git a/ecc.c b/ecc.c index 1bb7ea2..aad0344 100644 --- a/ecc.c +++ b/ecc.c @@ -239,13 +239,12 @@ static void del_point(ecc_point *p) XFREE(p); } - /* double a point R = 2P, R can be P*/ -static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus) +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) { return CRYPT_MEM; } @@ -254,12 +253,18 @@ static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus) if (mp_mul_2(&P->y, &tmp) != MP_OKAY) { goto error; } /* tmp = 2*y */ if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ if (mp_sqr(&P->x, &s) != MP_OKAY) { goto error; } /* s = x^2 */ + if (mp_reduce(&s, modulus, mu) != MP_OKAY) { goto error; } if (mp_mul_d(&s,(mp_digit)3, &s) != MP_OKAY) { goto error; } /* s = 3*(x^2) */ if (mp_sub_d(&s,(mp_digit)3, &s) != MP_OKAY) { goto error; } /* s = 3*(x^2) - 3 */ - if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY) { goto error; } /* s = tmp * s mod modulus */ + if (mp_cmp_d(&s, 0) == MP_LT) { /* if s < 0 add modulus */ + if (mp_add(&s, modulus, &s) != MP_OKAY) { goto error; } + } + if (mp_mul(&s, &tmp, &s) != MP_OKAY) { goto error; } /* s = tmp * s mod modulus */ + if (mp_reduce(&s, modulus, mu) != MP_OKAY) { goto error; } /* Xr = s^2 - 2Xp */ if (mp_sqr(&s, &tmpx) != MP_OKAY) { goto error; } /* tmpx = s^2 */ + if (mp_reduce(&tmpx, modulus, mu) != MP_OKAY) { goto error; } /* tmpx = tmpx mod modulus */ if (mp_sub(&tmpx, &P->x, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmpx - x */ if (mp_submod(&tmpx, &P->x, modulus, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmpx - x mod modulus */ @@ -279,11 +284,11 @@ done: } /* add two different points over Z/pZ, R = P + Q, note R can equal either P or Q */ -static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus) +static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus, mp_int *mu) { mp_int s, tmp, tmpx; int res; - + if (mp_init(&tmp) != MP_OKAY) { return CRYPT_MEM; } @@ -297,7 +302,7 @@ static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus) 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); + return dbl_point(P, R, modulus, mu); } if (mp_init_multi(&tmpx, &s, NULL) != MP_OKAY) { @@ -306,13 +311,21 @@ static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus) } /* get s = (Yp - Yq)/(Xp-Xq) mod p */ - if (mp_submod(&P->x, &Q->x, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = Px - Qx mod modulus */ + if (mp_sub(&P->x, &Q->x, &tmp) != MP_OKAY) { goto error; } /* tmp = Px - Qx mod modulus */ + if (mp_cmp_d(&tmp, 0) == MP_LT) { /* if tmp<0 add modulus */ + if (mp_add(&tmp, modulus, &tmp) != MP_OKAY) { goto error; } + } if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ if (mp_sub(&P->y, &Q->y, &s) != MP_OKAY) { goto error; } /* s = Py - Qy mod modulus */ - if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY) { goto error; } /* s = s * tmp mod modulus */ + if (mp_cmp_d(&s, 0) == MP_LT) { /* if s<0 add modulus */ + if (mp_add(&s, modulus, &s) != MP_OKAY) { goto error; } + } + if (mp_mul(&s, &tmp, &s) != MP_OKAY) { goto error; } /* s = s * tmp mod modulus */ + if (mp_reduce(&s, modulus, mu) != MP_OKAY) { goto error; } /* Xr = s^2 - Xp - Xq */ - if (mp_sqrmod(&s, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = s^2 mod modulus */ + if (mp_sqr(&s, &tmp) != MP_OKAY) { goto error; } /* tmp = s^2 mod modulus */ + if (mp_reduce(&tmp, modulus, mu) != MP_OKAY) { goto error; } if (mp_sub(&tmp, &P->x, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - Px */ if (mp_sub(&tmp, &Q->x, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmp - Qx */ @@ -334,32 +347,74 @@ done: /* perform R = kG where k == integer and G == ecc_point */ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) { - ecc_point *tG, *M[14]; - int i, j, z, res; + ecc_point *tG, *M[30]; + int i, j, z, res, Q; mp_digit d; unsigned char bits[150], m, first; + mp_int mu; - /* init M tab */ - for (i = 0; i < 14; i++) { + + if ((USED(k) * MP_DIGIT_BIT) > 256) { + Q = 5; + } else { + Q = 4; + } + + if (mp_init(&mu) != MP_OKAY) { + return CRYPT_MEM; + } + + /* init barrett reduction */ + mp_set(&mu, 1); + mp_lshd(&mu, 2 * USED(modulus)); + if (mp_div(&mu, modulus, &mu, NULL) != MP_OKAY) { + mp_clear(&mu); + return CRYPT_MEM; + } + + + /* init M tab (alloc here, calculate below) + + This table holds the first 2^Q multiples of the input base point G, that is + + M[x] = x * G + + Where G is the point and x is a scalar. The implementation is optimized + since M[0] == 0 and M[1] == G so there is no need to waste space for those. In + effect M'[x] == M[x+2] where M'[] is the table we make. If M[0] or M[1] are needed + we handle them with if statements. + + */ + for (i = 0; i < ((1<>= 1; } } @@ -371,34 +426,35 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) /* make a copy of G incase R==G */ tG = new_point(); - if (tG == NULL) { goto error; } + if (tG == NULL) { goto error; } /* skip leading digits which are zero */ --i; while (i != 0 && bits[i] == (unsigned char)0) { --i; } + /* if the multiplicand has no non-zero 4-bit words its invalid. */ if (i == 0) { res = CRYPT_INVALID_ARG; goto done; } - /* now calc the M tab, note that there are only 14 spots, the normal M[0] is a no-op, and M[1] is the input + /* now calc the M tab, note that there are only 2^Q - 2 spots, the normal M[0] is a no-op, and M[1] is the input point (saves ram) */ /* M[0] now is 2*G */ - if (dbl_point(G, M[0], modulus) != CRYPT_OK) { goto error; } - for (j = 1; j < 14; j++) { - if (add_point(M[j-1], G, M[j], modulus) != CRYPT_OK) { goto error; } + if (dbl_point(G, M[0], modulus, &mu) != CRYPT_OK) { goto error; } + for (j = 1; j < ((1<x, &tG->x) != MP_OKAY) { goto error; } - if (mp_copy(&G->y, &tG->y) != MP_OKAY) { goto error; } + if (mp_copy(&G->x, &tG->x) != MP_OKAY) { goto error; } + if (mp_copy(&G->y, &tG->y) != MP_OKAY) { goto error; } /* set result M[bits[i]] */ if (bits[i] == (unsigned char)1) { - if (mp_copy(&G->x, &R->x) != MP_OKAY) { goto error; } - if (mp_copy(&G->y, &R->y) != MP_OKAY) { goto error; } + if (mp_copy(&G->x, &R->x) != MP_OKAY) { goto error; } + if (mp_copy(&G->y, &R->y) != MP_OKAY) { goto error; } } else if (bits[i] >= (unsigned char)2) { if (mp_copy(&M[(int)bits[i]-2]->x, &R->x) != MP_OKAY) { goto error; } if (mp_copy(&M[(int)bits[i]-2]->y, &R->y) != MP_OKAY) { goto error; } @@ -406,8 +462,8 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) while (--i >= 0) { /* double */ - for (j = 0; j < 4; j++) { - if (dbl_point(R, R, modulus) != CRYPT_OK) { goto error; } + for (j = 0; j < Q; j++) { + if (dbl_point(R, R, modulus, &mu) != CRYPT_OK) { goto error; } } /* now based on the value of bits[i] we do ops */ @@ -415,10 +471,10 @@ static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) /* nop */ } else if (bits[i] == (unsigned char)1) { /* add base point */ - if (add_point(R, tG, R, modulus) != CRYPT_OK) { goto error; } + if (add_point(R, tG, R, modulus, &mu) != CRYPT_OK) { goto error; } } else { /* other case */ - if (add_point(R, M[(int)bits[i] - 2], R, modulus) != CRYPT_OK) { goto error; } + if (add_point(R, M[(int)bits[i] - 2], R, modulus, &mu) != CRYPT_OK) { goto error; } } } @@ -428,9 +484,10 @@ error: res = CRYPT_MEM; done: del_point(tG); - for (i = 0; i < 14; i++) { + for (i = 0; i < ((1<idx].prime, 64) != MP_OKAY) { goto error; } + + /* calculate barrett stuff */ + mp_set(&mu, 1); + mp_lshd(&mu, 2 * USED(&p)); + if (mp_div(&mu, &p, &mu, NULL) != MP_OKAY) { + res = CRYPT_MEM; + goto done; + } /* get bA */ - if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } + if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } /* get bA + Y */ - if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } + if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p, &mu) != CRYPT_OK) { goto error; } /* get mG */ if (mp_read_radix(&mG->x, (unsigned char *)sets[key->idx].Gx, 64) != MP_OKAY) { goto error; } @@ -403,7 +411,7 @@ error: done: del_point(mG); ecc_free(&pubkey); - mp_clear_multi(&p, &m, &b, NULL); - return CRYPT_OK; + mp_clear_multi(&p, &m, &b, &mu, NULL); + return res; } diff --git a/examples/ch2-01.c b/examples/ch2-01.c new file mode 100644 index 0000000..b565479 --- /dev/null +++ b/examples/ch2-01.c @@ -0,0 +1,35 @@ +/* + * Name : ch2-01.c + * Purpose : Demonstration of reading the RNG + * Author : Tom St Denis + * + * History : v0.81 Initial release + */ + + /* ch2-02-2 */ + #include + + int main(void) + { + unsigned char buf[16]; + unsigned long len; + int ix; + + /* read the RNG */ + len = rng_get_bytes(buf, sizeof(buf), NULL); + + /* verify return */ + if (len != sizeof(buf)) { + printf("Error: Only read %lu bytes.\n", len); + } else { + printf("Read %lu bytes\n", len); + for (ix = 0; ix < sizeof(buf); ix++) { + printf("%02x ", buf[ix]); + } + printf("\n"); + } + + return EXIT_SUCCESS; +} +/* ch2-02-2 */ + diff --git a/legal.txt b/legal.txt new file mode 100644 index 0000000..0603d4f --- /dev/null +++ b/legal.txt @@ -0,0 +1,80 @@ +Legal Issues Regarding LibTomCrypt +Tom St Denis + +The bulk of the code was written or donated under the TDCAL "Tom Doesn't Care About License" license. It entitles the developer to free-reign on +the use and distribution of derived works, commercial or otherwise. Certain files are taken from public domain packages. + +AES.C +----- +Author: Dr Brian Gladman +Email : gladman@seven77.demon.co.uk +Disclaimer (verbatim) +---- +/* Copyright in this implementation is held by Dr B R Gladman but I */ +/* hereby give permission for its free direct or derivative use subject */ +/* to acknowledgment of its origin and compliance with any conditions */ +/* that the originators of the algorithm place on its exploitation. */ +---- +Status: Public Domain, modified [not original] + +DES.C +----- +Author: Unknown, Submitted by Dobes Vandermeer +Email : dobes@smartt.com +Disclaimer: None +Status: TDCAL submission by Dobes, modified [not original] + +MD4.C +----- +Author: Dobes Vandermeer +Email : dobes@smartt.com +Disclaimer: None +Status: TDCAL submission by Dobes, modified [not original] + +HMAC.C +------ +Author: Dobes Vandermeer +Email: dobes@smartt.com +Disclaimer: None +Status: TDCAL submission by Dobes, modified [not original] + +MPI.C +----- +Author: Original [v0.80 and prior] Michael Fromberger, Current [v0.81 and later] Tom St Denis +Email: tomstdenis@iahu.ca +Disclaimer: None +Status: TDCAL submission by Tom + +RC2.C +----- +Author: Unknown, found on public domain archive [www.wiretapped.net] +Email: none +Disclaimer: Possible legal issues [should remove RC2/RC5/RC6 to simplify legal issues] +Status: Public Domain, questionable legal status, modified [not original] + +SAFER.C +------- +Author: [copied verbatim] +---- +* AUTHOR: Richard De Moliner (demoliner@isi.ee.ethz.ch) +* Signal and Information Processing Laboratory +* Swiss Federal Institute of Technology +* CH-8092 Zuerich, Switzerland +---- +Email: demoliner@isi.ee.ethz.ch +Disclaimer: Appears to be Public Domain [not quite sure] +Status: Public Domain, modified [not original] + +SERPENT.C +--------- +Author: Dr. Brian Gladman +Email : gladman@seven77.demon.co.uk +Disclaimer (verbatim) +---- +/* Copyright in this implementation is held by Dr B R Gladman but I */ +/* hereby give permission for its free direct or derivative use subject */ +/* to acknowledgment of its origin and compliance with any conditions */ +/* that the originators of the algorithm place on its exploitation. */ +---- +Status: Public Domain, modified [not original] + diff --git a/makefile b/makefile index 524839c..7daa8f7 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.80 +VERSION=0.81 #ch1-01-1 # Compiler and Linker Names @@ -21,200 +21,22 @@ AR=ar ARFLAGS=r #ch1-01-1 -#ch1-01-2 -# here you can set the malloc/calloc/free functions you want -XMALLOC=malloc -XCALLOC=calloc -XREALLOC=realloc -XFREE=free - -# you can redefine the clock -XCLOCK=clock -XCLOCKS_PER_SEC=CLOCKS_PER_SEC -#ch1-01-2 - #ch1-01-3 # Compilation flags. Note the += does not write over the user's CFLAGS! -CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ - -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) \ - -DXREALLOC=$(XREALLOC) -DXCLOCK=$(XCLOCK) \ - -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) +CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror # optimize for SPEED #CFLAGS += -O3 -funroll-loops -# optimize for SIZE -CFLAGS += -Os +# optimize for SIZE +CFLAGS += -Os -# compile for DEBUGGING +# compile for DEBUGGING #CFLAGS += -g3 #ch1-01-3 #These flags control how the library gets built. -#ch1-01-4 -# Use small code variants of functions when possible? -CFLAGS += -DSMALL_CODE - -# no file support, when defined the library will not -# have any functions that can read/write files -# (comment out to have file support) -#CFLAGS += -DNO_FILE - -# Support the UNIX /dev/random or /dev/urandom -CFLAGS += -DDEVRANDOM - -# Use /dev/urandom first on devices where -# /dev/random is too slow -#CFLAGS += -DTRY_URANDOM_FIRST - -# Clean the stack after sensitive functions. Not -# always required... With this defined most of -# the ciphers and hashes will clean their stack area -# after usage with a (sometimes) huge penalty in speed. -# Normally this is not required if you simply lock your -# stack and wipe it when your program is done. -# -#CFLAGS += -DCLEAN_STACK -#ch1-01-4 - -#ch1-01-5 -# What algorithms to include? comment out and rebuild to remove them -CFLAGS += -DBLOWFISH -CFLAGS += -DRC2 -CFLAGS += -DRC5 -CFLAGS += -DRC6 -CFLAGS += -DSERPENT -CFLAGS += -DSAFERP -CFLAGS += -DSAFER -CFLAGS += -DRIJNDAEL -CFLAGS += -DXTEA -CFLAGS += -DTWOFISH -CFLAGS += -DDES -CFLAGS += -DCAST5 -CFLAGS += -DNOEKEON -#ch1-01-5 - -#You can also customize the Twofish code. All four combinations -#of the flags are possible but only three of them make sense. -# -#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key -#Both defined : Slow, requires only ~100 bytes of ram per scheduled key -# -#If defined on their own -#_SMALL defined: Very Slow, small code only ~100 bytes of ram -#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger -# faster keysetup though... - -#ch1-01-6 -# Small Ram Variant of Twofish. For this you must have TWOFISH -# defined. This variant requires about 4kb less memory but -# is considerably slower. It is ideal when high throughput is -# less important than conserving memory. By default it is not -# defined which means the larger ram (about 4.2Kb used) variant -# is built. -#CFLAGS += -DTWOFISH_SMALL - -# Tell Twofish to use precomputed tables. If you want to use -# the small table variant of Twofish you may want to turn -# this on. Essentially it tells Twofish to use precomputed -# S-boxes (Q0 and Q1) as well as precomputed GF -# multiplications [in the MDS]. This speeds up the cipher -# somewhat. -#CFLAGS += -DTWOFISH_TABLES -#ch1-01-6 - -#Use fast PK routines. Basically this limits the size of the private key in the -#DH system to 256 bits. The group order remains unchanged so the best -#attacks are still GNFS (for DH upto 2560-bits) -# -#This will only speed up the key generation and encryption routines. It lowers the -#security so its by default not turned on. USE AT YOUR RISK! -#CFLAGS += -DFAST_PK - -#ch1-01-7 -# Chaining modes -CFLAGS += -DCFB -CFLAGS += -DOFB -CFLAGS += -DECB -CFLAGS += -DCBC -CFLAGS += -DCTR -#ch1-01-7 - -#ch1-01-8 -#One-way hashes -CFLAGS += -DSHA512 -CFLAGS += -DSHA384 -CFLAGS += -DSHA256 -CFLAGS += -DTIGER -CFLAGS += -DSHA1 -CFLAGS += -DMD5 -CFLAGS += -DMD4 -CFLAGS += -DMD2 -#ch1-01-8 - -#ch1-01-9 -# prngs -CFLAGS += -DYARROW -CFLAGS += -DSPRNG -CFLAGS += -DRC4 -#ch1-01-9 - -#ch1-01-10 -# PK code -CFLAGS += -DMRSA -CFLAGS += -DMDH -CFLAGS += -DMECC -CFLAGS += -DKR -#ch1-01-10 - -#ch1-01-12 -# Control which built in DH or ECC key paramaters -# are to be allowed -CFLAGS += -DDH768 -CFLAGS += -DDH1024 -CFLAGS += -DDH1280 -CFLAGS += -DDH1536 -CFLAGS += -DDH1792 -CFLAGS += -DDH2048 -CFLAGS += -DDH2560 -CFLAGS += -DDH3072 -CFLAGS += -DDH4096 - -CFLAGS += -DECC160 -CFLAGS += -DECC192 -CFLAGS += -DECC224 -CFLAGS += -DECC256 -CFLAGS += -DECC384 -CFLAGS += -DECC521 - -#ch1-01-12 - -#ch1-01-11 -# base64 -CFLAGS += -DBASE64 - -# include GF math routines? -# (not currently used by anything internally) -#CFLAGS += -DGF - -# include large integer math routines? (required by the PK code) -CFLAGS += -DMPI - -# use the fast exptmod operation (used in dsa/rsa/dh and is_prime) -# This uses slightly more heap than the old code [only during the function call] -# this is also fairly faster than the previous code -CFLAGS += -DMPI_FASTEXPT - -# use a "low" mem variant of the fast exptmod. It is still always -# faster then the old exptmod but its savings drops off after -# 1024 to 2048-bits -#CFLAGS += -DMPI_FASTEXPT_LOWMEM - -# include HMAC support -CFLAGS += -DHMAC -#ch1-01-11 - #Output filenames for various targets. LIBNAME=libtomcrypt.a TEST=test @@ -224,8 +46,11 @@ SMALL=small #LIBPATH-The directory for libtomcrypt to be installed to. #INCPATH-The directory to install the header files for libtomcrypt. +#DATAPATH-The directory to install the pdf docs. +DESTDIR= LIBPATH=/usr/lib INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtomcrypt/pdf #List of objects to compile. OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ @@ -246,10 +71,9 @@ LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz #Header files used by libtomcrypt. -HEADERS=mpi-types.h mpi-config.h mpi.h \ -mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \ +HEADERS=mpi.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_macros.h mycrypt_pk.h mycrypt.h mycrypt_argchk.h mycrypt_custom.h #The default rule for make builds the libtomcrypt library. default:library mycrypt.h mycrypt_cfg.h @@ -286,17 +110,19 @@ small: library $(SMALLOBJECTS) #as root in order to have a high enough permission to write to the correct #directories and to set the owner and group to root. install: library docs - install -g root -o root $(LIBNAME) $(LIBPATH) - install -g root -o root $(HEADERS) $(INCPATH) - mkdir -p /usr/doc/libtomcrypt/pdf - cp crypt.pdf /usr/doc/libtomcrypt/pdf/ + install -d -g root -o root $(DESTDIR)$(LIBPATH) + install -d -g root -o root $(DESTDIR)$(INCPATH) + install -d -g root -o root $(DESTDIR)$(DATAPATH) + install -g root -o root $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g root -o root $(HEADERS) $(DESTDIR)$(INCPATH) + install -g root -o root crypt.pdf $(DESTDIR)$(DATAPATH) #This rule cleans the source tree of all compiled code, not including the pdf #documentation. clean: rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) rm -f $(TEST) $(HASH) $(COMPRESSED) - rm -f *stackdump *.lib *.exe *.obj demos/*.obj *.bat makefile.out mycrypt_custom.h + rm -f *stackdump *.lib *.exe *.obj demos/*.obj *.bat #This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed #from the clean command! This is because most people would like to keep the @@ -312,6 +138,6 @@ docs: crypt.tex #zipup the project (take that!) zipup: clean docs - chdir .. ; rm -rf crypt* libtomcrypt-$(VERSION) ; mkdir libtomcrypt-$(VERSION) ; \ + cd .. ; rm -rf crypt* libtomcrypt-$(VERSION) ; mkdir libtomcrypt-$(VERSION) ; \ cp -R ./libtomcrypt/* ./libtomcrypt-$(VERSION)/ ; tar -c libtomcrypt-$(VERSION)/* > crypt-$(VERSION).tar ; \ - bzip2 -9vv crypt-$(VERSION).tar ; zip -9 -r crypt-$(VERSION).zip libtomcrypt-$(VERSION)/* \ No newline at end of file + bzip2 -9vv crypt-$(VERSION).tar ; zip -9 -r crypt-$(VERSION).zip libtomcrypt-$(VERSION)/* diff --git a/makefile.out b/makefile.out new file mode 100644 index 0000000..e0309fb --- /dev/null +++ b/makefile.out @@ -0,0 +1,24 @@ +#makefile generated with config.pl +# +#Tom St Denis (tomstdenis@yahoo.com, http://tom.iahu.ca) + +CC = gcc +AR = ar +LD = ld +CFLAGS += -Os -Wall -Wsign-compare -W -Wno-unused -Werror -I./ + +default: library + +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 + +rsa.o: rsa_sys.c +dh.o: dh_sys.c +ecc.o: ecc_sys.c + +library: $(OBJECTS) + $(AR) r libtomcrypt.a $(OBJECTS) + ranlib libtomcrypt.a + +clean: + rm -f $(OBJECTS) libtomcrypt.a + diff --git a/makefile.ps2 b/makefile.ps2 deleted file mode 100644 index 3a2024a..0000000 --- a/makefile.ps2 +++ /dev/null @@ -1,311 +0,0 @@ -# MAKEFILE for linux GCC -# -# Tom St Denis -# Modified by Clay Culver -# -# NOTE: This should later be replaced by autoconf/automake scripts, but for -# the time being this is actually pretty clean. The only ugly part is -# handling CFLAGS so that the x86 specific optimizations don't break -# a build. This is easy to remedy though, for those that have problems. - -#Compiler and Linker Names -CC=ee-gcc -LD=ee-ld - -# PlayStation(tm) 2 specifics -TOP = /usr/local/sce/ee -LIBDIR = $(TOP)/lib -INCDIR = $(TOP)/include/ -COMMONDIR = $(TOP)/../common/include/ -LCFILE = $(LIBDIR)/app.cmd -LDFLAGS = -DSONY_PS2 -DSONY_PS2_EE -Wl,-Map,$(@).map -mno-crt0 -L$(LIBDIR) -lm -AS = ee-gcc -ASFLAGS = -DSONY_PS2 -DSONY_PS2_EE -c -xassembler-with-cpp -Wa,-al -EXT = .elf -CFLAGS += -DSONY_PS2 -DSONY_PS2_EE -Wa,-al -Wno-unused -Werror \ - -fno-common -fno-strict-aliasing -I$(INCDIR) -I$(COMMONDIR) - -#Archiver [makes .a files] -AR=ee-ar -ARFLAGS=rs - -#here you can set the malloc/calloc/free functions you want -XMALLOC=malloc -XCALLOC=calloc -XREALLOC=realloc -XFREE=free - -#you can redefine the clock -XCLOCK=TIMER_clock -XCLOCKS_PER_SEC=576000 - -#Compilation flags. Note the += does not write over the user's CFLAGS! -CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ - -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) \ - -DXREALLOC=$(XREALLOC) -DXCLOCK=$(XCLOCK) \ - -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) - -#optimize for SPEED (comment out SIZE line as well) -#CFLAGS += -O3 -fomit-frame-pointer -funroll-loops - -#optimize for SIZE (comment out SPEED line as well) -CFLAGS += -Os - -#Use small code variants of functions when possible? (Slows it down!) -CFLAGS += -DSMALL_CODE - -#no file support, when defined the library will not have any functions that can read/write files -#(comment out to have file support) -CFLAGS += -DNO_FILE - -#These flags control how the library gets built. - -# Clean the stack after sensitive functions. Not always required... -# With this defined most of the ciphers and hashes will clean their stack area -# after usage with a (sometimes) huge penalty in speed. Normally this is not -# required if you simply lock your stack and wipe it when your program is done. -# -#CFLAGS += -DCLEAN_STACK - -# What algorithms to include? comment out and rebuild to remove em -CFLAGS += -DBLOWFISH -CFLAGS += -DRC2 -#CFLAGS += -DRC5 -#CFLAGS += -DRC6 -CFLAGS += -DSERPENT -CFLAGS += -DSAFERP -CFLAGS += -DSAFER -CFLAGS += -DRIJNDAEL -CFLAGS += -DXTEA -CFLAGS += -DTWOFISH -CFLAGS += -DDES -CFLAGS += -DCAST5 -CFLAGS += -DNOEKEON - -#You can also customize the Twofish code. All four combinations -#of the flags are possible but only three of them make sense. -# -#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key -#Both defined : Slow, requires only ~100 bytes of ram per scheduled key -# -#If defined on their own -#_SMALL defined: Very Slow, small code only ~100 bytes of ram -#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger -# faster keysetup though... - -# Small Ram Variant of Twofish. For this you must have TWOFISH defined. This -# variant requires about 4kb less memory but is considerably slower. It is ideal -# when high throughput is less important than conserving memory. By default it is -# not defined which means the larger ram (about 4.2Kb used) variant is built. -# CFLAGS += -DTWOFISH_SMALL - -# Tell Twofish to use precomputed tables. If you want to use the small table -# variant of Twofish you may want to turn this on. Essentially it tells Twofish to use -# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS]. -# This speeds up the cipher somewhat. -# CFLAGS += -DTWOFISH_TABLES - -#Use fast PK routines. Basically this limits the size of the private key in the -#DH system to 256 bits. The group order remains unchanged so the best -#attacks are still GNFS (for DH upto 2560-bits) -# -#This will only speed up the key generation and encryption routines. It lowers the -#security so its by default not turned on. USE AT YOUR RISK! -#CFLAGS += -DFAST_PK - -# Chaining modes -CFLAGS += -DCFB -CFLAGS += -DOFB -CFLAGS += -DECB -CFLAGS += -DCBC -CFLAGS += -DCTR - -#One-way hashes -CFLAGS += -DSHA512 -CFLAGS += -DSHA384 -CFLAGS += -DSHA256 -CFLAGS += -DTIGER -CFLAGS += -DSHA1 -CFLAGS += -DMD5 -CFLAGS += -DMD4 -CFLAGS += -DMD2 - -# base64 -CFLAGS += -DBASE64 - -# prngs -CFLAGS += -DYARROW -CFLAGS += -DSPRNG -CFLAGS += -DRC4 - -# PK code -CFLAGS += -DMRSA -CFLAGS += -DMDH -CFLAGS += -DMECC -CFLAGS += -DKR - -# Control which built in DH or ECC key paramaters -# are to be allowed -CFLAGS += -DDH768 -CFLAGS += -DDH1024 -CFLAGS += -DDH1280 -CFLAGS += -DDH1536 -CFLAGS += -DDH1792 -CFLAGS += -DDH2048 -CFLAGS += -DDH2560 -CFLAGS += -DDH3072 -CFLAGS += -DDH4096 - -CFLAGS += -DECC160 -CFLAGS += -DECC192 -CFLAGS += -DECC224 -CFLAGS += -DECC256 -CFLAGS += -DECC384 -CFLAGS += -DECC521 - -# include GF math routines? (not currently used by anything internally) -#CFLAGS += -DGF - -# include large integer math routines? (required by the PK code) -CFLAGS += -DMPI - -# use the fast exptmod operation (used in dsa/rsa/dh and is_prime) -# This uses slightly more heap than the old code [only during the function call] -# this is also fairly faster than the previous code -CFLAGS += -DMPI_FASTEXPT - -# use a "low" mem variant of the fast exptmod. It is still always -# faster then the old exptmod but its savings drops off after -# 1024-bits -CFLAGS += -DMPI_FASTEXPT_LOWMEM - -# include HMAC support -CFLAGS += -DHMAC - -# Have /dev/random or /dev/urandom? -#CFLAGS += -DDEVRANDOM - -#Output filenames for various targets. -LIBNAME=libtomcrypt.a -TEST=test$(EXT) -HASH=hashsum$(EXT) -CRYPT=encrypt$(EXT) -SMALL=small$(EXT) - -#LIBPATH-The directory for libtomcrypt to be installed to. -#INCPATH-The directory to install the header files for libtomcrypt. -LIBPATH=/usr/lib -INCPATH=/usr/include - -#List of objects to compile. -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 - -# PlayStation(tm) 2 C run-time startup module -PS2CRT0=crt0.o - -TESTOBJECTS=$(PS2CRT0) demos/test.o demos/timer.o -HASHOBJECTS=$(PS2CRT0) demos/hashsum.o -CRYPTOBJECTS=$(PS2CRT0) demos/encrypt.o -SMALLOBJECTS=$(PS2CRT0) demos/small.o - -#Files left over from making the crypt.pdf. -LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind - -#Compressed filenames -COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz - -#Header files used by libtomcrypt. -HEADERS=mpi-types.h mpi-config.h mpi.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 - -#The default rule for make builds the libtomcrypt library. -default:library mycrypt.h mycrypt_cfg.h - -#These are the rules to make certain object files. -rsa.o: rsa.c rsa_sys.c -ecc.o: ecc.c ecc_sys.c -dh.o: dh.c dh_sys.c -aes.o: aes.c aes_tab.c -sha512.o: sha512.c sha384.c - -#This rule makes the libtomcrypt library. -library: $(OBJECTS) - $(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS) - -#This rule makes the test program included with libtomcrypt -test: library $(TESTOBJECTS) - $(CC) -o $(TEST) -T $(LCFILE) $(LDFLAGS) $(TESTOBJECTS) $(LIBNAME) - -#This rule makes the hash program included with libtomcrypt -hashsum: library $(HASHOBJECTS) - $(CC) -o $(HASH) -T $(LCFILE) $(LDFLAGS) $(HASHOBJECTS) $(LIBNAME) - -#makes the crypt program -crypt: library $(CRYPTOBJECTS) - $(CC) -o $(CRYPT) -T $(LCFILE) $(LDFLAGS) $(CRYPTOBJECTS) $(LIBNAME) - -#makes the small program -small: library $(SMALLOBJECTS) - $(CC) -o $(SMALL) -T $(LCFILE) $(LDFLAGS) $(SMALLOBJECTS) $(LIBNAME) - -# makes the PlayStation(tm) 2 CRT 0 module -$(PS2CRT0): $(LIBDIR)/crt0.s - $(AS) $(ASFLAGS) $(TMPFLAGS) -o $@ $< > $*.lst - -#This rule installs the library and the header files. This must be run -#as root in order to have a high enough permission to write to the correct -#directories and to set the owner and group to root. -install: library - install -g root -o root $(LIBNAME) $(LIBPATH) - install -g root -o root $(HEADERS) $(INCPATH) - -#This rule cleans the source tree of all compiled code, not including the pdf -#documentation. -clean: - rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) - rm -f $(TEST) $(HASH) $(COMPRESSED) - rm -f *stackdump *.lib *.exe *.obj demos/*.obj zlib/*.obj - rm -f *.o *.lst demos/*.o demos/*.lst - -#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed -#from the clean command! This is because most people would like to keep the -#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) - latex crypt > /dev/null - makeindex crypt > /dev/null - pdflatex crypt > /dev/null - rm -f $(LEFTOVERS) - -#This used to be the zipup target. I have split it into two seperate targets: -#bz and zip. bz builds a crypt.tar.bz2 package, while zip builds a crypt.zip -#package. I have removed the dos2unix commands, as this is a Linux makefile, -#and these should not be needed. I also made it output the target to the -#current directory instead of the root (/) directory. (Bad Tom!) We are -#almost assured write permission in the current directory, but not in the root -#directory. This means any user can now build a BZ image or a zip. -#NOTE: This removes all pre-built compressed archives during clean. -bz: clean docs - chdir .. ; rm -f crypt.tar.bz2 ; tar -c libtomcrypt/* > crypt.tar ; bzip2 -9v crypt.tar - -zip: clean docs - chdir .. ; rm -f crypt.zip ; zip -9 -r crypt.zip libtomcrypt/* - -#Makes a tar/gz archive of the library. -gz: clean docs - chdir .. ; rm -f crypt.tar.gz ; tar -c libtomcrypt/* > crypt.tar ; gzip -9v crypt.tar - -#makes a tar/SZIP archive [slightly better than bzip2] -szip: clean docs - chdir .. ; rm -f crypt.tar.szp ; tar -c libtomcrypt/* > crypt.tar ; szip -b41o64v255 crypt.tar crypt.tar.szp - -.c.o: - $(CC) $(CFLAGS) $(TMPFLAGS) -c $< -o $*.o > $*.lst diff --git a/makefile.vc b/makefile.vc deleted file mode 100644 index f20dc3c..0000000 --- a/makefile.vc +++ /dev/null @@ -1,274 +0,0 @@ -# MAKEFILE for MSVC 6.0 SP5 -# -# Tom St Denis, tomstdenis@yahoo.com -# -CC=cl -AR=lib - -#here you can set the malloc/calloc/free functions you want -XMALLOC=malloc -XCALLOC=calloc -XREALLOC=realloc -XFREE=free - -#you can redefine the clock -XCLOCK=clock -XCLOCKS_PER_SEC=CLOCKS_PER_SEC - -CFLAGS = /c /Ogisy1 /Gs /I. /W3 /DWIN32 /DXREALLOC=$(XREALLOC) /DXMALLOC=$(XMALLOC) /DXCALLOC=$(XCALLOC) /DXFREE=$(XFREE) /DXCLOCK=$(XCLOCK) /DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) - -#Small code (smaller variants of some block ciphers) -CFLAGS += /DSMALL_CODE - -#These flags control how the library gets built. - -#no file support, when defined the library will not have any functions that can read/write files -#(comment out to have file support) -#CFLAGS += /DNO_FILE - -#Support the UNIX /dev/random or /dev/urandom -#CFLAGS += /DDEVRANDOM - -# Use /dev/urandom first on devices where /dev/random is too slow */ -#CFLAGS += /DTRY_URANDOM_FIRST - -# Clean the stack after sensitive functions. Not always required... -# With this defined most of the ciphers and hashes will clean their stack area -# after usage with a (sometimes) huge penalty in speed. Normally this is not -# required if you simply lock your stack and wipe it when your program is done. -# -#CFLAGS += /DCLEAN_STACK - -# What algorithms to include? comment out and rebuild to remove em -CFLAGS += /DBLOWFISH -CFLAGS += /DRC2 -CFLAGS += /DRC5 -CFLAGS += /DRC6 -CFLAGS += /DSERPENT -CFLAGS += /DSAFERP -CFLAGS += /DSAFER -CFLAGS += /DRIJNDAEL -CFLAGS += /DXTEA -CFLAGS += /DTWOFISH -CFLAGS += /DDES -CFLAGS += /DCAST5 -CFLAGS += /DNOEKEON - -#You can also customize the Twofish code. All four combinations -#of the flags are possible but only three of them make sense. -# -#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key -#Both defined : Slow, requires only ~100 bytes of ram per scheduled key -# -#If defined on their own -#_SMALL defined: Very Slow, small code only ~100 bytes of ram -#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger -# faster keysetup though... - -# Small Ram Variant of Twofish. For this you must have TWOFISH defined. This -# variant requires about 4kb less memory but is considerably slower. It is ideal -# when high throughput is less important than conserving memory. By default it is -# not defined which means the larger ram (about 4.2Kb used) variant is built. -# CFLAGS += /DTWOFISH_SMALL - -# Tell Twofish to use precomputed tables. If you want to use the small table -# variant of Twofish you may want to turn this on. Essentially it tells Twofish to use -# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS]. -# This speeds up the cipher somewhat. -# CFLAGS += /DTWOFISH_TABLES - -#Use fast PK routines. Basically this limits the size of the private key in the -#DH system to 256 bits. The group order remains unchanged so the best -#attacks are still GNFS (for DH upto 2560-bits) -# -#This will only speed up the key generation and encryption routines. It lowers the -#security so its by default not turned on. USE AT YOUR RISK! -#CFLAGS += /DFAST_PK - -# Chaining modes -CFLAGS += /DCFB -CFLAGS += /DOFB -CFLAGS += /DECB -CFLAGS += /DCBC -CFLAGS += /DCTR - -#One-way hashes -CFLAGS += /DSHA512 -CFLAGS += /DSHA384 -CFLAGS += /DSHA256 -CFLAGS += /DTIGER -CFLAGS += /DSHA1 -CFLAGS += /DMD5 -CFLAGS += /DMD4 -CFLAGS += /DMD2 - -# base64 -CFLAGS += /DBASE64 - -# prngs -CFLAGS += /DYARROW -CFLAGS += /DSPRNG -CFLAGS += /DRC4 - -# PK code -CFLAGS += /DMRSA -CFLAGS += /DMDH -CFLAGS += /DMECC -CFLAGS += /DKR - -# Control which built in DH or ECC key paramaters -# are to be allowed -CFLAGS += /DDH768 -CFLAGS += /DDH1024 -CFLAGS += /DDH1280 -CFLAGS += /DDH1536 -CFLAGS += /DDH1792 -CFLAGS += /DDH2048 -CFLAGS += /DDH2560 -CFLAGS += /DDH3072 -CFLAGS += /DDH4096 - -CFLAGS += /DECC160 -CFLAGS += /DECC192 -CFLAGS += /DECC224 -CFLAGS += /DECC256 -CFLAGS += /DECC384 -CFLAGS += /DECC521 - -# include GF math routines? (not currently used by anything internally) -#CFLAGS += /DGF - -# include large integer math routines? (required by the PK code) -CFLAGS += /DMPI - -# use the fast exptmod operation (used in dsa/rsa/dh and is_prime) -# This uses slightly more heap than the old code [only during the function call] -# this is also fairly faster than the previous code -CFLAGS += /DMPI_FASTEXPT - -# use a "low" mem variant of the fast exptmod. It is still always -# faster then the old exptmod but its savings drops off after -# 1024-bits -#CFLAGS += /DMPI_FASTEXPT_LOWMEM - - -# include HMAC support -CFLAGS += /DHMAC - -default: tomcrypt.lib - -keyring.obj: keyring.c - $(CC) $(CFLAGS) keyring.c -ampi.obj: ampi.c - $(CC) $(CFLAGS) ampi.c -mpi.obj: mpi.c - $(CC) $(CFLAGS) mpi.c -blowfish.obj: blowfish.c - $(CC) $(CFLAGS) blowfish.c -crypt.obj: crypt.c - $(CC) $(CFLAGS) crypt.c -sha512.obj: sha512.c sha384.c - $(CC) $(CFLAGS) sha512.c -sha256.obj: sha256.c - $(CC) $(CFLAGS) sha256.c -hash.obj: hash.c - $(CC) $(CFLAGS) hash.c -md5.obj: md5.c - $(CC) $(CFLAGS) md5.c -md4.obj: md4.c - $(CC) $(CFLAGS) md4.c -sha1.obj: sha1.c - $(CC) $(CFLAGS) sha1.c -cfb.obj: cfb.c - $(CC) $(CFLAGS) cfb.c -ofb.obj: ofb.c - $(CC) $(CFLAGS) ofb.c -ecb.obj: ecb.c - $(CC) $(CFLAGS) ecb.c -ctr.obj: ctr.c - $(CC) $(CFLAGS) ctr.c -prime.obj: prime.c - $(CC) $(CFLAGS) prime.c -base64.obj: base64.c - $(CC) $(CFLAGS) base64.c -sprng.obj: sprng.c - $(CC) $(CFLAGS) sprng.c -mem.obj: mem.c - $(CC) $(CFLAGS) mem.c -gf.obj: gf.c - $(CC) $(CFLAGS) gf.c -ecc.obj: ecc.c ecc_sys.c - $(CC) $(CFLAGS) ecc.c -yarrow.obj: yarrow.c - $(CC) $(CFLAGS) yarrow.c -bits.obj: bits.c - $(CC) $(CFLAGS) bits.c -rsa.obj: rsa.c - $(CC) $(CFLAGS) rsa.c -rc6.obj: rc6.c - $(CC) $(CFLAGS) rc6.c -des.obj: des.c - $(CC) $(CFLAGS) des.c -tiger.obj: tiger.c - $(CC) $(CFLAGS) tiger.c -dh.obj: dh.c dh_sys.c - $(CC) $(CFLAGS) dh.c -serpent.obj: serpent.c - $(CC) $(CFLAGS) serpent.c -aes.obj: aes.c aes_tab.c - $(CC) $(CFLAGS) aes.c -rc5.obj: rc5.c - $(CC) $(CFLAGS) rc5.c -rc2.obj: rc2.c - $(CC) $(CFLAGS) rc2.c -cbc.obj: cbc.c - $(CC) $(CFLAGS) cbc.c -safer+.obj: safer+.c - $(CC) $(CFLAGS) safer+.c -safer.obj: safer.c - $(CC) $(CFLAGS) safer.c -safer_tab.obj: safer_tab.c - $(CC) $(CFLAGS) safer_tab.c -xtea.obj: xtea.c - $(CC) $(CFLAGS) xtea.c -twofish.obj: twofish.c - $(CC) $(CFLAGS) twofish.c -packet.obj: packet.c - $(CC) $(CFLAGS) packet.c -pack.obj: pack.c - $(CC) $(CFLAGS) pack.c -hmac.obj: hmac.c - $(CC) $(CFLAGS) hmac.c -strings.obj: strings.c - $(CC) $(CFLAGS) strings.c -md2.obj: md2.c - $(CC) $(CFLAGS) md2.c -cast5.obj: cast5.c - $(CC) $(CFLAGS) cast5.c -noekeon.obj: noekeon.c - $(CC) $(CFLAGS) noekeon.c - -demos/test.obj: demos/test.c - $(CC) $(CFLAGS) demos/test.c - -demos/hashsum.obj: demos/hashsum.c - $(CC) $(CFLAGS) demos/hashsum.c - -tomcrypt.lib: keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj bits.obj hmac.obj \ -yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj sha512.obj xtea.obj \ -aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj noekeon.obj rc2.obj rc6.obj rc5.obj des.obj blowfish.obj crypt.obj ampi.obj \ -strings.obj mpi.obj prime.obj twofish.obj packet.obj - $(AR) /out:tomcrypt.lib keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj hmac.obj \ -bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj \ -strings.obj sha512.obj xtea.obj aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj noekeon.obj rc2.obj rc6.obj rc5.obj des.obj \ -blowfish.obj crypt.obj ampi.obj mpi.obj prime.obj twofish.obj packet.obj - - -test.exe: tomcrypt.lib demos/test.obj - link /OUT:test.exe test.obj tomcrypt.lib advapi32.lib - -hashsum.exe: tomcrypt.lib demos/hashsum.obj - link /OUT:hashsum.exe hashsum.obj tomcrypt.lib advapi32.lib - -clean: - rm -f demos/*.obj *.obj *.exe *.lib diff --git a/mpi-config.h b/mpi-config.h deleted file mode 100644 index 2e415dd..0000000 --- a/mpi-config.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Default configuration for MPI library */ -/* $ID$ */ - -#ifndef MPI_CONFIG_H_ -#define MPI_CONFIG_H_ - -/* - For boolean options, - 0 = no - 1 = yes - - Other options are documented individually. - - */ - -#ifndef MP_IOFUNC -#define MP_IOFUNC 0 /* include mp_print() ? */ -#endif - -#ifndef MP_MODARITH -#define MP_MODARITH 1 /* include modular arithmetic ? */ -#endif - -#ifndef MP_NUMTH -#define MP_NUMTH 1 /* include number theoretic functions? */ -#endif - -#ifndef MP_LOGTAB -#define MP_LOGTAB 1 /* use table of logs instead of log()? */ -#endif - -#ifndef MP_MEMSET -#define MP_MEMSET 1 /* use memset() to zero buffers? */ -#endif - -#ifndef MP_MEMCPY -#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ -#endif - -#ifndef MP_CRYPTO -#define MP_CRYPTO 1 /* erase memory on free? */ -#endif - -#ifndef MP_ARGCHK -/* - 0 = no parameter checks - 1 = runtime checks, continue execution and return an error to caller - 2 = assertions; dump core on parameter errors - */ -#define MP_ARGCHK 1 /* how to check input arguments */ -#endif - -#ifndef MP_DEBUG -#define MP_DEBUG 0 /* print diagnostic output? */ -#endif - -#ifndef MP_DEFPREC -#define MP_DEFPREC 64 /* default precision, in digits */ -#endif - -#ifndef MP_MACRO -#define MP_MACRO 0 /* use macros for frequent calls? */ -#endif - -#ifndef MP_SQUARE -#define MP_SQUARE 1 /* use separate squaring code? */ -#endif - -#ifndef MP_PTAB_SIZE -/* - When building mpprime.c, we build in a table of small prime - values to use for primality testing. The more you include, - the more space they take up. See primes.c for the possible - values (currently 16, 32, 64, 128, 256, and 6542) - */ -#define MP_PTAB_SIZE 128 /* how many built-in primes? */ -#endif - -#ifndef MP_COMPAT_MACROS -#define MP_COMPAT_MACROS 1 /* define compatibility macros? */ -#endif - -#endif /* ifndef MPI_CONFIG_H_ */ - - - - diff --git a/mpi-types.h b/mpi-types.h deleted file mode 100644 index e097188..0000000 --- a/mpi-types.h +++ /dev/null @@ -1,16 +0,0 @@ -/* Type definitions generated by 'types.pl' */ -typedef char mp_sign; -typedef unsigned short mp_digit; /* 2 byte type */ -typedef unsigned int mp_word; /* 4 byte type */ -typedef unsigned int mp_size; -typedef int mp_err; - -#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) -#define MP_DIGIT_MAX USHRT_MAX -#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) -#define MP_WORD_MAX UINT_MAX - -#define MP_DIGIT_SIZE 2 -#define DIGIT_FMT "%04X" -#define RADIX (MP_DIGIT_MAX+1) - diff --git a/mpi.c b/mpi.c index 2162f7b..4d6738b 100644 --- a/mpi.c +++ b/mpi.c @@ -1,4216 +1,5373 @@ - /* - mpi.c +/* File Generated Automatically by gen.pl */ - by Michael J. Fromberger - Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved - - Arbitrary precision integer arithmetic library - - $ID$ +/* 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://libtommath.iahu.ca */ +#include -#include -#include -#include -#include +int KARATSUBA_MUL_CUTOFF = 80, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 80, /* Min. number of digits before Karatsuba squaring is used. */ + MONTGOMERY_EXPT_CUTOFF = 74; /* max. number of digits that montgomery reductions will help for */ -#include "mycrypt.h" +/* End: bncore.c */ -#ifdef MPI - -#if MP_DEBUG -#include - -#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} -#else -#define DIAG(T,V) -#endif - -/* - If MP_LOGTAB is not defined, use the math library to compute the - logarithms on the fly. Otherwise, use the static table below. - Pick which works best for your system. +/* 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://libtommath.iahu.ca */ -#if MP_LOGTAB +#include -/* {{{ s_logv_2[] - log table for 2 in various bases */ - -/* - A table of the logs of 2 for various bases (the 0 and 1 entries of - this table are meaningless and should not be referenced). - - This table is used to compute output lengths for the mp_toradix() - function. Since a number n in radix r takes up about log_r(n) - digits, we estimate the output size by taking the least integer - greater than log_r(n), where: - - log_r(n) = log_2(n) * log_r(2) - - This table, therefore, is a table of log_r(2) for 2 <= r <= 36, - which are the output bases supported. +/* 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 */ -const float s_logv_2[] = { - 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ - 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ - 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ - 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ - 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ - 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ - 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ - 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ - 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ - 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ - 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ - 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ - 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ - 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ - 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ - 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ - 0.166666667 -}; -/* }}} */ -#define LOG_V_2(R) s_logv_2[(R)] - -#else - -#include -#define LOG_V_2(R) (log(2.0)/log(R)) - -#endif - -/* Default precision for newly created mp_int's */ -static unsigned int s_mp_defprec = MP_DEFPREC; - -/* {{{ Digit arithmetic macros */ - -/* - When adding and multiplying digits, the results can be larger than - can be contained in an mp_digit. Thus, an mp_word is used. These - macros mask off the upper and lower digits of the mp_word (the - mp_word may be more than 2 mp_digits wide, but we only concern - ourselves with the low-order 2 mp_digits) - - If your mp_word DOES have more than 2 mp_digits, you need to - uncomment the first line, and comment out the second. - */ - -/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ -#define CARRYOUT(W) ((W)>>DIGIT_BIT) -#define ACCUM(W) ((W)&MP_DIGIT_MAX) - -/* }}} */ - -/* {{{ Comparison constants */ - - -/* }}} */ - -/* {{{ Constant strings */ - -/* Constant strings returned by mp_strerror() */ -static const char *mp_err_string[] = { - "unknown result code", /* say what? */ - "boolean true", /* MP_OKAY, MP_YES */ - "boolean false", /* MP_NO */ - "out of memory", /* MP_MEM */ - "argument out of range", /* MP_RANGE */ - "invalid input parameter", /* MP_BADARG */ - "result is undefined" /* MP_UNDEF */ -}; - -/* Value to digit maps for radix conversion */ - -/* s_dmap_1 - standard digits and letters */ -static const char *s_dmap_1 = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -#if 0 -/* s_dmap_2 - base64 ordering for digits */ -static const char *s_dmap_2 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -#endif - -/* }}} */ - -/* {{{ Static function declarations */ - -/* - If MP_MACRO is false, these will be defined as actual functions; - otherwise, suitable macro definitions will be used. This works - around the fact that ANSI C89 doesn't support an 'inline' keyword - (although I hear C9x will ... about bloody time). At present, the - macro definitions are identical to the function bodies, but they'll - expand in place, instead of generating a function call. - - I chose these particular functions to be made into macros because - some profiling showed they are called a lot on a typical workload, - and yet they are primarily housekeeping. - */ -#if MP_MACRO == 0 - static void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ - static void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ - static void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ - static void s_mp_free(void *ptr); /* general free function */ -#else - - /* Even if these are defined as macros, we need to respect the settings - of the MP_MEMSET and MP_MEMCPY configuration options... - */ - #if MP_MEMSET == 0 - #define s_mp_setz(dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} - #else - #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) - #endif /* MP_MEMSET */ - - #if MP_MEMCPY == 0 - #define s_mp_copy(sp, dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} - #else - #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) - #endif /* MP_MEMCPY */ - - #define s_mp_alloc(nb, ni) XCALLOC(nb, ni) - #define s_mp_free(ptr) {if(ptr) XFREE(ptr);} -#endif /* MP_MACRO */ - -static mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ -static mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ - -static void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ - -static void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ - -static mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ -static void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ -static void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ -static void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ -static mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ -static void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ -static mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ -mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ -static mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ -static mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ -static mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ -static mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); - /* unsigned digit divide */ -static mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); - /* Barrett reduction */ -static mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ -static mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ -static mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ -#if 0 -static void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); - /* multiply buffers in place */ -#endif -#if MP_SQUARE -static mp_err s_mp_sqr(mp_int *a); /* magnitude square */ -#else -#define s_mp_sqr(a) s_mp_mul(a, a) -#endif -static mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ -static mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ -static int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ -static int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ -static int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ -static int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ - -static int s_mp_tovalue(char ch, int r); /* convert ch to value */ -char s_mp_todigit(int val, int r, int low); /* convert val to digit */ -static int s_mp_outlen(int bits, int r); /* output length in bytes */ - -/* }}} */ - -/* {{{ Default precision manipulation */ - -unsigned int mp_get_prec(void) +int +fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) { - return s_mp_defprec; + mp_int x, y, u, v, B, D; + int res, neg; -} /* end mp_get_prec() */ - -void mp_set_prec(unsigned int prec) -{ - if(prec == 0) - s_mp_defprec = MP_DEFPREC; - else - s_mp_defprec = prec; - -} /* end mp_set_prec() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_init(mp) */ - -/* - mp_init(mp) - - Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, - MP_MEM if memory could not be allocated for the structure. - */ - -mp_err mp_init(mp_int *mp) -{ - return mp_init_size(mp, s_mp_defprec); - -} /* end mp_init() */ - -/* }}} */ - -/* {{{ mp_init_array(mp[], count) */ - -mp_err mp_init_array(mp_int mp[], int count) -{ - mp_err res; - int pos; - - ARGCHK(mp !=NULL && count > 0, MP_BADARG); - - for(pos = 0; pos < count; ++pos) { - if((res = mp_init(&mp[pos])) != MP_OKAY) - goto CLEANUP; + if ((res = mp_init (&x)) != MP_OKAY) { + goto __ERR; } - return MP_OKAY; - - CLEANUP: - while(--pos >= 0) - mp_clear(&mp[pos]); - - return res; - -} /* end mp_init_array() */ - -/* }}} */ - -/* {{{ mp_init_size(mp, prec) */ - -/* - mp_init_size(mp, prec) - - Initialize a new zero-valued mp_int with at least the given - precision; returns MP_OKAY if successful, or MP_MEM if memory could - not be allocated for the structure. - */ - -mp_err mp_init_size(mp_int *mp, mp_size prec) -{ - ARGCHK(mp != NULL && prec > 0, MP_BADARG); - - if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) - return MP_MEM; - - SIGN(mp) = MP_ZPOS; - USED(mp) = 1; - ALLOC(mp) = prec; - - return MP_OKAY; - -} /* end mp_init_size() */ - -/* }}} */ - -/* {{{ mp_init_copy(mp, from) */ - -/* - mp_init_copy(mp, from) - - Initialize mp as an exact copy of from. Returns MP_OKAY if - successful, MP_MEM if memory could not be allocated for the new - structure. - */ - -mp_err mp_init_copy(mp_int *mp, mp_int *from) -{ - ARGCHK(mp != NULL && from != NULL, MP_BADARG); - - if(mp == from) - return MP_OKAY; - - if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); - USED(mp) = USED(from); - ALLOC(mp) = USED(from); - SIGN(mp) = SIGN(from); - - return MP_OKAY; - -} /* end mp_init_copy() */ - -/* }}} */ - -/* {{{ mp_copy(from, to) */ - -/* - mp_copy(from, to) - - Copies the mp_int 'from' to the mp_int 'to'. It is presumed that - 'to' has already been initialized (if not, use mp_init_copy() - instead). If 'from' and 'to' are identical, nothing happens. - */ - -mp_err mp_copy(mp_int *from, mp_int *to) -{ - ARGCHK(from != NULL && to != NULL, MP_BADARG); - - if(from == to) - return MP_OKAY; - - { /* copy */ - mp_digit *tmp; - - /* - If the allocated buffer in 'to' already has enough space to hold - all the used digits of 'from', we'll re-use it to avoid hitting - the memory allocater more than necessary; otherwise, we'd have - to grow anyway, so we just allocate a hunk and make the copy as - usual - */ - if(ALLOC(to) >= USED(from)) { - s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); - s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); - - } else { - if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), tmp, USED(from)); - - if(DIGITS(to) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(to), ALLOC(to)); -#endif - s_mp_free(DIGITS(to)); - } - - DIGITS(to) = tmp; - ALLOC(to) = USED(from); - } - - /* Copy the precision and sign from the original */ - USED(to) = USED(from); - SIGN(to) = SIGN(from); - } /* end copy */ - - return MP_OKAY; - -} /* end mp_copy() */ - -/* }}} */ - -/* {{{ mp_exch(mp1, mp2) */ - -/* - mp_exch(mp1, mp2) - - Exchange mp1 and mp2 without allocating any intermediate memory - (well, unless you count the stack space needed for this call and the - locals it creates...). This cannot fail. - */ - -void mp_exch(mp_int *mp1, mp_int *mp2) -{ -#if MP_ARGCHK == 2 - assert(mp1 != NULL && mp2 != NULL); -#else - if(mp1 == NULL || mp2 == NULL) - return; -#endif - - s_mp_exch(mp1, mp2); - -} /* end mp_exch() */ - -/* }}} */ - -/* {{{ mp_clear(mp) */ - -/* - mp_clear(mp) - - Release the storage used by an mp_int, and void its fields so that - if someone calls mp_clear() again for the same int later, we won't - get tollchocked. - */ - -void mp_clear(mp_int *mp) -{ - if(mp == NULL) - return; - - if(DIGITS(mp) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = NULL; + if ((res = mp_init (&y)) != MP_OKAY) { + goto __X; } - USED(mp) = 0; - ALLOC(mp) = 0; - -} /* end mp_clear() */ - -/* }}} */ - -/* {{{ mp_clear_array(mp[], count) */ - -void mp_clear_array(mp_int mp[], int count) -{ -// ARGCHK(mp != NULL && count > 0, MP_BADARG); - - while(--count >= 0) - mp_clear(&mp[count]); - -} /* end mp_clear_array() */ - -/* }}} */ - -/* {{{ mp_zero(mp) */ - -/* - mp_zero(mp) - - Set mp to zero. Does not change the allocated size of the structure, - and therefore cannot fail (except on a bad argument, which we ignore) - */ -void mp_zero(mp_int *mp) -{ - if(mp == NULL) - return; - - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - -} /* end mp_zero() */ - -/* }}} */ - -/* {{{ mp_set(mp, d) */ - -void mp_set(mp_int *mp, mp_digit d) -{ - if(mp == NULL) - return; - - mp_zero(mp); - DIGIT(mp, 0) = d; - -} /* end mp_set() */ - -/* }}} */ - -/* {{{ mp_set_int(mp, z) */ - -mp_err mp_set_int(mp_int *mp, long z) -{ - int ix; - unsigned long v = abs(z); - mp_err res; - - ARGCHK(mp != NULL, MP_BADARG); - - mp_zero(mp); - if(z == 0) - return MP_OKAY; /* shortcut for zero */ - - for(ix = sizeof(long) - 1; ix >= 0; ix--) { - -/* --- bug in MSVC [first release] */ - if (ix == -1) break; -/* --- end of fix */ - - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - res = s_mp_add_d(mp, - (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); - if(res != MP_OKAY) - return res; + if ((res = mp_init (&u)) != MP_OKAY) { + goto __Y; } - if(z < 0) - SIGN(mp) = MP_NEG; - - return MP_OKAY; - -} /* end mp_set_int() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Digit arithmetic */ - -/* {{{ mp_add_d(a, d, b) */ - -/* - mp_add_d(a, d, b) - - Compute the sum b = a + d, for a single digit d. Respects the sign of - its primary addend (single digits are unsigned anyway). - */ - -mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res = MP_OKAY; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_ZPOS) { - res = s_mp_add_d(b, d); - } else if(s_mp_cmp_d(b, d) >= 0) { - res = s_mp_sub_d(b, d); - } else { - SIGN(b) = MP_ZPOS; - - DIGIT(b, 0) = d - DIGIT(b, 0); + if ((res = mp_init (&v)) != MP_OKAY) { + goto __U; } - return res; - -} /* end mp_add_d() */ - -/* }}} */ - -/* {{{ mp_sub_d(a, d, b) */ - -/* - mp_sub_d(a, d, b) - - Compute the difference b = a - d, for a single digit d. Respects the - sign of its subtrahend (single digits are unsigned anyway). - */ - -mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_NEG) { - if((res = s_mp_add_d(b, d)) != MP_OKAY) - return res; - - } else if(s_mp_cmp_d(b, d) >= 0) { - if((res = s_mp_sub_d(b, d)) != MP_OKAY) - return res; - - } else { - mp_neg(b, b); - - DIGIT(b, 0) = d - DIGIT(b, 0); - SIGN(b) = MP_NEG; + if ((res = mp_init (&B)) != MP_OKAY) { + goto __V; } - if(s_mp_cmp_d(b, 0) == 0) - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sub_d() */ - -/* }}} */ - -/* {{{ mp_mul_d(a, d, b) */ - -/* - mp_mul_d(a, d, b) - - Compute the product b = a * d, for a single digit d. Respects the sign - of its multiplicand (single digits are unsigned anyway) - */ - -mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if(d == 0) { - mp_zero(b); - return MP_OKAY; + if ((res = mp_init (&D)) != MP_OKAY) { + goto __B; } - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - res = s_mp_mul_d(b, d); - - return res; - -} /* end mp_mul_d() */ - -/* }}} */ - -/* {{{ mp_mul_2(a, c) */ - -mp_err mp_mul_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - return s_mp_mul_2(c); - -} /* end mp_mul_2() */ - -/* }}} */ - -/* {{{ mp_div_d(a, d, q, r) */ - -/* - mp_div_d(a, d, q, r) - - Compute the quotient q = a / d and remainder r = a mod d, for a - single digit d. Respects the sign of its divisor (single digits are - unsigned anyway). - */ - -mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) -{ - mp_err res; - mp_digit rem; - int pow; - - ARGCHK(a != NULL, MP_BADARG); - - if(d == 0) - return MP_RANGE; - - /* Shortcut for powers of two ... */ - if((pow = s_mp_ispow2d(d)) >= 0) { - mp_digit mask; - - mask = (1 << pow) - 1; - rem = DIGIT(a, 0) & mask; - - if(q) { - mp_copy(a, q); - s_mp_div_2d(q, (mp_digit)pow); - } - - if(r) - *r = rem; - - return MP_OKAY; + /* 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; } - /* - If the quotient is actually going to be returned, we'll try to - avoid hitting the memory allocator by copying the dividend into it - and doing the division there. This can't be any _worse_ than - always copying, and will sometimes be better (since it won't make - another copy) + if ((res = mp_abs (&y, &y)) != MP_OKAY) { + goto __D; + } - If it's not going to be returned, we need to allocate a temporary - to hold the quotient, which will just be discarded. + /* 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(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - res = s_mp_div_d(q, d, &rem); - if(s_mp_cmp_d(q, 0) == MP_EQ) - SIGN(q) = MP_ZPOS; - - } else { - mp_int qp; - - if((res = mp_init_copy(&qp, a)) != MP_OKAY) - return res; - - res = s_mp_div_d(&qp, d, &rem); - if(s_mp_cmp_d(&qp, 0) == 0) - SIGN(&qp) = MP_ZPOS; - - mp_clear(&qp); + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __D; } - if(r) - *r = rem; + /* 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); - return res; -} /* end mp_div_d() */ +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; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __D; + } + } -/* }}} */ -/* {{{ mp_div_2(a, c) */ + /* 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) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __D; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __D; + } + } -/* - mp_div_2(a, c) - - Compute c = a / 2, disregarding the remainder. - */ - -mp_err mp_div_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - s_mp_div_2(c); - - return MP_OKAY; - -} /* end mp_div_2() */ - -/* }}} */ - -/* {{{ mp_expt_d(a, d, b) */ - -mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) -{ - mp_int s, x; - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - DIGIT(&s, 0) = 1; - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; + /* 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; } - d >>= 1; + 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 = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __D; + } } - s_mp_exch(&s, c); + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); + /* 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 mp_expt_d() */ +/* End: bn_fast_mp_invmod.c */ -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Full arithmetic */ - -/* {{{ mp_abs(a, b) */ - -/* - mp_abs(a, b) - - Compute b = |a|. 'a' and 'b' may be identical. +/* 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://libtommath.iahu.ca */ +#include -mp_err mp_abs(mp_int *a, mp_int *b) +/* 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) { - mp_err res; + int ix, res, olduse; + mp_word W[512]; - ARGCHK(a != NULL && b != NULL, MP_BADARG); + /* get old used count */ + olduse = a->used; - if((res = mp_copy(a, b)) != MP_OKAY) - return res; + /* grow a as required */ + if (a->alloc < m->used + 1) { + if ((res = mp_grow (a, m->used + 1)) != MP_OKAY) { + return res; + } + } - SIGN(b) = MP_ZPOS; + { + register mp_word *_W; + register mp_digit *tmpa; - return MP_OKAY; + _W = W; + tmpa = a->dp; -} /* end mp_abs() */ + /* copy the digits of a */ + for (ix = 0; ix < a->used; ix++) { + *_W++ = *tmpa++; + } -/* }}} */ + /* zero the high words */ + for (; ix < m->used * 2 + 1; ix++) { + *_W++ = 0; + } + } -/* {{{ mp_neg(a, b) */ - -/* - mp_neg(a, b) - - Compute b = -a. 'a' and 'b' may be identical. - */ - -mp_err mp_neg(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(s_mp_cmp_d(b, 0) == MP_EQ) - SIGN(b) = MP_ZPOS; - else - SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; - - return MP_OKAY; - -} /* end mp_neg() */ - -/* }}} */ - -/* {{{ mp_add(a, b, c) */ - -/* - mp_add(a, b, c) - - Compute c = a + b. All parameters may be identical. - */ - -mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - int cmp; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ - - /* Commutativity of addition lets us do this in either order, - so we avoid having to use a temporary even if the result - is supposed to replace the output + 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) */ - if(c == b) { - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - } else { - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; + register mp_digit ui; + ui = (((mp_digit) (W[ix] & MP_MASK)) * mp) & MP_MASK; - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ - - /* If the output is going to be clobbered, we will use a temporary - variable; otherwise, we'll do it without touching the memory - allocator at all, if possible + /* 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 */ - if(c == b) { - mp_int tmp; + { + register int iy; + register mp_digit *tmpx; + register mp_word *_W; - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; + /* 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++); } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - } - } else if(cmp == 0) { /* different sign, a == b */ + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } - mp_zero(c); - return MP_OKAY; + /* nox fix rest of carries */ + for (++ix; ix <= m->used * 2 + 1; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + } - } else { /* different sign: a < b */ + { + register mp_digit *tmpa; + register mp_word *_W; - /* See above... */ - if(c == a) { - mp_int tmp; + /* 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; - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != b && (res = mp_copy(b, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; + 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; } } - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; + /* 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 mp_add() */ +/* End: bn_fast_mp_montgomery_reduce.c */ -/* }}} */ - -/* {{{ mp_sub(a, b, c) */ - -/* - mp_sub(a, b, c) - - Compute c = a - b. All parameters may be identical. +/* 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://libtommath.iahu.ca */ +#include -mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) +/* 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) { - mp_err res; - int cmp; + int olduse, res, pa, ix; + mp_word W[512]; - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) != SIGN(b)) { - if(c == a) { - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - SIGN(c) = SIGN(a); + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ - if(c == b) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - } - - } else if(cmp == 0) { /* Same sign, equal magnitude */ - mp_zero(c); - return MP_OKAY; - - } else { /* Same sign, b > a */ - if(c == a) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; - } - - SIGN(c) = !SIGN(b); } - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; + /* clear temp buf (the columns) */ + memset (W, 0, sizeof (mp_word) * digs); - return MP_OKAY; + /* calculate the columns */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { -} /* end mp_sub() */ + /* 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]; -/* {{{ mp_mul(a, b, c) */ + /* alias for the right side */ + tmpy = b->dp; -/* - mp_mul(a, b, c) + /* alias for the columns, each step through the loop adds a new + term to each column + */ + _W = W + ix; - Compute c = a * b. All parameters may be identical. - */ + /* 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); -mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_sign sgn; + for (iy = 0; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; - - if(c == b) { - if((res = s_mp_mul(c, a)) != MP_OKAY) - return res; - - } else { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if((res = s_mp_mul(c, b)) != MP_OKAY) - return res; } - - if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) - SIGN(c) = MP_ZPOS; - else - SIGN(c) = sgn; - + + /* 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 mp_mul() */ +/* End: bn_fast_s_mp_mul_digs.c */ -/* }}} */ - -/* {{{ mp_mul_2d(a, d, c) */ - -/* - mp_mul_2d(a, d, c) - - Compute c = a * 2^d. a may be the same as 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://libtommath.iahu.ca */ +#include -mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) +/* 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) { - mp_err res; + int oldused, newused, res, pa, pb, ix; + mp_word W[512]; - ARGCHK(a != NULL && c != NULL, MP_BADARG); + /* 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; + } + } - if((res = mp_copy(a, c)) != 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; - if(d == 0) - return MP_OKAY; + /* work todo, that is we only calculate digits that are at "digs" or above */ + iy = digs - ix; - return s_mp_mul_2d(c, d); + /* copy of word on the left of A[ix] * B[iy] */ + tmpx = a->dp[ix]; -} /* end mp_mul() */ + /* 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]); -/* {{{ mp_sqr(a, b) */ + /* compute column products for digits above the minimum */ + for (; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + } + } + } -#if MP_SQUARE -mp_err mp_sqr(mp_int *a, mp_int *b) -{ - mp_err res; + /* setup dest */ + oldused = c->used; + c->used = newused; - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if((res = s_mp_sqr(b)) != MP_OKAY) - return res; - - SIGN(b) = MP_ZPOS; + /* 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 mp_sqr() */ -#endif +/* End: bn_fast_s_mp_mul_high_digs.c */ -/* }}} */ - -/* {{{ mp_div(a, b, q, r) */ - -/* - mp_div(a, b, q, r) - - Compute q = a / b and r = a mod b. Input parameters may be re-used - as output parameters. If q or r is NULL, that portion of the - computation will be discarded (although it will still be computed) - - Pay no attention to the hacker behind the curtain. +/* 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://libtommath.iahu.ca */ +#include -mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) +/* 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) { - mp_err res; - mp_int qtmp, rtmp; - int cmp; + int olduse, newused, res, ix, pa; + mp_word W2[512], W[512]; - ARGCHK(a != NULL && b != NULL, MP_BADARG); + /* 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; + } + } - if(mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - - /* If a <= b, we can compute the solution without division, and - avoid any memory allocation + /* 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 */ - if((cmp = s_mp_cmp(a, b)) < 0) { - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - } + memset (W, 0, newused * sizeof (mp_word)); + memset (W2, 0, newused * sizeof (mp_word)); - if(q) - mp_zero(q); - - return MP_OKAY; - - } else if(cmp == 0) { - - /* Set quotient to 1, with appropriate sign */ - if(q) { - int qneg = (SIGN(a) != SIGN(b)); - - mp_set(q, 1); - if(qneg) - SIGN(q) = MP_NEG; - } - - if(r) - mp_zero(r); - - return MP_OKAY; - } - - /* If we get here, it means we actually have to do some division */ - - /* Set up some temporaries... */ - if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) - return res; - if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) - goto CLEANUP; - - /* Compute the signs for the output */ - SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ - if(SIGN(a) == SIGN(b)) - SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ - else - SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ - - if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) - SIGN(&qtmp) = MP_ZPOS; - if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) - SIGN(&rtmp) = MP_ZPOS; - - /* Copy output, if it is needed */ - if(q) - s_mp_exch(&qtmp, q); - - if(r) - s_mp_exch(&rtmp, r); - -CLEANUP: - mp_clear(&rtmp); - mp_clear(&qtmp); - - return res; - -} /* end mp_div() */ - -/* }}} */ - -/* {{{ mp_div_2d(a, d, q, r) */ - -mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) -{ - mp_err res; - - ARGCHK(a != NULL, MP_BADARG); - - if(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - s_mp_div_2d(q, d); - } - - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - - s_mp_mod_2d(r, d); - } - - return MP_OKAY; - -} /* end mp_div_2d() */ - -/* }}} */ - -/* {{{ mp_expt(a, b, c) */ - -/* - mp_expt(a, b, c) - - Compute c = a ** b, that is, raise a to the b power. Uses a - standard iterative square-and-multiply technique. +/* 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 */ -mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int s, x; - mp_err res; - mp_digit d; - int dig, bit; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(b) < 0) - return MP_RANGE; - - if((res = mp_init(&s)) != MP_OKAY) - return res; - - mp_set(&s, 1); - - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - /* Loop over low-order digits in ascending order */ - for(dig = 0; dig < (int)(USED(b) - 1); dig++) { - d = DIGIT(b, dig); - - /* Loop over bits of each non-maximal digit */ - for(bit = 0; bit < (int)DIGIT_BIT; bit++) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - } - - /* Consider now the last digit... */ - d = DIGIT(b, dig); - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - - if(mp_iseven(b)) - SIGN(&s) = SIGN(a); - - res = mp_copy(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_expt() */ - -/* }}} */ - -/* {{{ mp_2expt(a, k) */ - -/* Compute a = 2^k */ - -mp_err mp_2expt(mp_int *a, mp_digit k) -{ - ARGCHK(a != NULL, MP_BADARG); - - return s_mp_2expt(a, k); - -} /* end mp_2expt() */ - -/* }}} */ - -/* {{{ mp_mod(a, m, c) */ - -/* - mp_mod(a, m, c) - - Compute c = a (mod m). Result will always be 0 <= c < m. - */ - -mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - int mag; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if(SIGN(m) == MP_NEG) - return MP_RANGE; - - /* - If |a| > m, we need to divide to get the remainder and take the - absolute value. - - If |a| < m, we don't need to do any division, just copy and adjust - the sign (if a is negative). - - If |a| == m, we can simply set the result to zero. - - This order is intended to minimize the average path length of the - comparison chain on common workloads -- the most frequent cases are - that |a| != m, so we do those first. + /* This computes the inner product. To simplify the inner N^2 loop + * the multiplication by two is done afterwards in the N loop. */ - if((mag = s_mp_cmp(a, m)) > 0) { - if((res = mp_div(a, m, NULL, c)) != MP_OKAY) - return res; - - if(SIGN(c) == MP_NEG) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; + 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; } - } else if(mag < 0) { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; + } - if(mp_cmp_z(a) < 0) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; + /* fix the sign (since we no longer make a fresh temp) */ + b->sign = MP_ZPOS; + 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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 { - mp_zero(c); + /* -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://libtommath.iahu.ca + */ +#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; } - return MP_OKAY; + 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 mp_mod() */ +/* End: bn_mp_addmod.c */ -/* }}} */ - -/* {{{ mp_mod_d(a, d, c) */ - -/* - mp_mod_d(a, d, c) - - Compute c = a (mod d). Result will always be 0 <= c < d +/* 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://libtommath.iahu.ca */ -mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) +#include + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) { - mp_err res; - mp_digit rem; + mp_int t; + int res; - ARGCHK(a != NULL && c != NULL, MP_BADARG); + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + mp_set (&t, b); + res = mp_add (a, &t, c); - if(s_mp_cmp_d(a, d) > 0) { - if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) + 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://libtommath.iahu.ca + */ +#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(SIGN(a) == MP_NEG) - rem = d - DIGIT(a, 0); - else - rem = DIGIT(a, 0); - } - - if(c) - *c = rem; - - return MP_OKAY; - -} /* end mp_mod_d() */ - -/* }}} */ - -/* {{{ mp_sqrt(a, b) */ - -/* - mp_sqrt(a, b) - - Compute the integer square root of a, and store the result in b. - Uses an integer-arithmetic version of Newton's iterative linear - approximation technique to determine this value; the result has the - following two properties: - - b^2 <= a - (b+1)^2 >= a - - It is a range error to pass a negative value. - */ -mp_err mp_sqrt(mp_int *a, mp_int *b) -{ - mp_int x, t; - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - /* Cannot take square root of a negative value */ - if(SIGN(a) == MP_NEG) - return MP_RANGE; - - /* Special cases for zero and one, trivial */ - if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) - return mp_copy(a, b); - - /* Initialize the temporaries we'll use below */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - return res; - - /* Compute an initial guess for the iteration as a itself */ - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - for(;;) { - /* t = (x * x) - a */ - mp_copy(&x, &t); /* can't fail, t is big enough for original x */ - if((res = mp_sqr(&t, &t)) != MP_OKAY || - (res = mp_sub(&t, a, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = t / 2x */ - s_mp_mul_2(&x); - if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) - goto CLEANUP; - s_mp_div_2(&x); - - /* Terminate the loop, if the quotient is zero */ - if(mp_cmp_z(&t) == MP_EQ) - break; - - /* x = x - t */ - if((res = mp_sub(&x, &t, &x)) != MP_OKAY) - goto CLEANUP; - - } - - /* Copy result to output parameter */ - mp_sub_d(&x, 1, &x); - s_mp_exch(&x, b); - - CLEANUP: - mp_clear(&x); - X: - mp_clear(&t); - - return res; - -} /* end mp_sqrt() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Modular arithmetic */ - -#if MP_MODARITH -/* {{{ mp_addmod(a, b, m, c) */ - -/* - mp_addmod(a, b, m, c) - - Compute c = (a + b) mod m - */ - -mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_add(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_submod(a, b, m, c) */ - -/* - mp_submod(a, b, m, c) - - Compute c = (a - b) mod m - */ - -mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sub(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_mulmod(a, b, m, c) */ - -/* - mp_mulmod(a, b, m, c) - - Compute c = (a * b) mod m - */ - -mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_mul(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_sqrmod(a, m, c) */ - -#if MP_SQUARE -mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sqr(a, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} /* end mp_sqrmod() */ -#endif - -/* }}} */ - -/* shrinks the memory required to store a mp_int if possible */ -mp_err mp_shrink(mp_int *a) -{ - if (a->used != a->alloc) { - if ((a->dp = XREALLOC(a->dp, a->used * sizeof(mp_digit))) == NULL) { - return MP_MEM; - } else { - a->alloc = a->used; - return MP_OKAY; - } - } else { - return MP_OKAY; - } -} - -/* {{{ mp_exptmod(a, b, m, c) */ - -#ifdef MPI_FASTEXPT - -/* computes y == g^x mod p */ -mp_err mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) -{ - mp_int *M, tx, mu, res; - int QQQ, QQ, Q, x, *vals, err; - - /* determine the value of Q */ - x = (USED(X) - 1) * DIGIT_BIT; - Q = DIGIT(X, USED(X)-1); - while (Q) { - ++x; - Q >>= 1; - } - if (x <= 8) { Q = 2; } - else if (x <= 64) { Q = 3; } - else if (x <= 256) { Q = 4; } - else if (x <= 950) { Q = 5; } - else if (x <= 2755) { Q = 6; } - else { Q = 7; } - -#ifdef MPI_FASTEXPT_LOWMEM - if (Q > 5) { - Q = 5; - } -#endif - - /* alloc room for table */ - vals = XCALLOC(sizeof(int), USED(X)*((DIGIT_BIT/Q)+((DIGIT_BIT%Q)?1:0))); - if (vals == NULL) { err = MP_MEM; goto _ERR; } - - M = XCALLOC(sizeof(mp_int), 1<= 0) { - for (QQ = 0; QQ < Q; QQ++) { - if ((err = s_mp_sqr(&res)) != MP_OKAY) { goto _TX; } - if ((err = s_mp_reduce(&res, P, &mu)) != MP_OKAY) { goto _TX; } - } - if (vals[x] != 0) { - if ((err = s_mp_mul(&res, &M[vals[x]])) != MP_OKAY) { goto _TX; } - if ((err = s_mp_reduce(&res, P, &mu)) != MP_OKAY) { goto _TX; } - } - } - s_mp_exch(&res, Y); - - /* free ram */ -_TX: - mp_clear(&tx); -_RES: - mp_clear(&res); -_MU: - mp_clear(&mu); -_M: - for (x = 0; x < (1<>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; } + px = a->used; + x = a; } - /* Now do the last digit... */ - d = *db; - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; } - s_mp_exch(&s, c); - - CLEANUP: - mp_clear(&mu); - MU: - mp_clear(&x); - X: - mp_clear(&s); - - return res; - -} /* end mp_exptmod() */ - -#endif - -/* }}} */ - -/* {{{ mp_exptmod_d(a, d, m, c) */ - -mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) -{ - mp_int s, x; - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - mp_set(&s, 1); - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY || - (res = mp_mod(&s, m, &s)) != MP_OKAY) - goto CLEANUP; - } - - d /= 2; - - if((res = s_mp_sqr(&x)) != MP_OKAY || - (res = mp_mod(&x, m, &x)) != MP_OKAY) - goto CLEANUP; + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; } - s_mp_exch(&s, c); + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); +/* End: bn_mp_and.c */ - return res; - -} /* end mp_exptmod_d() */ - -/* }}} */ -#endif /* if MP_MODARITH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Comparison functions */ - -/* {{{ mp_cmp_z(a) */ - -/* - mp_cmp_z(a) - - Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. +/* 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://libtommath.iahu.ca */ +#include -int mp_cmp_z(mp_int *a) +/* 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) { - if(SIGN(a) == MP_NEG) + 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://libtommath.iahu.ca + */ +#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 */ +/* 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://libtommath.iahu.ca + */ +#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(USED(a) == 1 && DIGIT(a, 0) == 0) + } 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://libtommath.iahu.ca + */ +#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; - else - return MP_GT; + } +} -} /* end mp_cmp_z() */ +/* End: bn_mp_cmp_d.c */ -/* }}} */ - -/* {{{ mp_cmp_d(a, d) */ - -/* - mp_cmp_d(a, d) - - Compare a <=> d. Returns <0 if a0 if a>d +/* 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://libtommath.iahu.ca */ +#include -int mp_cmp_d(mp_int *a, mp_digit d) +/* compare maginitude of two ints (unsigned) */ +int +mp_cmp_mag (mp_int * a, mp_int * b) { - ARGCHK(a != NULL, MP_EQ); + int n; - if(SIGN(a) == MP_NEG) - return MP_LT; - - return s_mp_cmp_d(a, d); - -} /* end mp_cmp_d() */ - -/* }}} */ - -/* {{{ mp_cmp(a, b) */ - -int mp_cmp(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - if(SIGN(a) == SIGN(b)) { - int mag; - - if((mag = s_mp_cmp(a, b)) == MP_EQ) - return MP_EQ; - - if(SIGN(a) == MP_ZPOS) - return mag; - else - return -mag; - - } else if(SIGN(a) == MP_ZPOS) { + /* compare based on # of non-zero digits */ + if (a->used > b->used) { return MP_GT; - } else { + } else if (a->used < b->used) { return MP_LT; } -} /* end mp_cmp() */ - -/* }}} */ - -/* {{{ mp_cmp_mag(a, b) */ - -/* - mp_cmp_mag(a, b) - - Compares |a| <=> |b|, and returns an appropriate comparison result - */ - -int mp_cmp_mag(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - return s_mp_cmp(a, b); - -} /* end mp_cmp_mag() */ - -/* }}} */ - -/* {{{ mp_cmp_int(a, z) */ - -/* - This just converts z to an mp_int, and uses the existing comparison - routines. This is sort of inefficient, but it's not clear to me how - frequently this wil get used anyway. For small positive constants, - you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). - */ -int mp_cmp_int(mp_int *a, long z) -{ - mp_int tmp; - int out; - - ARGCHK(a != NULL, MP_EQ); - - mp_init(&tmp); mp_set_int(&tmp, z); - out = mp_cmp(a, &tmp); - mp_clear(&tmp); - - return out; - -} /* end mp_cmp_int() */ - -/* }}} */ - -/* {{{ mp_isodd(a) */ - -/* - mp_isodd(a) - - Returns a true (non-zero) value if a is odd, false (zero) otherwise. - */ -int mp_isodd(mp_int *a) -{ - ARGCHK(a != NULL, 0); - - return (DIGIT(a, 0) & 1); - -} /* end mp_isodd() */ - -/* }}} */ - -/* {{{ mp_iseven(a) */ - -int mp_iseven(mp_int *a) -{ - return !mp_isodd(a); - -} /* end mp_iseven() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Number theoretic functions */ - -#if MP_NUMTH -/* {{{ mp_gcd(a, b, c) */ - -/* - Like the old mp_gcd() function, except computes the GCD using the - binary algorithm due to Josef Stein in 1961 (via Knuth). - */ -mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_int u, v, t; - mp_size k = 0; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - if(mp_cmp_z(a) == MP_EQ) { - return mp_copy(b, c); - } else if(mp_cmp_z(b) == MP_EQ) { - return mp_copy(a, c); - } - - if((res = mp_init(&t)) != MP_OKAY) - return res; - if((res = mp_init_copy(&u, a)) != MP_OKAY) - goto U; - if((res = mp_init_copy(&v, b)) != MP_OKAY) - goto V; - - SIGN(&u) = MP_ZPOS; - SIGN(&v) = MP_ZPOS; - - /* Divide out common factors of 2 until at least 1 of a, b is even */ - while(mp_iseven(&u) && mp_iseven(&v)) { - s_mp_div_2(&u); - s_mp_div_2(&v); - ++k; - } - - /* Initialize t */ - if(mp_isodd(&u)) { - if((res = mp_copy(&v, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = -v */ - if(SIGN(&v) == MP_ZPOS) - SIGN(&t) = MP_NEG; - else - SIGN(&t) = MP_ZPOS; - - } else { - if((res = mp_copy(&u, &t)) != MP_OKAY) - goto CLEANUP; - - } - - for(;;) { - while(mp_iseven(&t)) { - s_mp_div_2(&t); - } - - if(mp_cmp_z(&t) == MP_GT) { - if((res = mp_copy(&t, &u)) != MP_OKAY) - goto CLEANUP; - - } else { - if((res = mp_copy(&t, &v)) != MP_OKAY) - goto CLEANUP; - - /* v = -t */ - if(SIGN(&t) == MP_ZPOS) - SIGN(&v) = MP_NEG; - else - SIGN(&v) = MP_ZPOS; - } - - if((res = mp_sub(&u, &v, &t)) != MP_OKAY) - goto CLEANUP; - - if(s_mp_cmp_d(&t, 0) == MP_EQ) - break; - } - - s_mp_2expt(&v, (mp_digit)k); /* v = 2^k */ - res = mp_mul(&u, &v, c); /* c = u * v */ - - CLEANUP: - mp_clear(&v); - V: - mp_clear(&u); - U: - mp_clear(&t); - - return res; - -} /* end mp_bgcd() */ - -/* }}} */ - -/* {{{ mp_lcm(a, b, c) */ - -/* We compute the least common multiple using the rule: - - ab = [a, b](a, b) - - ... by computing the product, and dividing out the gcd. - */ - -mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int gcd, prod; - mp_err res; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - /* Set up temporaries */ - if((res = mp_init(&gcd)) != MP_OKAY) - return res; - if((res = mp_init(&prod)) != MP_OKAY) - goto GCD; - - if((res = mp_mul(a, b, &prod)) != MP_OKAY) - goto CLEANUP; - if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) - goto CLEANUP; - - res = mp_div(&prod, &gcd, c, NULL); - - CLEANUP: - mp_clear(&prod); - GCD: - mp_clear(&gcd); - - return res; - -} /* end mp_lcm() */ - -/* }}} */ - -/* {{{ mp_xgcd(a, b, g, x, y) */ - -/* - mp_xgcd(a, b, g, x, y) - - Compute g = (a, b) and values x and y satisfying Bezout's identity - (that is, ax + by = g). This uses the extended binary GCD algorithm - based on the Stein algorithm used for mp_gcd() - */ - -mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) -{ - mp_int gx, xc, yc, u, v, A, B, C, D; - mp_int *clean[9]; - mp_err res; - int last = -1; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Initialize all these variables we need */ - if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; - clean[++last] = &u; - if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; - clean[++last] = &v; - if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; - clean[++last] = &gx; - if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; - clean[++last] = &A; - if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; - clean[++last] = &B; - if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; - clean[++last] = &C; - if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; - clean[++last] = &D; - if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; - clean[++last] = &xc; - mp_abs(&xc, &xc); - if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; - clean[++last] = &yc; - mp_abs(&yc, &yc); - - mp_set(&gx, 1); - - /* Divide by two until at least one of them is even */ - while(mp_iseven(&xc) && mp_iseven(&yc)) { - s_mp_div_2(&xc); - s_mp_div_2(&yc); - if((res = s_mp_mul_2(&gx)) != MP_OKAY) - goto CLEANUP; - } - - mp_copy(&xc, &u); - mp_copy(&yc, &v); - mp_set(&A, 1); mp_set(&D, 1); - - /* Loop through binary GCD algorithm */ - for(;;) { - while(mp_iseven(&u)) { - s_mp_div_2(&u); - - if(mp_iseven(&A) && mp_iseven(&B)) { - s_mp_div_2(&A); s_mp_div_2(&B); - } else { - if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&A); - if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&B); - } - } - - while(mp_iseven(&v)) { - s_mp_div_2(&v); - - if(mp_iseven(&C) && mp_iseven(&D)) { - s_mp_div_2(&C); s_mp_div_2(&D); - } else { - if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&C); - if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&D); - } - } - - if(mp_cmp(&u, &v) >= 0) { - if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; - - } else { - if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; - - } - - /* If we're done, copy results to output */ - if(mp_cmp_z(&u) == 0) { - if(x) - if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; - - if(y) - if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; - - if(g) - if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; - - break; + /* 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; +} - CLEANUP: - while(last >= 0) - mp_clear(clean[last--]); +/* End: bn_mp_cmp_mag.c */ - return res; - -} /* end mp_xgcd() */ - -/* }}} */ - -/* {{{ mp_invmod(a, m, c) */ - -/* - mp_invmod(a, m, c) - - Compute c = a^-1 (mod m), if there is an inverse for a (mod m). - This is equivalent to the question of whether (a, m) = 1. If not, - MP_UNDEF is returned, and there is no inverse. +/* 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://libtommath.iahu.ca */ +#include -mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) { - mp_int g, x; - mp_err res; + int res, n; - ARGCHK(a && m && c, MP_BADARG); - - if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) - return MP_RANGE; - - if((res = mp_init(&g)) != MP_OKAY) - return res; - if((res = mp_init(&x)) != MP_OKAY) - goto X; - - if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) - goto CLEANUP; - - if(mp_cmp_d(&g, 1) != MP_EQ) { - res = MP_UNDEF; - goto CLEANUP; - } - - res = mp_mod(&x, m, c); - SIGN(c) = SIGN(a); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&g); - - return res; - -} /* end mp_invmod() */ - -/* }}} */ -#endif /* if MP_NUMTH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_print(mp, ofp) */ - -#if MP_IOFUNC -/* - mp_print(mp, ofp) - - Print a textual representation of the given mp_int on the output - stream 'ofp'. Output is generated using the internal radix. - */ - -void mp_print(mp_int *mp, FILE *ofp) -{ - int ix; - - if(mp == NULL || ofp == NULL) - return; - - fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); - - for(ix = USED(mp) - 1; ix >= 0; ix--) { - fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); - } - -} /* end mp_print() */ - -#endif /* if MP_IOFUNC */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ More I/O Functions */ - -/* {{{ mp_read_signed_bin(mp, str, len) */ - -/* - mp_read_signed_bin(mp, str, len) - - Read in a raw value (base 256) into the given mp_int - */ - -mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) -{ - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { - /* Get sign from first byte */ - if(str[0]) - SIGN(mp) = MP_NEG; - else - SIGN(mp) = MP_ZPOS; - } - - return res; - -} /* end mp_read_signed_bin() */ - -/* }}} */ - -/* {{{ mp_signed_bin_size(mp) */ - -int mp_signed_bin_size(mp_int *mp) -{ - ARGCHK(mp != NULL, 0); - - return mp_unsigned_bin_size(mp) + 1; - -} /* end mp_signed_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_signed_bin(mp, str) */ - -mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) -{ - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ - str[0] = (char)SIGN(mp); - - return mp_to_unsigned_bin(mp, str + 1); - -} /* end mp_to_signed_bin() */ - -/* }}} */ - -/* {{{ mp_read_unsigned_bin(mp, str, len) */ - -/* - mp_read_unsigned_bin(mp, str, len) - - Read in an unsigned value (base 256) into the given mp_int - */ - -mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) -{ - int ix; - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - mp_zero(mp); - - for(ix = 0; ix < len; ix++) { - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) - return res; - } - - return MP_OKAY; - -} /* end mp_read_unsigned_bin() */ - -/* }}} */ - -/* {{{ mp_unsigned_bin_size(mp) */ - -int mp_unsigned_bin_size(mp_int *mp) -{ - mp_digit topdig; - int count; - - ARGCHK(mp != NULL, 0); - - /* Special case for the value zero */ - if(USED(mp) == 1 && DIGIT(mp, 0) == 0) - return 1; - - count = (USED(mp) - 1) * sizeof(mp_digit); - topdig = DIGIT(mp, USED(mp) - 1); - - while(topdig != 0) { - ++count; - topdig >>= CHAR_BIT; - } - - return count; - -} /* end mp_unsigned_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_unsigned_bin(mp, str) */ - -mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) -{ - mp_digit *dp, *end, d; - unsigned char *spos; - - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - dp = DIGITS(mp); - end = dp + USED(mp) - 1; - spos = str; - - /* Special case for zero, quick test */ - if(dp == end && *dp == 0) { - *str = '\0'; + /* if dst == src do nothing */ + if (a == b || a->dp == b->dp) { return MP_OKAY; } - /* Generate digits in reverse order */ - while(dp < end) { - int ix; + /* grow dest */ + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } - d = *dp; - for(ix = 0; ix < (int)sizeof(mp_digit); ++ix) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; + /* zero b and copy the parameters over */ + b->used = a->used; + b->sign = a->sign; + + { + register mp_digit *tmpa, *tmpb; + + tmpa = a->dp; + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; } - ++dp; + /* clear high digits */ + for (; n < b->alloc; n++) { + *tmpb++ = 0; + } } - - /* Now handle last digit specially, high order zeroes are not written */ - d = *end; - while(d != 0) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; - } - - /* Reverse everything to get digits in the correct order */ - while(--spos > str) { - unsigned char t = *str; - *str = *spos; - *spos = t; - - ++str; - } - return MP_OKAY; +} -} /* end mp_to_unsigned_bin() */ +/* End: bn_mp_copy.c */ -/* }}} */ - -/* {{{ mp_count_bits(mp) */ - -int mp_count_bits(mp_int *mp) -{ - int len; - mp_digit d; - - ARGCHK(mp != NULL, MP_BADARG); - - len = DIGIT_BIT * (USED(mp) - 1); - d = DIGIT(mp, USED(mp) - 1); - - while(d != 0) { - ++len; - d >>= 1; - } - - return len; - -} /* end mp_count_bits() */ - -/* }}} */ - -/* {{{ mp_read_radix(mp, str, radix) */ - -/* - mp_read_radix(mp, str, radix) - - Read an integer from the given string, and set mp to the resulting - value. The input is presumed to be in base 10. Leading non-digit - characters are ignored, and the function reads until a non-digit - character or the end of the string. +/* 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://libtommath.iahu.ca */ +#include -mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) { - int ix = 0, val = 0; - mp_err res; - mp_sign sig = MP_ZPOS; + int r; + mp_digit q; - ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, - MP_BADARG); - - mp_zero(mp); - - /* Skip leading non-digit characters until a digit or '-' or '+' */ - while(str[ix] && - (s_mp_tovalue(str[ix], radix) < 0) && - str[ix] != '-' && - str[ix] != '+') { - ++ix; + if (a->used == 0) { + return 0; } - if(str[ix] == '-') { - sig = MP_NEG; - ++ix; - } else if(str[ix] == '+') { - sig = MP_ZPOS; /* this is the default anyway... */ - ++ix; + r = (a->used - 1) * DIGIT_BIT; + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); } + return r; +} - while((val = s_mp_tovalue(str[ix], radix)) >= 0) { - if((res = s_mp_mul_d(mp, (mp_digit)radix)) != MP_OKAY) - return res; - if((res = s_mp_add_d(mp, (mp_digit)val)) != MP_OKAY) - return res; - ++ix; - } +/* End: bn_mp_count_bits.c */ - if(s_mp_cmp_d(mp, 0) == MP_EQ) - SIGN(mp) = MP_ZPOS; - else - SIGN(mp) = sig; - - return MP_OKAY; - -} /* end mp_read_radix() */ - -/* }}} */ - -/* {{{ mp_radix_size(mp, radix) */ - -int mp_radix_size(mp_int *mp, int radix) -{ - int len; - ARGCHK(mp != NULL, 0); - - len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ - - if(mp_cmp_z(mp) < 0) - ++len; /* for sign */ - - return len; - -} /* end mp_radix_size() */ - -/* }}} */ - -/* {{{ mp_value_radix_size(num, qty, radix) */ - -/* num = number of digits - qty = number of bits per digit - radix = target base - - Return the number of digits in the specified radix that would be - needed to express 'num' digits of 'qty' bits each. +/* 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://libtommath.iahu.ca */ -int mp_value_radix_size(int num, int qty, int radix) +#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) { - ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; - return s_mp_outlen(num * qty, radix); -} /* end mp_value_radix_size() */ + /* 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; + } -/* {{{ mp_toradix(mp, str, radix) */ + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; -mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) -{ - int ix, pos = 0; + if ((res = mp_init (&t1)) != MP_OKAY) { + goto __Q; + } - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } - if(mp_cmp_z(mp) == MP_EQ) { - str[0] = '0'; - str[1] = '\0'; - } else { - mp_err res; - mp_int tmp; - mp_sign sgn; - mp_digit rem, rdx = (mp_digit)radix; - char ch; + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto __T2; + } - if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) - return res; + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto __X; + } - /* Save sign for later, and take absolute value */ - sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; - /* Generate output digits in reverse order */ - while(mp_cmp_z(&tmp) != 0) { - if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { - mp_clear(&tmp); - return res; + /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ + norm = 0; + while ((y.dp[y.used - 1] & (((mp_digit) 1) << (DIGIT_BIT - 1))) == + ((mp_digit) 0)) { + ++norm; + if ((res = mp_mul_2 (&x, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2 (&y, &y)) != MP_OKAY) { + goto __Y; + } + } + + /* 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.alloc) + 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; } - /* Generate digits, use capital letters */ - ch = s_mp_todigit(rem, radix, 0); + /* 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); - str[pos++] = ch; + /* 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; } - /* Add - sign if original value was negative */ - if(sgn == MP_NEG) - str[pos++] = '-'; - - /* Add trailing NUL to end the string */ - str[pos--] = '\0'; - - /* Reverse the digits and sign indicator */ - ix = 0; - while(ix < pos) { - char tmp = str[ix]; - - str[ix] = str[pos]; - str[pos] = tmp; - ++ix; - --pos; + 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; } - - mp_clear(&tmp); } - return MP_OKAY; + /* 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; + } -} /* end mp_toradix() */ + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_clamp (&x); + mp_exch (&x, d); + } -/* }}} */ + res = MP_OKAY; -/* {{{ mp_char2value(ch, r) */ +__Y:mp_clear (&y); +__X:mp_clear (&x); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); +__Q:mp_clear (&q); + return res; +} -int mp_char2value(char ch, int r) -{ - return s_mp_tovalue(ch, r); +/* End: bn_mp_div.c */ -} /* end mp_tovalue() */ - -/* }}} */ - -/* }}} */ - -/* {{{ mp_strerror(ec) */ - -/* - mp_strerror(ec) - - Return a string describing the meaning of error code 'ec'. The - string returned is allocated in static memory, so the caller should - not attempt to modify or free the memory associated with this - string. +/* 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://libtommath.iahu.ca */ -const char *mp_strerror(mp_err ec) +#include + +/* b = a/2 */ +int +mp_div_2 (mp_int * a, mp_int * b) { - int aec = (ec < 0) ? -ec : ec; + int x, res, oldused; - /* Code values are negative, so the senses of these comparisons - are accurate */ - if(ec < MP_LAST_CODE || ec > MP_OKAY) { - return mp_err_string[0]; /* unknown error code */ - } else { - return mp_err_string[aec + 1]; - } - -} /* end mp_strerror() */ - -/* }}} */ - -/*========================================================================*/ -/*------------------------------------------------------------------------*/ -/* Static function definitions (internal use only) */ - -/* {{{ Memory management */ - -/* {{{ s_mp_grow(mp, min) */ - -/* Make sure there are at least 'min' digits allocated to mp */ -static mp_err s_mp_grow(mp_int *mp, mp_size min) -{ - if(min > ALLOC(mp)) { - mp_digit *tmp; - - /* Set min to next nearest default precision block size */ - min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; - - if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(mp), tmp, USED(mp)); - -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = tmp; - ALLOC(mp) = min; - } - - return MP_OKAY; - -} /* end s_mp_grow() */ - -/* }}} */ - -/* {{{ s_mp_pad(mp, min) */ - -/* Make sure the used size of mp is at least 'min', growing if needed */ -static mp_err s_mp_pad(mp_int *mp, mp_size min) -{ - if(min > USED(mp)) { - mp_err res; - - /* Make sure there is room to increase precision */ - if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { return res; - - /* Increase precision; should already be 0-filled */ - USED(mp) = min; + } } + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + tmpa = a->dp + b->used - 1; + tmpb = b->dp + b->used - 1; + r = 0; + for (x = b->used - 1; x >= 0; x--) { + rr = *tmpa & 1; + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + r = rr; + } + + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + mp_clamp (b); return MP_OKAY; +} -} /* end s_mp_pad() */ +/* 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://libtommath.iahu.ca + */ +#include -/* {{{ s_mp_setz(dp, count) */ - -#if MP_MACRO == 0 -/* Set 'count' digits pointed to by dp to be zeroes */ -static void s_mp_setz(mp_digit *dp, mp_size count) +/* 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) { -#if MP_MEMSET == 0 - int ix; + mp_digit D, r, rr; + int x, res; + mp_int t; - for(ix = 0; ix < count; ix++) - dp[ix] = 0; -#else - memset(dp, 0, count * sizeof(mp_digit)); -#endif -} /* end s_mp_setz() */ -#endif + /* 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; + } -/* {{{ s_mp_copy(sp, dp, count) */ + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } -#if MP_MACRO == 0 -/* Copy 'count' digits from sp to dp */ -static void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + mp_rshd (c, b / DIGIT_BIT); + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = c->dp[x] & ((mp_digit) ((1U << D) - 1U)); + + /* shift the current word and mix in the carry bits from the previous word */ + c->dp[x] = (c->dp[x] >> D) | (r << (DIGIT_BIT - D)); + + /* 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://libtommath.iahu.ca + */ +#include + +/* single digit division */ +int +mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) { -#if MP_MEMCPY == 0 - int ix; + mp_int t, t2; + int res; - for(ix = 0; ix < count; ix++) - dp[ix] = sp[ix]; -#else - memcpy(dp, sp, count * sizeof(mp_digit)); -#endif -} /* end s_mp_copy() */ -#endif + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } -/* }}} */ + if ((res = mp_init (&t2)) != MP_OKAY) { + mp_clear (&t); + return res; + } -/* {{{ s_mp_alloc(nb, ni) */ + mp_set (&t, b); + res = mp_div (a, &t, c, &t2); -#if MP_MACRO == 0 -/* Allocate ni records of nb bytes each, and return a pointer to that */ -static void *s_mp_alloc(size_t nb, size_t ni) + if (d != NULL) { + *d = t2.dp[0]; + } + + mp_clear (&t); + mp_clear (&t2); + return res; +} + +/* End: bn_mp_div_d.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://libtommath.iahu.ca + */ +#include + +void +mp_exch (mp_int * a, mp_int * b) { - return XCALLOC(nb, ni); + mp_int t; -} /* end s_mp_alloc() */ -#endif - -/* }}} */ - -/* {{{ s_mp_free(ptr) */ - -#if MP_MACRO == 0 -/* Free the memory pointed to by ptr */ -static void s_mp_free(void *ptr) -{ - if(ptr) - XFREE(ptr); - -} /* end s_mp_free() */ -#endif - -/* }}} */ - -/* {{{ s_mp_clamp(mp) */ - -/* Remove leading zeroes from the given value */ -static void s_mp_clamp(mp_int *mp) -{ - mp_size du = USED(mp); - mp_digit *zp = DIGITS(mp) + du - 1; - - while(du > 1 && !*zp--) - --du; - - USED(mp) = du; - -} /* end s_mp_clamp() */ - - -/* }}} */ - -/* {{{ s_mp_exch(a, b) */ - -/* Exchange the data for a and b; (b, a) = (a, b) */ -static void s_mp_exch(mp_int *a, mp_int *b) -{ - mp_int tmp; - - tmp = *a; + t = *a; *a = *b; - *b = tmp; + *b = t; +} -} /* end s_mp_exch() */ +/* End: bn_mp_exch.c */ -/* }}} */ - -/* }}} */ - -/* {{{ Arithmetic helpers */ - -/* {{{ s_mp_lshd(mp, p) */ - -/* - Shift mp leftward by p digits, growing if needed, and zero-filling - the in-shifted digits at the right end. This is a convenient - alternative to multiplication by powers of the radix - */ - -static mp_err s_mp_lshd(mp_int *mp, mp_size p) -{ - mp_err res; - mp_size pos; - mp_digit *dp; - int ix; - - if(p == 0) - return MP_OKAY; - - if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) - return res; - - pos = USED(mp) - 1; - dp = DIGITS(mp); - - /* Shift all the significant figures over as needed */ - for(ix = pos - p; ix >= 0; ix--) - dp[ix + p] = dp[ix]; - - /* Fill the bottom digits with zeroes */ - for(ix = 0; ix < (int)p; ix++) - dp[ix] = 0; - - return MP_OKAY; - -} /* end s_mp_lshd() */ - -/* }}} */ - -/* {{{ s_mp_rshd(mp, p) */ - -/* - Shift mp rightward by p digits. Maintains the invariant that - digits above the precision are all zero. Digits shifted off the - end are lost. Cannot fail. +/* 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://libtommath.iahu.ca */ +#include -static void s_mp_rshd(mp_int *mp, mp_size p) +int +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) { - mp_size ix; - mp_digit *dp; + mp_int M[256], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - if(p == 0) - return; - /* Shortcut when all digits are to be shifted off */ - if(p >= USED(mp)) { - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - return; + /* if the modulus is odd use the fast method */ + if (mp_isodd (P) == 1 && P->used > 4 && P->used < MONTGOMERY_EXPT_CUTOFF) { + err = mp_exptmod_fast (G, X, P, Y); + return err; } - /* Shift all the significant figures over as needed */ - dp = DIGITS(mp); - for(ix = p; ix < USED(mp); ix++) - dp[ix - p] = dp[ix]; - - - /* Fill the top digits with zeroes */ - - ix -= p; - while(ix < USED(mp)) - dp[ix++] = 0; - - /* Strip off any leading zeroes */ - s_mp_clamp(mp); - -} /* end s_mp_rshd() */ - -/* }}} */ - -/* {{{ s_mp_div_2(mp) */ - -/* Divide by two -- take advantage of radix properties to do it fast */ -static void s_mp_div_2(mp_int *mp) -{ - s_mp_div_2d(mp, 1); - -} /* end s_mp_div_2() */ - -/* }}} */ - -/* {{{ s_mp_mul_2(mp) */ - -static mp_err s_mp_mul_2(mp_int *mp) -{ - int ix; - mp_digit kin = 0, kout, *dp = DIGITS(mp); - mp_err res; - - /* Shift digits leftward by 1 bit */ - for(ix = 0; ix < (int)USED(mp); ix++) { - kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; - dp[ix] = (dp[ix] << 1) | kin; - - kin = kout; + /* 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; } - /* Deal with rollover from last digit */ - if(kin) { - if(ix >= (int)ALLOC(mp)) { - if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) + /* 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 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://libtommath.iahu.ca + */ +#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 reduction + */ +int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[256], res; + mp_digit buf, mp; + 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 (&M[x])) != MP_OKAY) { + for (y = 0; y < x; y++) { + mp_clear (&M[y]); + } + return err; + } + } + + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto __M; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __RES; + } + + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != 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 ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (&M[1], &res, 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 = + mp_montgomery_reduce (&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 = mp_montgomery_reduce (&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 = mp_montgomery_reduce (&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 multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_montgomery_reduce (&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 = mp_montgomery_reduce (&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 = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + } + } + + /* 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://libtommath.iahu.ca + */ +#include + +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++) { + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + if ((b & (mp_digit) (1 << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); return res; - dp = DIGITS(mp); + } } - dp[ix] = kin; - USED(mp) += 1; + b <<= 1; } + mp_clear (&g); return MP_OKAY; +} -} /* end s_mp_mul_2() */ +/* End: bn_mp_expt_d.c */ -/* }}} */ - -/* {{{ s_mp_mod_2d(mp, d) */ - -/* - Remainder the integer by 2^d, where d is a number of bits. This - amounts to a bitwise AND of the value, and does not require the full - division code +/* 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://libtommath.iahu.ca */ -static void s_mp_mod_2d(mp_int *mp, mp_digit d) -{ - unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); - unsigned int ix; - mp_digit dmask, *dp = DIGITS(mp); +#include - if(ndig >= USED(mp)) - return; - - /* Flush all the bits above 2^d in its digit */ - dmask = (1 << nbit) - 1; - dp[ndig] &= dmask; - - /* Flush all digits above the one with 2^d in it */ - for(ix = ndig + 1; ix < USED(mp); ix++) - dp[ix] = 0; - - s_mp_clamp(mp); -} /* end s_mp_mod_2d() */ - -/* }}} */ - -/* {{{ s_mp_mul_2d(mp, d) */ - -/* - Multiply by the integer 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full multiplication code. +/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] */ -static mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) +int +mp_gcd (mp_int * a, mp_int * b, mp_int * c) { - mp_err res; - mp_digit save, next, mask, *dp; - mp_size used; - int ix; + mp_int u, v, t; + int k, res, neg; - if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) - return res; - dp = DIGITS(mp); used = USED(mp); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - /* If the shift requires another digit, make sure we've got one to - work with */ - if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { - if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) - return res; - dp = DIGITS(mp); + /* either zero than gcd is the largest */ + if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { + return mp_copy (b, c); } - - /* Do the shifting... */ - save = 0; - for(ix = 0; ix < (int)used; ix++) { - next = (dp[ix] >> (DIGIT_BIT - d)) & mask; - dp[ix] = (dp[ix] << d) | save; - save = next; + if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { + return mp_copy (a, c); } - - /* If, at this point, we have a nonzero carryout into the next - digit, we'll increase the size by one digit, and store it... - */ - if(save) { - dp[used] = save; - USED(mp) += 1; - } - - s_mp_clamp(mp); - return MP_OKAY; - -} /* end s_mp_mul_2d() */ - -/* }}} */ - -/* {{{ s_mp_div_2d(mp, d) */ - -/* - Divide the integer by 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full division code (used in Barrett reduction, see below) - */ -static void s_mp_div_2d(mp_int *mp, mp_digit d) -{ - int ix; - mp_digit save, next, mask, *dp = DIGITS(mp); - - s_mp_rshd(mp, d / DIGIT_BIT); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - save = 0; - for(ix = USED(mp) - 1; ix >= 0; ix--) { - next = dp[ix] & mask; - dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); - save = next; - } - - s_mp_clamp(mp); - -} /* end s_mp_div_2d() */ - -/* }}} */ - -/* {{{ s_mp_norm(a, b) */ - -/* - s_mp_norm(a, b) - - Normalize a and b for division, where b is the divisor. In order - that we might make good guesses for quotient digits, we want the - leading digit of b to be at least half the radix, which we - accomplish by multiplying a and b by a constant. This constant is - returned (so that it can be divided back out of the remainder at the - end of the division process). - - We multiply by the smallest power of 2 that gives us a leading digit - at least half the radix. By choosing a power of 2, we simplify the - multiplication and division steps to simple shifts. - */ -mp_digit s_mp_norm(mp_int *a, mp_int *b) -{ - mp_digit t, d = 0; - - t = DIGIT(b, USED(b) - 1); - while(t < (RADIX / 2)) { - t <<= 1; - ++d; - } - - if(d != 0) { - s_mp_mul_2d(a, d); - s_mp_mul_2d(b, d); - } - - return d; - -} /* end s_mp_norm() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive digit arithmetic */ - -/* {{{ s_mp_add_d(mp, d) */ - -/* Add d to |mp| in place */ -static mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ -{ - mp_word w, k = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - w = dp[0] + d; - dp[0] = ACCUM(w); - k = CARRYOUT(w); - - while(ix < used && k) { - w = dp[ix] + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - ++ix; - } - - if(k != 0) { - mp_err res; - - if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) - return res; - - DIGIT(mp, ix) = k; - } - - return MP_OKAY; - -} /* end s_mp_add_d() */ - -/* }}} */ - -/* {{{ s_mp_sub_d(mp, d) */ - -/* Subtract d from |mp| in place, assumes |mp| > d */ -static mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ -{ - mp_word w, b = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - /* Compute initial subtraction */ - w = (RADIX + dp[0]) - d; - b = CARRYOUT(w) ? 0 : 1; - dp[0] = ACCUM(w); - - /* Propagate borrows leftward */ - while(b && ix < used) { - w = (RADIX + dp[ix]) - b; - b = CARRYOUT(w) ? 0 : 1; - dp[ix] = ACCUM(w); - ++ix; - } - - /* Remove leading zeroes */ - s_mp_clamp(mp); - - /* If we have a borrow out, it's a violation of the input invariant */ - if(b) - return MP_RANGE; - else + if (mp_iszero (a) == 1 && mp_iszero (b) == 1) { + mp_set (c, 1); return MP_OKAY; - -} /* end s_mp_sub_d() */ - -/* }}} */ - -/* {{{ s_mp_mul_d(a, d) */ - -/* Compute a = a * d, single digit multiplication */ -static mp_err s_mp_mul_d(mp_int *a, mp_digit d) -{ - mp_word w, k = 0; - mp_size ix, max; - mp_err res; - mp_digit *dp = DIGITS(a); - - /* - Single-digit multiplication will increase the precision of the - output by at most one digit. However, we can detect when this - will happen -- if the high-order digit of a, times d, gives a - two-digit result, then the precision of the result will increase; - otherwise it won't. We use this fact to avoid calling s_mp_pad() - unless absolutely necessary. - */ - max = USED(a); - w = dp[max - 1] * d; - if(CARRYOUT(w) != 0) { - if((res = s_mp_pad(a, max + 1)) != MP_OKAY) - return res; - dp = DIGITS(a); } - for(ix = 0; ix < max; ix++) { - w = (dp[ix] * d) + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - } + /* if both are negative they share (-1) as a common divisor */ + neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; - /* If there is a precision increase, take care of it here; the above - test guarantees we have enough storage to do this safely. - */ - if(k) { - dp[max] = k; - USED(a) = max + 1; - } - - s_mp_clamp(a); - - return MP_OKAY; - -} /* end s_mp_mul_d() */ - -/* }}} */ - -/* {{{ s_mp_div_d(mp, d, r) */ - -/* - s_mp_div_d(mp, d, r) - - Compute the quotient mp = mp / d and remainder r = mp mod d, for a - single digit d. If r is null, the remainder will be discarded. - */ - -static mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) -{ - mp_word w = 0, t; - mp_int quot; - mp_err res; - mp_digit *dp = DIGITS(mp), *qp; - int ix; - - if(d == 0) - return MP_RANGE; - - /* Make room for the quotient */ - if((res = mp_init_size(", USED(mp))) != MP_OKAY) + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { return res; + } - USED(") = USED(mp); /* so clamping will work below */ - qp = DIGITS("); + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto __U; + } - /* Divide without subtraction */ - for(ix = USED(mp) - 1; ix >= 0; ix--) { - w = (w << DIGIT_BIT) | dp[ix]; + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; - if(w >= d) { - t = w / d; - w = w % d; + if ((res = mp_init (&t)) != MP_OKAY) { + goto __V; + } + + /* B1. Find power of two */ + k = 0; + while ((u.dp[0] & 1) == 0 && (v.dp[0] & 1) == 0) { + ++k; + if ((res = mp_div_2d (&u, 1, &u, NULL)) != MP_OKAY) { + goto __T; + } + if ((res = mp_div_2d (&v, 1, &v, NULL)) != MP_OKAY) { + goto __T; + } + } + + /* B2. Initialize */ + if ((u.dp[0] & 1) == 1) { + if ((res = mp_copy (&v, &t)) != MP_OKAY) { + goto __T; + } + t.sign = MP_NEG; + } else { + if ((res = mp_copy (&u, &t)) != MP_OKAY) { + goto __T; + } + } + + do { + /* B3 (and B4). Halve t, if even */ + while (t.used != 0 && (t.dp[0] & 1) == 0) { + if ((res = mp_div_2d (&t, 1, &t, NULL)) != 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 { - t = 0; + if ((res = mp_copy (&t, &v)) != MP_OKAY) { + goto __T; + } + v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; } - qp[ix] = t; - } - - /* Deliver the remainder, if desired */ - if(r) - *r = w; - - s_mp_clamp("); - mp_exch(", mp); - mp_clear("); - - return MP_OKAY; - -} /* end s_mp_div_d() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive full arithmetic */ - -/* {{{ s_mp_add(a, b) */ - -/* Compute a = |a| + |b| */ -static mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - mp_err res; - - /* Make sure a has enough precision for the output value */ - if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) - return res; - - /* - Add up all digits up to the precision of b. If b had initially - the same precision as a, or greater, we took care of it by the - padding step above, so there is no problem. If b had initially - less precision, we'll have to make sure the carry out is duly - propagated upward among the higher-order digits of the sum. - */ - pa = DIGITS(a); - pb = DIGITS(b); - for(ix = 0; ix < used; ++ix) { - w += *pa + *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - } - - /* If we run out of 'b' digits before we're actually done, make - sure the carries get propagated upward... - */ - used = USED(a); - while(w && ix < used) { - w += *pa; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - ++ix; - } - - /* If there's an overall carry out, increase precision and include - it. We could have done this initially, but why touch the memory - allocator unless we're sure we have to? - */ - if(w) { - if((res = s_mp_pad(a, used + 1)) != MP_OKAY) - return res; - - DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ - } - - return MP_OKAY; - -} /* end s_mp_add() */ - -/* }}} */ - -/* {{{ s_mp_sub(a, b) */ - -/* Compute a = |a| - |b|, assumes |a| >= |b| */ -static mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - - /* - Subtract and propagate borrow. Up to the precision of b, this - accounts for the digits of b; after that, we just make sure the - carries get to the right place. This saves having to pad b out to - the precision of a just to make the loops work right... - */ - pa = DIGITS(a); - pb = DIGITS(b); - - for(ix = 0; ix < used; ++ix) { - w = (RADIX + *pa) - w - *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - } - - used = USED(a); - while(ix < used) { - w = RADIX + *pa - w; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - ++ix; - } - - /* Clobber any leading zeroes we created */ - s_mp_clamp(a); - - /* - If there was a borrow out, then |b| > |a| in violation - of our input invariant. We've already done the work, - but we'll at least complain about it... - */ - if(w) - return MP_RANGE; - else - return MP_OKAY; - -} /* end s_mp_sub() */ - -/* }}} */ - -/* {{{ s_mp_mul(a, b) */ - -/* Compute a = |a| * |b| */ -static mp_err s_mp_mul(mp_int *a, mp_int *b) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, ua = USED(a), ub = USED(b); - mp_digit *pa, *pb, *pt, *pbt; - - if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) - return res; - - /* This has the effect of left-padding with zeroes... */ - USED(&tmp) = ua + ub; - - /* We're going to need the base value each iteration */ - pbt = DIGITS(&tmp); - - /* Outer loop: Digits of b */ - - pb = DIGITS(b); - for(ix = 0; ix < ub; ++ix, ++pb) { - if(*pb == 0) - continue; - - /* Inner product: Digits of a */ - pa = DIGITS(a); - for(jx = 0; jx < ua; ++jx, ++pa) { - pt = pbt + ix + jx; - w = *pb * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); + /* 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); - pbt[ix + jx] = k; - k = 0; + if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { + goto __T; } - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_mul() */ - -/* Compute a = |a| * |b| max of digs digits */ -static mp_err s_mp_mul_dig(mp_int *a, mp_int *b, int digs) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, ua = USED(a), ub = USED(b); - mp_digit *pa, *pb, *pt, *pbt; - - if((res = mp_init_size(&tmp, digs+1)) != MP_OKAY) - return res; - - /* This has the effect of left-padding with zeroes... */ - USED(&tmp) = digs+1; - - /* We're going to need the base value each iteration */ - pbt = DIGITS(&tmp); - - /* Outer loop: Digits of b */ - - ub = MIN(digs, (int)ub); - ua = MIN(digs, (int)ua); - - pb = DIGITS(b); - for(ix = 0; ix < ub; ++ix, ++pb) { - if(*pb == 0) - continue; - - /* Inner product: Digits of a */ - pa = DIGITS(a); - for(jx = 0; jx < ua; ++jx, ++pa) { - if ((int)(ix+jx) > digs) { break; } - pt = pbt + ix + jx; - w = *pb * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - if ((int)(ix + jx) < digs) { - pbt[ix + jx] = k; - } - k = 0; - } - - USED(&tmp) = digs; - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_mul() */ - -/* }}} */ - -/* {{{ s_mp_kmul(a, b, out, len) */ - -#if 0 -static void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) -{ - mp_word w, k = 0; - mp_size ix, jx; - mp_digit *pa, *pt; - - for(ix = 0; ix < len; ++ix, ++b) { - if(*b == 0) - continue; - - pa = a; - for(jx = 0; jx < len; ++jx, ++pa) { - pt = out + ix + jx; - w = *b * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - - out[ix + jx] = k; - k = 0; - } - -} /* end s_mp_kmul() */ -#endif - -/* }}} */ - -/* {{{ s_mp_sqr(a) */ - -/* - Computes the square of a, in place. This can be done more - efficiently than a general multiplication, because many of the - computation steps are redundant when squaring. The inner product - step is a bit more complicated, but we save a fair number of - iterations of the multiplication loop. - */ -#if MP_SQUARE -static mp_err s_mp_sqr(mp_int *a) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, kx, used = USED(a); - mp_digit *pa1, *pa2, *pt, *pbt; - - if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) - return res; - - /* Left-pad with zeroes */ - USED(&tmp) = 2 * used; - - /* We need the base value each time through the loop */ - pbt = DIGITS(&tmp); - - pa1 = DIGITS(a); - for(ix = 0; ix < used; ++ix, ++pa1) { - if(*pa1 == 0) - continue; - - w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); - - pbt[ix + ix] = ACCUM(w); - k = CARRYOUT(w); - - /* - The inner product is computed as: - - (C, S) = t[i,j] + 2 a[i] a[j] + C - - This can overflow what can be represented in an mp_word, and - since C arithmetic does not provide any way to check for - overflow, we have to check explicitly for overflow conditions - before they happen. - */ - for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { - mp_word u = 0, v; - - /* Store this in a temporary to avoid indirections later */ - pt = pbt + ix + jx; - - /* Compute the multiplicative step */ - w = *pa1 * *pa2; - - /* If w is more than half MP_WORD_MAX, the doubling will - overflow, and we need to record a carry out into the next - word */ - u = (w >> (MP_WORD_BIT - 1)) & 1; - - /* Double what we've got, overflow will be ignored as defined - for C arithmetic (we've already noted if it is to occur) - */ - w *= 2; - - /* Compute the additive step */ - v = *pt + k; - - /* If we do not already have an overflow carry, check to see - if the addition will cause one, and set the carry out if so - */ - u |= ((MP_WORD_MAX - v) < w); - - /* Add in the rest, again ignoring overflow */ - w += v; - - /* Set the i,j digit of the output */ - *pt = ACCUM(w); - - /* Save carry information for the next iteration of the loop. - This is why k must be an mp_word, instead of an mp_digit */ - k = CARRYOUT(w) | (u << DIGIT_BIT); - - } /* for(jx ...) */ - - /* Set the last digit in the cycle and reset the carry */ - k = DIGIT(&tmp, ix + jx) + k; - pbt[ix + jx] = ACCUM(k); - k = CARRYOUT(k); - - /* If we are carrying out, propagate the carry to the next digit - in the output. This may cascade, so we have to be somewhat - circumspect -- but we will have enough precision in the output - that we won't overflow - */ - kx = 1; - while(k) { - k = pbt[ix + jx + kx] + 1; - pbt[ix + jx + kx] = ACCUM(k); - k = CARRYOUT(k); - ++kx; - } - } /* for(ix ...) */ - - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_sqr() */ -#endif - -/* }}} */ - -/* {{{ s_mp_div(a, b) */ - -/* - s_mp_div(a, b) - - Compute a = a / b and b = a mod b. Assumes b > a. - */ - -static mp_err s_mp_div(mp_int *a, mp_int *b) -{ - mp_int quot, rem, t; - mp_word q; - mp_err res; - mp_digit d; - int ix; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Shortcut if b is power of two */ - if((ix = s_mp_ispow2(b)) >= 0) { - mp_copy(a, b); /* need this for remainder */ - s_mp_div_2d(a, (mp_digit)ix); - s_mp_mod_2d(b, (mp_digit)ix); - - return MP_OKAY; - } - - /* Allocate space to store the quotient */ - if((res = mp_init_size(", USED(a))) != MP_OKAY) - return res; - - /* A working temporary for division */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - goto T; - - /* Allocate space for the remainder */ - if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) - goto REM; - - /* Normalize to optimize guessing */ - d = s_mp_norm(a, b); - - /* Perform the division itself...woo! */ - ix = USED(a) - 1; - - while(ix >= 0) { - /* Find a partial substring of a which is at least b */ - while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { - if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_lshd(", 1)) != MP_OKAY) - goto CLEANUP; - - DIGIT(&rem, 0) = DIGIT(a, ix); - s_mp_clamp(&rem); - --ix; - } - - /* If we didn't find one, we're finished dividing */ - if(s_mp_cmp(&rem, b) < 0) - break; - - /* Compute a guess for the next quotient digit */ - q = DIGIT(&rem, USED(&rem) - 1); - if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) - q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); - - q /= DIGIT(b, USED(b) - 1); - - /* The guess can be as much as RADIX + 1 */ - if(q >= RADIX) - q = RADIX - 1; - - /* See what that multiplies out to */ - mp_copy(b, &t); - if((res = s_mp_mul_d(&t, (mp_digit)q)) != MP_OKAY) - goto CLEANUP; - - /* - If it's too big, back it off. We should not have to do this - more than once, or, in rare cases, twice. Knuth describes a - method by which this could be reduced to a maximum of once, but - I didn't implement that here. - */ - while(s_mp_cmp(&t, &rem) > 0) { - --q; - s_mp_sub(&t, b); - } - - /* At this point, q should be the right next digit */ - if((res = s_mp_sub(&rem, &t)) != MP_OKAY) - goto CLEANUP; - - /* - Include the digit in the quotient. We allocated enough memory - for any quotient we could ever possibly get, so we should not - have to check for failures here - */ - DIGIT(", 0) = q; - } - - /* Denormalize remainder */ - if(d != 0) - s_mp_div_2d(&rem, d); - - s_mp_clamp("); - s_mp_clamp(&rem); - - /* Copy quotient back to output */ - s_mp_exch(", a); - - /* Copy remainder back to output */ - s_mp_exch(&rem, b); - -CLEANUP: - mp_clear(&rem); -REM: - mp_clear(&t); -T: - mp_clear("); - + 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 s_mp_div() */ +/* 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://libtommath.iahu.ca + */ +#include -/* {{{ s_mp_2expt(a, k) */ - -static mp_err s_mp_2expt(mp_int *a, mp_digit k) +/* grow as required */ +int +mp_grow (mp_int * a, int size) { - mp_err res; - mp_size dig, bit; + int i, n; - dig = k / DIGIT_BIT; - bit = k % DIGIT_BIT; + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); /* ensure there are always at least MP_PREC digits extra on top */ - mp_zero(a); - if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) - return res; - - DIGIT(a, dig) |= (1 << bit); + a->dp = realloc (a->dp, sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + 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://libtommath.iahu.ca + */ +#include + +/* init a new bigint */ +int +mp_init (mp_int * a) +{ + + /* allocate ram required and clear it */ + a->dp = calloc (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 s_mp_2expt() */ +/* End: bn_mp_init.c */ -/* }}} */ - -/* {{{ s_mp_reduce(x, m, mu) */ - -/* - Compute Barrett reduction, x (mod m), given a precomputed value for - mu = b^2k / m, where b = RADIX and k = #digits(m). This should be - faster than straight division, when many reductions by the same - value of m are required (such as in modular exponentiation). This - can nearly halve the time required to do modular exponentiation, - as compared to using the full integer divide to reduce. - - This algorithm was derived from the _Handbook of Applied - Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, - pp. 603-604. +/* 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://libtommath.iahu.ca */ +#include -static mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) +/* creates "a" then copies b into it */ +int +mp_init_copy (mp_int * a, mp_int * b) { - mp_int q; - mp_err res; - mp_size um = USED(m); + int res; - if((res = mp_init_copy(&q, x)) != MP_OKAY) + if ((res = mp_init (a)) != MP_OKAY) { return res; + } + res = mp_copy (b, a); + return res; +} - s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ - s_mp_mul(&q, mu); /* q2 = q1 * mu */ - s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ +/* 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://libtommath.iahu.ca + */ +#include + +/* init a mp_init and grow it to a given size */ +int +mp_init_size (mp_int * a, int size) +{ + + /* pad up so there are at least 16 zero digits */ + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); /* ensure there are always at least 16 digits extra on top */ + a->dp = 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 */ +/* 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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, x; + + + 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 (&t1) != MP_OKAY) + goto Y1; + if (mp_init (&t2) != MP_OKAY) + goto T1; + if (mp_init (&x0y0) != MP_OKAY) + goto T2; + if (mp_init (&x1y1) != 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; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + for (x = 0; x < B; x++) { + x0.dp[x] = a->dp[x]; + y0.dp[x] = b->dp[x]; + } + for (x = B; x < a->used; x++) { + x1.dp[x - B] = a->dp[x]; + } + for (x = B; x < b->used; x++) { + y1.dp[x - B] = b->dp[x]; + } + + /* 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, x; + + + 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 (&t1) != MP_OKAY) + goto X1; + if (mp_init (&t2) != MP_OKAY) + goto T1; + if (mp_init (&x0x0) != MP_OKAY) + goto T2; + if (mp_init (&x1x1) != MP_OKAY) + goto X0X0; + + /* now shift the digits */ + for (x = 0; x < B; x++) { + x0.dp[x] = a->dp[x]; + } + + for (x = B; x < a->used; x++) { + x1.dp[x - B] = a->dp[x]; + } + + 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 (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://libtommath.iahu.ca + */ +#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; + } + + /* increment the used by the shift amount than copy upwards */ + a->used += b; + for (x = a->used - 1; x >= b; x--) { + a->dp[x] = a->dp[x - b]; + } + + /* zero the lower digits */ + for (x = 0; x < b; x++) { + a->dp[x] = 0; + } + mp_clamp (a); + 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#include + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (mp_int * a, mp_digit * mp) +{ + mp_int t, tt; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&tt)) != MP_OKAY) { + goto __T; + } + + /* tt = b */ + tt.dp[0] = 0; + tt.dp[1] = 1; + tt.used = 2; + + /* t = m mod b */ + t.dp[0] = a->dp[0]; + t.used = 1; + + /* t = 1/m mod b */ + if ((res = mp_invmod (&t, &tt, &t)) != MP_OKAY) { + goto __TT; + } + + /* t = -1/m mod b */ + *mp = ((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - t.dp[0]; + + res = MP_OKAY; +__TT:mp_clear (&tt); +__T:mp_clear (&t); + return res; +} + +/* 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://libtommath.iahu.ca + */ +#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 { + 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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; + + r = 0; + tmpa = a->dp; + tmpb = b->dp; + for (x = 0; x < b->used; x++) { + rr = *tmpa >> (DIGIT_BIT - 1); + *tmpb++ = ((*tmpa++ << 1) | r) & MP_MASK; + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + if (b->alloc == b->used) { + if ((res = mp_grow (b, b->used + 1)) != MP_OKAY) { + return res; + } + } + /* add a MSB of 1 */ + *tmpb = 1; + ++b->used; + } + + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + 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://libtommath.iahu.ca + */ +#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 ((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) { + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (c->dp[x] >> (DIGIT_BIT - d)) & ((mp_digit) ((1U << d) - 1U)); + + /* shift the current word and OR in the carry */ + c->dp[x] = ((c->dp[x] << d) | r) & MP_MASK; + + /* 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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_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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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) */ - s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1))); + 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) */ - s_mp_mul_dig(&q, m, um + 1); -// s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1))); + 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) + if ((res = mp_sub (x, &q, x)) != MP_OKAY) goto CLEANUP; /* If x < 0, add b^(k+1) to it */ - if(mp_cmp_z(x) < 0) { - mp_set(&q, 1); - if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY) + 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) + if ((res = mp_add (x, &q, x)) != MP_OKAY) goto CLEANUP; } /* Back off if it's too big */ - while(mp_cmp(x, m) >= 0) { - if((res = s_mp_sub(x, m)) != MP_OKAY) + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) break; } - CLEANUP: - mp_clear(&q); +CLEANUP: + mp_clear (&q); return res; +} -} /* end s_mp_reduce() */ +/* 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://libtommath.iahu.ca + */ +#include -/* }}} */ - -/* {{{ Primitive comparisons */ - -/* {{{ s_mp_cmp(a, b) */ - -/* Compare |a| <=> |b|, return 0 if equal, <0 if a0 if a>b */ -static int s_mp_cmp(mp_int *a, mp_int *b) +/* shift right a certain amount of digits */ +void +mp_rshd (mp_int * a, int b) { - mp_size ua = USED(a), ub = USED(b); + int x; - if(ua > ub) - return MP_GT; - else if(ua < ub) - return MP_LT; - else { - int ix = ua - 1; - mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; - while(ix >= 0) { - if(*ap > *bp) - return MP_GT; - else if(*ap < *bp) - return MP_LT; + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } - --ap; --bp; --ix; + /* if b > used then simply zero it and return */ + if (a->used < b) { + mp_zero (a); + return; + } + + /* shift the digits down */ + for (x = 0; x < (a->used - b); x++) { + a->dp[x] = a->dp[x + b]; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + a->dp[x] = 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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; } - return MP_EQ; + /* 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; } -} /* end s_mp_cmp() */ + mp_clamp (a); + return MP_OKAY; +} -/* }}} */ +/* End: bn_mp_set_int.c */ -/* {{{ s_mp_cmp_d(a, d) */ - -/* Compare |a| <=> d, return 0 if equal, <0 if a0 if a>d */ -static int s_mp_cmp_d(mp_int *a, mp_digit d) -{ - mp_size ua = USED(a); - mp_digit *ap = DIGITS(a); - - if(ua > 1) - return MP_GT; - - if(*ap < d) - return MP_LT; - else if(*ap > d) - return MP_GT; - else - return MP_EQ; - -} /* end s_mp_cmp_d() */ - -/* }}} */ - -/* {{{ s_mp_ispow2(v) */ - -/* - Returns -1 if the value is not a power of two; otherwise, it returns - k such that v = 2^k, i.e. lg(v). +/* 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://libtommath.iahu.ca */ -static int s_mp_ispow2(mp_int *v) +#include + +/* shrink a bignum */ +int +mp_shrink (mp_int * a) { - mp_digit d, *dp; - mp_size uv = USED(v); - int extra = 0, ix; + if (a->alloc != a->used) { + if ((a->dp = realloc (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->alloc = a->used; + } + return MP_OKAY; +} - d = DIGIT(v, uv - 1); /* most significant digit of v */ +/* End: bn_mp_shrink.c */ - while(d && ((d & 1) == 0)) { - d >>= 1; - ++extra; +/* 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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 { + 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://libtommath.iahu.ca + */ +#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(d == 1) { - ix = uv - 2; - dp = DIGITS(v) + ix; + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} - while(ix >= 0) { - if(*dp) - return -1; /* not a power of two */ +/* End: bn_mp_sqrmod.c */ - --dp; --ix; +/* 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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_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://libtommath.iahu.ca + */ +#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; + } } - return ((uv - 1) * DIGIT_BIT) + extra; - } + 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; +} - return -1; - -} /* end s_mp_ispow2() */ - -/* }}} */ - -/* {{{ s_mp_ispow2d(d) */ - -static int s_mp_ispow2d(mp_digit d) +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int +mp_toradix (mp_int * a, char *str, int radix) { - int pow = 0; + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; - while((d & 1) == 0) { - ++pow; d >>= 1; + if (radix < 2 || radix > 64) { + return MP_VAL; } - if(d == 1) - return pow; + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } - return -1; + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } -} /* end s_mp_ispow2d() */ + 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; +} -/* }}} */ - -/* }}} */ - -/* {{{ Primitive I/O helpers */ - -/* {{{ s_mp_tovalue(ch, r) */ - -/* - Convert the given character to its digit value, in the given radix. - If the given character is not understood in the given radix, -1 is - returned. Otherwise the digit's numeric value is returned. - - The results will be odd if you use a radix < 2 or > 62, you are - expected to know what you're up to. - */ -static int s_mp_tovalue(char ch, int r) +/* returns size of ASCII reprensentation */ +int +mp_radix_size (mp_int * a, int radix) { - int val, xch; - - if(r > 36) - xch = ch; - else - xch = toupper(ch); + int res, digs; + mp_int t; + mp_digit d; - if(isdigit(xch)) - val = xch - '0'; - else if(isupper(xch)) - val = xch - 'A' + 10; - else if(islower(xch)) - val = xch - 'a' + 36; - else if(xch == '+') - val = 62; - else if(xch == '/') - val = 63; - else - return -1; + /* special case for binary */ + if (radix == 2) { + return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + } - if(val < 0 || val >= r) - return -1; - - return val; - -} /* end s_mp_tovalue() */ - -/* }}} */ - -/* {{{ s_mp_todigit(val, r, low) */ - -/* - Convert val to a radix-r digit, if possible. If val is out of range - for r, returns zero. Otherwise, returns an ASCII character denoting - the value in the given radix. - - The results may be odd if you use a radix < 2 or > 64, you are - expected to know what you're doing. - */ - -char s_mp_todigit(int val, int r, int low) -{ - char ch; - - if(val < 0 || val >= r) + if (radix < 2 || radix > 64) { return 0; + } - ch = s_dmap_1[val]; + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return 0; + } - if(r <= 36 && low) - ch = tolower(ch); + digs = 0; + if (t.sign == MP_NEG) { + ++digs; + t.sign = MP_ZPOS; + } - return ch; + 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 s_mp_todigit() */ +/* End: bn_radix.c */ -/* }}} */ - -/* {{{ s_mp_outlen(bits, radix) */ - -/* - Return an estimate for how long a string is needed to hold a radix - r representation of a number with 'bits' significant bits. - - Does not include space for a sign or a NUL terminator. +/* 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://libtommath.iahu.ca */ -static int s_mp_outlen(int bits, int r) +#include + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) { - return (int)((double)bits * LOG_V_2(r)); + int ix, iy; + unsigned char t; -} /* end s_mp_outlen() */ + 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://libtommath.iahu.ca + */ +#include -#endif /* MPI */ +/* 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; -/*------------------------------------------------------------------------*/ -/* HERE THERE BE DRAGONS */ + /* 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 */ + tmpa = a->dp; + tmpb = b->dp; + 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://libtommath.iahu.ca + */ +#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? + * + * 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 + */ + if ((digs < 512) + && digs < (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 */ + 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://libtommath.iahu.ca + */ +#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://libtommath.iahu.ca + */ +#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; + + /* can we use the fast multiplier? */ + if (((a->used * 2 + 1) < 512) + && a->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT) - 1))) { + return fast_s_mp_sqr (a, b); + } + + 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://libtommath.iahu.ca + */ +#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 */ diff --git a/mpi.h b/mpi.h deleted file mode 100644 index e19ecf8..0000000 --- a/mpi.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - mpi.h - - by Michael J. Fromberger - Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved - - Arbitrary precision integer arithmetic library - - $ID$ - */ - -#ifndef _H_MPI_ -#define _H_MPI_ - -#include "mpi-config.h" - -#define MP_LT -1 -#define MP_EQ 0 -#define MP_GT 1 - -#if MP_DEBUG -#undef MP_IOFUNC -#define MP_IOFUNC 1 -#endif - -#if MP_IOFUNC -#include -#include -#endif - -#include - -#define MP_NEG 1 -#define MP_ZPOS 0 - -/* Included for compatibility... */ -#define NEG MP_NEG -#define ZPOS MP_ZPOS - -#define MP_OKAY 0 /* no error, all is well */ -#define MP_YES 0 /* yes (boolean result) */ -#define MP_NO -1 /* no (boolean result) */ -#define MP_MEM -2 /* out of memory */ -#define MP_RANGE -3 /* argument out of range */ -#define MP_BADARG -4 /* invalid parameter */ -#define MP_UNDEF -5 /* answer is undefined */ -#define MP_LAST_CODE MP_UNDEF - -#include "mpi-types.h" - -/* Included for compatibility... */ -#define DIGIT_BIT MP_DIGIT_BIT -#define DIGIT_MAX MP_DIGIT_MAX - -/* Macros for accessing the mp_int internals */ -#define SIGN(MP) ((MP)->sign) -#define USED(MP) ((MP)->used) -#define ALLOC(MP) ((MP)->alloc) -#define DIGITS(MP) ((MP)->dp) -#define DIGIT(MP,N) (MP)->dp[(N)] - -#if MP_ARGCHK == 1 -#define ARGCHK(X,Y) {if(!(X)){return (Y);}} -#elif MP_ARGCHK == 2 -#include -#define ARGCHK(X,Y) assert(X) -#else -#define ARGCHK(X,Y) /* */ -#endif - -/* This defines the maximum I/O base (minimum is 2) */ -#define MAX_RADIX 64 - -typedef struct { - mp_sign sign; /* sign of this quantity */ - mp_size alloc; /* how many digits allocated */ - mp_size used; /* how many digits used */ - mp_digit *dp; /* the digits themselves */ -} mp_int; - -/*------------------------------------------------------------------------*/ -/* Default precision */ - -unsigned int mp_get_prec(void); -void mp_set_prec(unsigned int prec); - -/*------------------------------------------------------------------------*/ -/* Memory management */ - -mp_err mp_init(mp_int *mp); -mp_err mp_init_array(mp_int mp[], int count); -mp_err mp_init_size(mp_int *mp, mp_size prec); -mp_err mp_init_copy(mp_int *mp, mp_int *from); -mp_err mp_copy(mp_int *from, mp_int *to); -void mp_exch(mp_int *mp1, mp_int *mp2); -void mp_clear(mp_int *mp); -void mp_clear_array(mp_int mp[], int count); -void mp_zero(mp_int *mp); -void mp_set(mp_int *mp, mp_digit d); -mp_err mp_set_int(mp_int *mp, long z); -mp_err mp_shrink(mp_int *a); - - -/*------------------------------------------------------------------------*/ -/* Single digit arithmetic */ - -mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b); -mp_err mp_mul_2(mp_int *a, mp_int *c); -mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r); -mp_err mp_div_2(mp_int *a, mp_int *c); -mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c); - -/*------------------------------------------------------------------------*/ -/* Sign manipulations */ - -mp_err mp_abs(mp_int *a, mp_int *b); -mp_err mp_neg(mp_int *a, mp_int *b); - -/*------------------------------------------------------------------------*/ -/* Full arithmetic */ - -mp_err mp_add(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c); -#if MP_SQUARE -mp_err mp_sqr(mp_int *a, mp_int *b); -#else -#define mp_sqr(a, b) mp_mul(a, a, b) -#endif -mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r); -mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r); -mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_2expt(mp_int *a, mp_digit k); -mp_err mp_sqrt(mp_int *a, mp_int *b); - -/*------------------------------------------------------------------------*/ -/* Modular arithmetic */ - -#if MP_MODARITH -mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c); -mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c); -mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -#if MP_SQUARE -mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c); -#else -#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c) -#endif -mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); -mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c); -#endif /* MP_MODARITH */ - -/*------------------------------------------------------------------------*/ -/* Comparisons */ - -int mp_cmp_z(mp_int *a); -int mp_cmp_d(mp_int *a, mp_digit d); -int mp_cmp(mp_int *a, mp_int *b); -int mp_cmp_mag(mp_int *a, mp_int *b); -int mp_cmp_int(mp_int *a, long z); -int mp_isodd(mp_int *a); -int mp_iseven(mp_int *a); - -/*------------------------------------------------------------------------*/ -/* Number theoretic */ - -#if MP_NUMTH -mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); -mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y); -mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c); -#endif /* end MP_NUMTH */ - -/*------------------------------------------------------------------------*/ -/* Input and output */ - -#if MP_IOFUNC -void mp_print(mp_int *mp, FILE *ofp); -#endif /* end MP_IOFUNC */ - -/*------------------------------------------------------------------------*/ -/* Base conversion */ - -#define BITS 1 -#define BYTES CHAR_BIT - -mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len); -int mp_signed_bin_size(mp_int *mp); -mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str); - -mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len); -int mp_unsigned_bin_size(mp_int *mp); -mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); - -int mp_count_bits(mp_int *mp); - -#if MP_COMPAT_MACROS -#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)) -#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) -#define mp_mag_size(mp) mp_unsigned_bin_size(mp) -#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) -#endif - -mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix); -int mp_radix_size(mp_int *mp, int radix); -int mp_value_radix_size(int num, int qty, int radix); -mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix); - -int mp_char2value(char ch, int r); - -#define mp_tobinary(M, S) mp_toradix((M), (S), 2) -#define mp_tooctal(M, S) mp_toradix((M), (S), 8) -#define mp_todecimal(M, S) mp_toradix((M), (S), 10) -#define mp_tohex(M, S) mp_toradix((M), (S), 16) - -/*------------------------------------------------------------------------*/ -/* Error strings */ - -const char *mp_strerror(mp_err ec); - -#endif /* end _H_MPI_ */ diff --git a/mpi.old b/mpi.old deleted file mode 100644 index 6307cab..0000000 --- a/mpi.old +++ /dev/null @@ -1,4216 +0,0 @@ - /* - mpi.c - - by Michael J. Fromberger - Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved - - Arbitrary precision integer arithmetic library - - $Id: mpi.c,v 1.22 2001/09/14 15:11:20 sting Exp sting $ - */ - -#include -#include -#include -#include - -#include "mycrypt.h" - -#ifdef MPI - -#if MP_DEBUG -#include - -#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} -#else -#define DIAG(T,V) -#endif - -/* - If MP_LOGTAB is not defined, use the math library to compute the - logarithms on the fly. Otherwise, use the static table below. - Pick which works best for your system. - */ -#if MP_LOGTAB - -/* {{{ s_logv_2[] - log table for 2 in various bases */ - -/* - A table of the logs of 2 for various bases (the 0 and 1 entries of - this table are meaningless and should not be referenced). - - This table is used to compute output lengths for the mp_toradix() - function. Since a number n in radix r takes up about log_r(n) - digits, we estimate the output size by taking the least integer - greater than log_r(n), where: - - log_r(n) = log_2(n) * log_r(2) - - This table, therefore, is a table of log_r(2) for 2 <= r <= 36, - which are the output bases supported. - */ -const float s_logv_2[] = { - 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ - 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ - 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ - 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ - 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ - 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ - 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ - 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ - 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ - 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ - 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ - 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ - 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ - 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ - 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ - 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ - 0.166666667 -}; -/* }}} */ -#define LOG_V_2(R) s_logv_2[(R)] - -#else - -#include -#define LOG_V_2(R) (log(2.0)/log(R)) - -#endif - -/* Default precision for newly created mp_int's */ -static unsigned static int s_mp_defprec = MP_DEFPREC; - -/* {{{ Digit arithmetic macros */ - -/* - When adding and multiplying digits, the results can be larger than - can be contained in an mp_digit. Thus, an mp_word is used. These - macros mask off the upper and lower digits of the mp_word (the - mp_word may be more than 2 mp_digits wide, but we only concern - ourselves with the low-order 2 mp_digits) - - If your mp_word DOES have more than 2 mp_digits, you need to - uncomment the first line, and comment out the second. - */ - -/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ -#define CARRYOUT(W) ((W)>>DIGIT_BIT) -#define ACCUM(W) ((W)&MP_DIGIT_MAX) - -/* }}} */ - -/* {{{ Comparison constants */ - - -/* }}} */ - -/* {{{ Constant strings */ - -/* Constant strings returned by mp_strerror() */ -static const char *mp_err_string[] = { - "unknown result code", /* say what? */ - "boolean true", /* MP_OKAY, MP_YES */ - "boolean false", /* MP_NO */ - "out of memory", /* MP_MEM */ - "argument out of range", /* MP_RANGE */ - "invalid input parameter", /* MP_BADARG */ - "result is undefined" /* MP_UNDEF */ -}; - -/* Value to digit maps for radix conversion */ - -/* s_dmap_1 - standard digits and letters */ -static const char *s_dmap_1 = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -#if 0 -/* s_dmap_2 - base64 ordering for digits */ -static const char *s_dmap_2 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -#endif - -/* }}} */ - -/* {{{ Static function declarations */ - -/* - If MP_MACRO is false, these will be defined as actual functions; - otherwise, suitable macro definitions will be used. This works - around the fact that ANSI C89 doesn't support an 'inline' keyword - (although I hear C9x will ... about bloody time). At present, the - macro definitions are identical to the function bodies, but they'll - expand in place, instead of generating a function call. - - I chose these particular functions to be made into macros because - some profiling showed they are called a lot on a typical workload, - and yet they are primarily housekeeping. - */ -#if MP_MACRO == 0 - void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ - void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ - void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ - void s_mp_free(void *ptr); /* general free function */ -#else - - /* Even if these are defined as macros, we need to respect the settings - of the MP_MEMSET and MP_MEMCPY configuration options... - */ - #if MP_MEMSET == 0 - #define s_mp_setz(dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} - #else - #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) - #endif /* MP_MEMSET */ - - #if MP_MEMCPY == 0 - #define s_mp_copy(sp, dp, count) \ - {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} - #else - #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) - #endif /* MP_MEMCPY */ - - #define s_mp_alloc(nb, ni) XCALLOC(nb, ni) - #define s_mp_free(ptr) {if(ptr) XFREE(ptr);} -#endif /* MP_MACRO */ - -static mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ -static mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ - -void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ - -void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ - -static mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ -void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ -void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ -void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ -static mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ -void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ -static mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ -mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ -static mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ -static mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ -static mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ -static mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); - /* unsigned digit divide */ -static mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); - /* Barrett reduction */ -static mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ -static mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ -static mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ -#if 0 -void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); - /* multiply buffers in place */ -#endif -#if MP_SQUARE -static mp_err s_mp_sqr(mp_int *a); /* magnitude square */ -#else -#define s_mp_sqr(a) s_mp_mul(a, a) -#endif -static mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ -static mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ -static int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ -static int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ -static int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ -static int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ - -static int s_mp_tovalue(char ch, int r); /* convert ch to value */ -char s_mp_todigit(int val, int r, int low); /* convert val to digit */ -static int s_mp_outlen(int bits, int r); /* output length in bytes */ - -/* }}} */ - -/* {{{ Default precision manipulation */ - -unsigned int mp_get_prec(void) -{ - return s_mp_defprec; - -} /* end mp_get_prec() */ - -void mp_set_prec(unsigned int prec) -{ - if(prec == 0) - s_mp_defprec = MP_DEFPREC; - else - s_mp_defprec = prec; - -} /* end mp_set_prec() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_init(mp) */ - -/* - mp_init(mp) - - Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, - MP_MEM if memory could not be allocated for the structure. - */ - -mp_err mp_init(mp_int *mp) -{ - return mp_init_size(mp, s_mp_defprec); - -} /* end mp_init() */ - -/* }}} */ - -/* {{{ mp_init_array(mp[], count) */ - -mp_err mp_init_array(mp_int mp[], int count) -{ - mp_err res; - int pos; - - ARGCHK(mp !=NULL && count > 0, MP_BADARG); - - for(pos = 0; pos < count; ++pos) { - if((res = mp_init(&mp[pos])) != MP_OKAY) - goto CLEANUP; - } - - return MP_OKAY; - - CLEANUP: - while(--pos >= 0) - mp_clear(&mp[pos]); - - return res; - -} /* end mp_init_array() */ - -/* }}} */ - -/* {{{ mp_init_size(mp, prec) */ - -/* - mp_init_size(mp, prec) - - Initialize a new zero-valued mp_int with at least the given - precision; returns MP_OKAY if successful, or MP_MEM if memory could - not be allocated for the structure. - */ - -mp_err mp_init_size(mp_int *mp, mp_size prec) -{ - ARGCHK(mp != NULL && prec > 0, MP_BADARG); - - if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) - return MP_MEM; - - SIGN(mp) = MP_ZPOS; - USED(mp) = 1; - ALLOC(mp) = prec; - - return MP_OKAY; - -} /* end mp_init_size() */ - -/* }}} */ - -/* {{{ mp_init_copy(mp, from) */ - -/* - mp_init_copy(mp, from) - - Initialize mp as an exact copy of from. Returns MP_OKAY if - successful, MP_MEM if memory could not be allocated for the new - structure. - */ - -mp_err mp_init_copy(mp_int *mp, mp_int *from) -{ - ARGCHK(mp != NULL && from != NULL, MP_BADARG); - - if(mp == from) - return MP_OKAY; - - if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); - USED(mp) = USED(from); - ALLOC(mp) = USED(from); - SIGN(mp) = SIGN(from); - - return MP_OKAY; - -} /* end mp_init_copy() */ - -/* }}} */ - -/* {{{ mp_copy(from, to) */ - -/* - mp_copy(from, to) - - Copies the mp_int 'from' to the mp_int 'to'. It is presumed that - 'to' has already been initialized (if not, use mp_init_copy() - instead). If 'from' and 'to' are identical, nothing happens. - */ - -mp_err mp_copy(mp_int *from, mp_int *to) -{ - ARGCHK(from != NULL && to != NULL, MP_BADARG); - - if(from == to) - return MP_OKAY; - - { /* copy */ - mp_digit *tmp; - - /* - If the allocated buffer in 'to' already has enough space to hold - all the used digits of 'from', we'll re-use it to avoid hitting - the memory allocater more than necessary; otherwise, we'd have - to grow anyway, so we just allocate a hunk and make the copy as - usual - */ - if(ALLOC(to) >= USED(from)) { - s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); - s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); - - } else { - if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(from), tmp, USED(from)); - - if(DIGITS(to) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(to), ALLOC(to)); -#endif - s_mp_free(DIGITS(to)); - } - - DIGITS(to) = tmp; - ALLOC(to) = USED(from); - } - - /* Copy the precision and sign from the original */ - USED(to) = USED(from); - SIGN(to) = SIGN(from); - } /* end copy */ - - return MP_OKAY; - -} /* end mp_copy() */ - -/* }}} */ - -/* {{{ mp_exch(mp1, mp2) */ - -/* - mp_exch(mp1, mp2) - - Exchange mp1 and mp2 without allocating any intermediate memory - (well, unless you count the stack space needed for this call and the - locals it creates...). This cannot fail. - */ - -void mp_exch(mp_int *mp1, mp_int *mp2) -{ -#if MP_ARGCHK == 2 - assert(mp1 != NULL && mp2 != NULL); -#else - if(mp1 == NULL || mp2 == NULL) - return; -#endif - - s_mp_exch(mp1, mp2); - -} /* end mp_exch() */ - -/* }}} */ - -/* {{{ mp_clear(mp) */ - -/* - mp_clear(mp) - - Release the storage used by an mp_int, and void its fields so that - if someone calls mp_clear() again for the same int later, we won't - get tollchocked. - */ - -void mp_clear(mp_int *mp) -{ - if(mp == NULL) - return; - - if(DIGITS(mp) != NULL) { -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = NULL; - } - - USED(mp) = 0; - ALLOC(mp) = 0; - -} /* end mp_clear() */ - -/* }}} */ - -/* {{{ mp_clear_array(mp[], count) */ - -void mp_clear_array(mp_int mp[], int count) -{ -// ARGCHK(mp != NULL && count > 0, MP_BADARG); - - while(--count >= 0) - mp_clear(&mp[count]); - -} /* end mp_clear_array() */ - -/* }}} */ - -/* {{{ mp_zero(mp) */ - -/* - mp_zero(mp) - - Set mp to zero. Does not change the allocated size of the structure, - and therefore cannot fail (except on a bad argument, which we ignore) - */ -void mp_zero(mp_int *mp) -{ - if(mp == NULL) - return; - - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - -} /* end mp_zero() */ - -/* }}} */ - -/* {{{ mp_set(mp, d) */ - -void mp_set(mp_int *mp, mp_digit d) -{ - if(mp == NULL) - return; - - mp_zero(mp); - DIGIT(mp, 0) = d; - -} /* end mp_set() */ - -/* }}} */ - -/* {{{ mp_set_int(mp, z) */ - -mp_err mp_set_int(mp_int *mp, long z) -{ - int ix; - unsigned long v = abs(z); - mp_err res; - - ARGCHK(mp != NULL, MP_BADARG); - - mp_zero(mp); - if(z == 0) - return MP_OKAY; /* shortcut for zero */ - - for(ix = sizeof(long) - 1; ix >= 0; ix--) { - -/* --- bug in MSVC [first release] */ - if (ix == -1) break; -/* --- end of fix */ - - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - res = s_mp_add_d(mp, - (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); - if(res != MP_OKAY) - return res; - } - - if(z < 0) - SIGN(mp) = MP_NEG; - - return MP_OKAY; - -} /* end mp_set_int() */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Digit arithmetic */ - -/* {{{ mp_add_d(a, d, b) */ - -/* - mp_add_d(a, d, b) - - Compute the sum b = a + d, for a single digit d. Respects the sign of - its primary addend (single digits are unsigned anyway). - */ - -mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res = MP_OKAY; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_ZPOS) { - res = s_mp_add_d(b, d); - } else if(s_mp_cmp_d(b, d) >= 0) { - res = s_mp_sub_d(b, d); - } else { - SIGN(b) = MP_ZPOS; - - DIGIT(b, 0) = d - DIGIT(b, 0); - } - - return res; - -} /* end mp_add_d() */ - -/* }}} */ - -/* {{{ mp_sub_d(a, d, b) */ - -/* - mp_sub_d(a, d, b) - - Compute the difference b = a - d, for a single digit d. Respects the - sign of its subtrahend (single digits are unsigned anyway). - */ - -mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(SIGN(b) == MP_NEG) { - if((res = s_mp_add_d(b, d)) != MP_OKAY) - return res; - - } else if(s_mp_cmp_d(b, d) >= 0) { - if((res = s_mp_sub_d(b, d)) != MP_OKAY) - return res; - - } else { - mp_neg(b, b); - - DIGIT(b, 0) = d - DIGIT(b, 0); - SIGN(b) = MP_NEG; - } - - if(s_mp_cmp_d(b, 0) == 0) - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sub_d() */ - -/* }}} */ - -/* {{{ mp_mul_d(a, d, b) */ - -/* - mp_mul_d(a, d, b) - - Compute the product b = a * d, for a single digit d. Respects the sign - of its multiplicand (single digits are unsigned anyway) - */ - -mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if(d == 0) { - mp_zero(b); - return MP_OKAY; - } - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - res = s_mp_mul_d(b, d); - - return res; - -} /* end mp_mul_d() */ - -/* }}} */ - -/* {{{ mp_mul_2(a, c) */ - -mp_err mp_mul_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - return s_mp_mul_2(c); - -} /* end mp_mul_2() */ - -/* }}} */ - -/* {{{ mp_div_d(a, d, q, r) */ - -/* - mp_div_d(a, d, q, r) - - Compute the quotient q = a / d and remainder r = a mod d, for a - single digit d. Respects the sign of its divisor (single digits are - unsigned anyway). - */ - -mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) -{ - mp_err res; - mp_digit rem; - int pow; - - ARGCHK(a != NULL, MP_BADARG); - - if(d == 0) - return MP_RANGE; - - /* Shortcut for powers of two ... */ - if((pow = s_mp_ispow2d(d)) >= 0) { - mp_digit mask; - - mask = (1 << pow) - 1; - rem = DIGIT(a, 0) & mask; - - if(q) { - mp_copy(a, q); - s_mp_div_2d(q, (mp_digit)pow); - } - - if(r) - *r = rem; - - return MP_OKAY; - } - - /* - If the quotient is actually going to be returned, we'll try to - avoid hitting the memory allocator by copying the dividend into it - and doing the division there. This can't be any _worse_ than - always copying, and will sometimes be better (since it won't make - another copy) - - If it's not going to be returned, we need to allocate a temporary - to hold the quotient, which will just be discarded. - */ - if(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - res = s_mp_div_d(q, d, &rem); - if(s_mp_cmp_d(q, 0) == MP_EQ) - SIGN(q) = MP_ZPOS; - - } else { - mp_int qp; - - if((res = mp_init_copy(&qp, a)) != MP_OKAY) - return res; - - res = s_mp_div_d(&qp, d, &rem); - if(s_mp_cmp_d(&qp, 0) == 0) - SIGN(&qp) = MP_ZPOS; - - mp_clear(&qp); - } - - if(r) - *r = rem; - - return res; - -} /* end mp_div_d() */ - -/* }}} */ - -/* {{{ mp_div_2(a, c) */ - -/* - mp_div_2(a, c) - - Compute c = a / 2, disregarding the remainder. - */ - -mp_err mp_div_2(mp_int *a, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - s_mp_div_2(c); - - return MP_OKAY; - -} /* end mp_div_2() */ - -/* }}} */ - -/* {{{ mp_expt_d(a, d, b) */ - -mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) -{ - mp_int s, x; - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - DIGIT(&s, 0) = 1; - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - - s_mp_exch(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_expt_d() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Full arithmetic */ - -/* {{{ mp_abs(a, b) */ - -/* - mp_abs(a, b) - - Compute b = |a|. 'a' and 'b' may be identical. - */ - -mp_err mp_abs(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_abs() */ - -/* }}} */ - -/* {{{ mp_neg(a, b) */ - -/* - mp_neg(a, b) - - Compute b = -a. 'a' and 'b' may be identical. - */ - -mp_err mp_neg(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if(s_mp_cmp_d(b, 0) == MP_EQ) - SIGN(b) = MP_ZPOS; - else - SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; - - return MP_OKAY; - -} /* end mp_neg() */ - -/* }}} */ - -/* {{{ mp_add(a, b, c) */ - -/* - mp_add(a, b, c) - - Compute c = a + b. All parameters may be identical. - */ - -mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - int cmp; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ - - /* Commutativity of addition lets us do this in either order, - so we avoid having to use a temporary even if the result - is supposed to replace the output - */ - if(c == b) { - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - } else { - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; - - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ - - /* If the output is going to be clobbered, we will use a temporary - variable; otherwise, we'll do it without touching the memory - allocator at all, if possible - */ - if(c == b) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != a && (res = mp_copy(a, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - - } - - } else if(cmp == 0) { /* different sign, a == b */ - - mp_zero(c); - return MP_OKAY; - - } else { /* different sign: a < b */ - - /* See above... */ - if(c == a) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - - if(c != b && (res = mp_copy(b, c)) != MP_OKAY) - return res; - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; - - } - } - - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_add() */ - -/* }}} */ - -/* {{{ mp_sub(a, b, c) */ - -/* - mp_sub(a, b, c) - - Compute c = a - b. All parameters may be identical. - */ - -mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - int cmp; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(SIGN(a) != SIGN(b)) { - if(c == a) { - if((res = s_mp_add(c, b)) != MP_OKAY) - return res; - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - if((res = s_mp_add(c, a)) != MP_OKAY) - return res; - SIGN(c) = SIGN(a); - } - - } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ - if(c == b) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, a)) != MP_OKAY) - return res; - if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, b)) != MP_OKAY) - return res; - } - - } else if(cmp == 0) { /* Same sign, equal magnitude */ - mp_zero(c); - return MP_OKAY; - - } else { /* Same sign, b > a */ - if(c == a) { - mp_int tmp; - - if((res = mp_init_copy(&tmp, b)) != MP_OKAY) - return res; - - if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - s_mp_exch(&tmp, c); - mp_clear(&tmp); - - } else { - if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) - return res; - - if((res = s_mp_sub(c, a)) != MP_OKAY) - return res; - } - - SIGN(c) = !SIGN(b); - } - - if(USED(c) == 1 && DIGIT(c, 0) == 0) - SIGN(c) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sub() */ - -/* }}} */ - -/* {{{ mp_mul(a, b, c) */ - -/* - mp_mul(a, b, c) - - Compute c = a * b. All parameters may be identical. - */ - -mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_sign sgn; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; - - if(c == b) { - if((res = s_mp_mul(c, a)) != MP_OKAY) - return res; - - } else { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if((res = s_mp_mul(c, b)) != MP_OKAY) - return res; - } - - if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) - SIGN(c) = MP_ZPOS; - else - SIGN(c) = sgn; - - return MP_OKAY; - -} /* end mp_mul() */ - -/* }}} */ - -/* {{{ mp_mul_2d(a, d, c) */ - -/* - mp_mul_2d(a, d, c) - - Compute c = a * 2^d. a may be the same as c. - */ - -mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if(d == 0) - return MP_OKAY; - - return s_mp_mul_2d(c, d); - -} /* end mp_mul() */ - -/* }}} */ - -/* {{{ mp_sqr(a, b) */ - -#if MP_SQUARE -mp_err mp_sqr(mp_int *a, mp_int *b) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if((res = mp_copy(a, b)) != MP_OKAY) - return res; - - if((res = s_mp_sqr(b)) != MP_OKAY) - return res; - - SIGN(b) = MP_ZPOS; - - return MP_OKAY; - -} /* end mp_sqr() */ -#endif - -/* }}} */ - -/* {{{ mp_div(a, b, q, r) */ - -/* - mp_div(a, b, q, r) - - Compute q = a / b and r = a mod b. Input parameters may be re-used - as output parameters. If q or r is NULL, that portion of the - computation will be discarded (although it will still be computed) - - Pay no attention to the hacker behind the curtain. - */ - -mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) -{ - mp_err res; - mp_int qtmp, rtmp; - int cmp; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - if(mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - - /* If a <= b, we can compute the solution without division, and - avoid any memory allocation - */ - if((cmp = s_mp_cmp(a, b)) < 0) { - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - } - - if(q) - mp_zero(q); - - return MP_OKAY; - - } else if(cmp == 0) { - - /* Set quotient to 1, with appropriate sign */ - if(q) { - int qneg = (SIGN(a) != SIGN(b)); - - mp_set(q, 1); - if(qneg) - SIGN(q) = MP_NEG; - } - - if(r) - mp_zero(r); - - return MP_OKAY; - } - - /* If we get here, it means we actually have to do some division */ - - /* Set up some temporaries... */ - if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) - return res; - if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) - goto CLEANUP; - - /* Compute the signs for the output */ - SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ - if(SIGN(a) == SIGN(b)) - SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ - else - SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ - - if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) - SIGN(&qtmp) = MP_ZPOS; - if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) - SIGN(&rtmp) = MP_ZPOS; - - /* Copy output, if it is needed */ - if(q) - s_mp_exch(&qtmp, q); - - if(r) - s_mp_exch(&rtmp, r); - -CLEANUP: - mp_clear(&rtmp); - mp_clear(&qtmp); - - return res; - -} /* end mp_div() */ - -/* }}} */ - -/* {{{ mp_div_2d(a, d, q, r) */ - -mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) -{ - mp_err res; - - ARGCHK(a != NULL, MP_BADARG); - - if(q) { - if((res = mp_copy(a, q)) != MP_OKAY) - return res; - - s_mp_div_2d(q, d); - } - - if(r) { - if((res = mp_copy(a, r)) != MP_OKAY) - return res; - - s_mp_mod_2d(r, d); - } - - return MP_OKAY; - -} /* end mp_div_2d() */ - -/* }}} */ - -/* {{{ mp_expt(a, b, c) */ - -/* - mp_expt(a, b, c) - - Compute c = a ** b, that is, raise a to the b power. Uses a - standard iterative square-and-multiply technique. - */ - -mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int s, x; - mp_err res; - mp_digit d; - int dig, bit; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(b) < 0) - return MP_RANGE; - - if((res = mp_init(&s)) != MP_OKAY) - return res; - - mp_set(&s, 1); - - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - /* Loop over low-order digits in ascending order */ - for(dig = 0; dig < (int)(USED(b) - 1); dig++) { - d = DIGIT(b, dig); - - /* Loop over bits of each non-maximal digit */ - for(bit = 0; bit < (int)DIGIT_BIT; bit++) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - } - - /* Consider now the last digit... */ - d = DIGIT(b, dig); - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - } - - if(mp_iseven(b)) - SIGN(&s) = SIGN(a); - - res = mp_copy(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_expt() */ - -/* }}} */ - -/* {{{ mp_2expt(a, k) */ - -/* Compute a = 2^k */ - -mp_err mp_2expt(mp_int *a, mp_digit k) -{ - ARGCHK(a != NULL, MP_BADARG); - - return s_mp_2expt(a, k); - -} /* end mp_2expt() */ - -/* }}} */ - -/* {{{ mp_mod(a, m, c) */ - -/* - mp_mod(a, m, c) - - Compute c = a (mod m). Result will always be 0 <= c < m. - */ - -mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - int mag; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if(SIGN(m) == MP_NEG) - return MP_RANGE; - - /* - If |a| > m, we need to divide to get the remainder and take the - absolute value. - - If |a| < m, we don't need to do any division, just copy and adjust - the sign (if a is negative). - - If |a| == m, we can simply set the result to zero. - - This order is intended to minimize the average path length of the - comparison chain on common workloads -- the most frequent cases are - that |a| != m, so we do those first. - */ - if((mag = s_mp_cmp(a, m)) > 0) { - if((res = mp_div(a, m, NULL, c)) != MP_OKAY) - return res; - - if(SIGN(c) == MP_NEG) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; - } - - } else if(mag < 0) { - if((res = mp_copy(a, c)) != MP_OKAY) - return res; - - if(mp_cmp_z(a) < 0) { - if((res = mp_add(c, m, c)) != MP_OKAY) - return res; - - } - - } else { - mp_zero(c); - - } - - return MP_OKAY; - -} /* end mp_mod() */ - -/* }}} */ - -/* {{{ mp_mod_d(a, d, c) */ - -/* - mp_mod_d(a, d, c) - - Compute c = a (mod d). Result will always be 0 <= c < d - */ -mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) -{ - mp_err res; - mp_digit rem; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if(s_mp_cmp_d(a, d) > 0) { - if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) - return res; - - } else { - if(SIGN(a) == MP_NEG) - rem = d - DIGIT(a, 0); - else - rem = DIGIT(a, 0); - } - - if(c) - *c = rem; - - return MP_OKAY; - -} /* end mp_mod_d() */ - -/* }}} */ - -/* {{{ mp_sqrt(a, b) */ - -/* - mp_sqrt(a, b) - - Compute the integer square root of a, and store the result in b. - Uses an integer-arithmetic version of Newton's iterative linear - approximation technique to determine this value; the result has the - following two properties: - - b^2 <= a - (b+1)^2 >= a - - It is a range error to pass a negative value. - */ -mp_err mp_sqrt(mp_int *a, mp_int *b) -{ - mp_int x, t; - mp_err res; - - ARGCHK(a != NULL && b != NULL, MP_BADARG); - - /* Cannot take square root of a negative value */ - if(SIGN(a) == MP_NEG) - return MP_RANGE; - - /* Special cases for zero and one, trivial */ - if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) - return mp_copy(a, b); - - /* Initialize the temporaries we'll use below */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - return res; - - /* Compute an initial guess for the iteration as a itself */ - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - for(;;) { - /* t = (x * x) - a */ - mp_copy(&x, &t); /* can't fail, t is big enough for original x */ - if((res = mp_sqr(&t, &t)) != MP_OKAY || - (res = mp_sub(&t, a, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = t / 2x */ - s_mp_mul_2(&x); - if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) - goto CLEANUP; - s_mp_div_2(&x); - - /* Terminate the loop, if the quotient is zero */ - if(mp_cmp_z(&t) == MP_EQ) - break; - - /* x = x - t */ - if((res = mp_sub(&x, &t, &x)) != MP_OKAY) - goto CLEANUP; - - } - - /* Copy result to output parameter */ - mp_sub_d(&x, 1, &x); - s_mp_exch(&x, b); - - CLEANUP: - mp_clear(&x); - X: - mp_clear(&t); - - return res; - -} /* end mp_sqrt() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Modular arithmetic */ - -#if MP_MODARITH -/* {{{ mp_addmod(a, b, m, c) */ - -/* - mp_addmod(a, b, m, c) - - Compute c = (a + b) mod m - */ - -mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_add(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_submod(a, b, m, c) */ - -/* - mp_submod(a, b, m, c) - - Compute c = (a - b) mod m - */ - -mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sub(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_mulmod(a, b, m, c) */ - -/* - mp_mulmod(a, b, m, c) - - Compute c = (a * b) mod m - */ - -mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_mul(a, b, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} - -/* }}} */ - -/* {{{ mp_sqrmod(a, m, c) */ - -#if MP_SQUARE -mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_err res; - - ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); - - if((res = mp_sqr(a, c)) != MP_OKAY) - return res; - if((res = mp_mod(c, m, c)) != MP_OKAY) - return res; - - return MP_OKAY; - -} /* end mp_sqrmod() */ -#endif - -/* }}} */ - -/* shrinks the memory required to store a mp_int if possible */ -mp_err mp_shrink(mp_int *a) -{ - if (a->used != a->alloc) { - if ((a->dp = XREALLOC(a->dp, a->used * sizeof(mp_digit))) == NULL) { - return MP_MEM; - } else { - a->alloc = a->used; - return MP_OKAY; - } - } else { - return MP_OKAY; - } -} - -/* {{{ mp_exptmod(a, b, m, c) */ - -#ifdef MPI_FASTEXPT - -/* computes y == g^x mod p */ -mp_err mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) -{ - mp_int *M, tx, mu, res; - int QQQ, QQ, Q, x, *vals, err; - - /* determine the value of Q */ - x = (USED(X) - 1) * DIGIT_BIT; - Q = DIGIT(X, USED(X)-1); - while (Q) { - ++x; - Q >>= 1; - } - if (x <= 8) { Q = 2; } - else if (x <= 64) { Q = 3; } - else if (x <= 256) { Q = 4; } - else if (x <= 950) { Q = 5; } - else if (x <= 2755) { Q = 6; } - else { Q = 7; } - -#ifdef MPI_FASTEXPT_LOWMEM - if (Q > 5) { - Q = 5; - } -#endif - - /* alloc room for table */ - vals = XCALLOC(sizeof(int), USED(X)*((DIGIT_BIT/Q)+((DIGIT_BIT%Q)?1:0))); - if (vals == NULL) { err = MP_MEM; goto _ERR; } - - M = XCALLOC(sizeof(mp_int), 1<= 0) { - for (QQ = 0; QQ < Q; QQ++) { - if ((err = s_mp_sqr(&res)) != MP_OKAY) { goto _TX; } - if ((err = s_mp_reduce(&res, P, &mu)) != MP_OKAY) { goto _TX; } - } - if (vals[x] != 0) { - if ((err = s_mp_mul(&res, &M[vals[x]])) != MP_OKAY) { goto _TX; } - if ((err = s_mp_reduce(&res, P, &mu)) != MP_OKAY) { goto _TX; } - } - } - s_mp_exch(&res, Y); - - /* free ram */ -_TX: - mp_clear(&tx); -_RES: - mp_clear(&res); -_MU: - mp_clear(&mu); -_M: - for (x = 0; x < (1<>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - } - - /* Now do the last digit... */ - d = *db; - - while(d) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - d >>= 1; - - if((res = s_mp_sqr(&x)) != MP_OKAY) - goto CLEANUP; - if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) - goto CLEANUP; - } - - s_mp_exch(&s, c); - - CLEANUP: - mp_clear(&mu); - MU: - mp_clear(&x); - X: - mp_clear(&s); - - return res; - -} /* end mp_exptmod() */ - -#endif - -/* }}} */ - -/* {{{ mp_exptmod_d(a, d, m, c) */ - -mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) -{ - mp_int s, x; - mp_err res; - - ARGCHK(a != NULL && c != NULL, MP_BADARG); - - if((res = mp_init(&s)) != MP_OKAY) - return res; - if((res = mp_init_copy(&x, a)) != MP_OKAY) - goto X; - - mp_set(&s, 1); - - while(d != 0) { - if(d & 1) { - if((res = s_mp_mul(&s, &x)) != MP_OKAY || - (res = mp_mod(&s, m, &s)) != MP_OKAY) - goto CLEANUP; - } - - d /= 2; - - if((res = s_mp_sqr(&x)) != MP_OKAY || - (res = mp_mod(&x, m, &x)) != MP_OKAY) - goto CLEANUP; - } - - s_mp_exch(&s, c); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&s); - - return res; - -} /* end mp_exptmod_d() */ - -/* }}} */ -#endif /* if MP_MODARITH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Comparison functions */ - -/* {{{ mp_cmp_z(a) */ - -/* - mp_cmp_z(a) - - Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. - */ - -int mp_cmp_z(mp_int *a) -{ - if(SIGN(a) == MP_NEG) - return MP_LT; - else if(USED(a) == 1 && DIGIT(a, 0) == 0) - return MP_EQ; - else - return MP_GT; - -} /* end mp_cmp_z() */ - -/* }}} */ - -/* {{{ mp_cmp_d(a, d) */ - -/* - mp_cmp_d(a, d) - - Compare a <=> d. Returns <0 if a0 if a>d - */ - -int mp_cmp_d(mp_int *a, mp_digit d) -{ - ARGCHK(a != NULL, MP_EQ); - - if(SIGN(a) == MP_NEG) - return MP_LT; - - return s_mp_cmp_d(a, d); - -} /* end mp_cmp_d() */ - -/* }}} */ - -/* {{{ mp_cmp(a, b) */ - -int mp_cmp(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - if(SIGN(a) == SIGN(b)) { - int mag; - - if((mag = s_mp_cmp(a, b)) == MP_EQ) - return MP_EQ; - - if(SIGN(a) == MP_ZPOS) - return mag; - else - return -mag; - - } else if(SIGN(a) == MP_ZPOS) { - return MP_GT; - } else { - return MP_LT; - } - -} /* end mp_cmp() */ - -/* }}} */ - -/* {{{ mp_cmp_mag(a, b) */ - -/* - mp_cmp_mag(a, b) - - Compares |a| <=> |b|, and returns an appropriate comparison result - */ - -int mp_cmp_mag(mp_int *a, mp_int *b) -{ - ARGCHK(a != NULL && b != NULL, MP_EQ); - - return s_mp_cmp(a, b); - -} /* end mp_cmp_mag() */ - -/* }}} */ - -/* {{{ mp_cmp_int(a, z) */ - -/* - This just converts z to an mp_int, and uses the existing comparison - routines. This is sort of inefficient, but it's not clear to me how - frequently this wil get used anyway. For small positive constants, - you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). - */ -int mp_cmp_int(mp_int *a, long z) -{ - mp_int tmp; - int out; - - ARGCHK(a != NULL, MP_EQ); - - mp_init(&tmp); mp_set_int(&tmp, z); - out = mp_cmp(a, &tmp); - mp_clear(&tmp); - - return out; - -} /* end mp_cmp_int() */ - -/* }}} */ - -/* {{{ mp_isodd(a) */ - -/* - mp_isodd(a) - - Returns a true (non-zero) value if a is odd, false (zero) otherwise. - */ -int mp_isodd(mp_int *a) -{ - ARGCHK(a != NULL, 0); - - return (DIGIT(a, 0) & 1); - -} /* end mp_isodd() */ - -/* }}} */ - -/* {{{ mp_iseven(a) */ - -int mp_iseven(mp_int *a) -{ - return !mp_isodd(a); - -} /* end mp_iseven() */ - -/* }}} */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ Number theoretic functions */ - -#if MP_NUMTH -/* {{{ mp_gcd(a, b, c) */ - -/* - Like the old mp_gcd() function, except computes the GCD using the - binary algorithm due to Josef Stein in 1961 (via Knuth). - */ -mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) -{ - mp_err res; - mp_int u, v, t; - mp_size k = 0; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) - return MP_RANGE; - if(mp_cmp_z(a) == MP_EQ) { - return mp_copy(b, c); - } else if(mp_cmp_z(b) == MP_EQ) { - return mp_copy(a, c); - } - - if((res = mp_init(&t)) != MP_OKAY) - return res; - if((res = mp_init_copy(&u, a)) != MP_OKAY) - goto U; - if((res = mp_init_copy(&v, b)) != MP_OKAY) - goto V; - - SIGN(&u) = MP_ZPOS; - SIGN(&v) = MP_ZPOS; - - /* Divide out common factors of 2 until at least 1 of a, b is even */ - while(mp_iseven(&u) && mp_iseven(&v)) { - s_mp_div_2(&u); - s_mp_div_2(&v); - ++k; - } - - /* Initialize t */ - if(mp_isodd(&u)) { - if((res = mp_copy(&v, &t)) != MP_OKAY) - goto CLEANUP; - - /* t = -v */ - if(SIGN(&v) == MP_ZPOS) - SIGN(&t) = MP_NEG; - else - SIGN(&t) = MP_ZPOS; - - } else { - if((res = mp_copy(&u, &t)) != MP_OKAY) - goto CLEANUP; - - } - - for(;;) { - while(mp_iseven(&t)) { - s_mp_div_2(&t); - } - - if(mp_cmp_z(&t) == MP_GT) { - if((res = mp_copy(&t, &u)) != MP_OKAY) - goto CLEANUP; - - } else { - if((res = mp_copy(&t, &v)) != MP_OKAY) - goto CLEANUP; - - /* v = -t */ - if(SIGN(&t) == MP_ZPOS) - SIGN(&v) = MP_NEG; - else - SIGN(&v) = MP_ZPOS; - } - - if((res = mp_sub(&u, &v, &t)) != MP_OKAY) - goto CLEANUP; - - if(s_mp_cmp_d(&t, 0) == MP_EQ) - break; - } - - s_mp_2expt(&v, (mp_digit)k); /* v = 2^k */ - res = mp_mul(&u, &v, c); /* c = u * v */ - - CLEANUP: - mp_clear(&v); - V: - mp_clear(&u); - U: - mp_clear(&t); - - return res; - -} /* end mp_bgcd() */ - -/* }}} */ - -/* {{{ mp_lcm(a, b, c) */ - -/* We compute the least common multiple using the rule: - - ab = [a, b](a, b) - - ... by computing the product, and dividing out the gcd. - */ - -mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int gcd, prod; - mp_err res; - - ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); - - /* Set up temporaries */ - if((res = mp_init(&gcd)) != MP_OKAY) - return res; - if((res = mp_init(&prod)) != MP_OKAY) - goto GCD; - - if((res = mp_mul(a, b, &prod)) != MP_OKAY) - goto CLEANUP; - if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) - goto CLEANUP; - - res = mp_div(&prod, &gcd, c, NULL); - - CLEANUP: - mp_clear(&prod); - GCD: - mp_clear(&gcd); - - return res; - -} /* end mp_lcm() */ - -/* }}} */ - -/* {{{ mp_xgcd(a, b, g, x, y) */ - -/* - mp_xgcd(a, b, g, x, y) - - Compute g = (a, b) and values x and y satisfying Bezout's identity - (that is, ax + by = g). This uses the extended binary GCD algorithm - based on the Stein algorithm used for mp_gcd() - */ - -mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) -{ - mp_int gx, xc, yc, u, v, A, B, C, D; - mp_int *clean[9]; - mp_err res; - int last = -1; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Initialize all these variables we need */ - if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; - clean[++last] = &u; - if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; - clean[++last] = &v; - if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; - clean[++last] = &gx; - if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; - clean[++last] = &A; - if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; - clean[++last] = &B; - if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; - clean[++last] = &C; - if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; - clean[++last] = &D; - if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; - clean[++last] = &xc; - mp_abs(&xc, &xc); - if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; - clean[++last] = &yc; - mp_abs(&yc, &yc); - - mp_set(&gx, 1); - - /* Divide by two until at least one of them is even */ - while(mp_iseven(&xc) && mp_iseven(&yc)) { - s_mp_div_2(&xc); - s_mp_div_2(&yc); - if((res = s_mp_mul_2(&gx)) != MP_OKAY) - goto CLEANUP; - } - - mp_copy(&xc, &u); - mp_copy(&yc, &v); - mp_set(&A, 1); mp_set(&D, 1); - - /* Loop through binary GCD algorithm */ - for(;;) { - while(mp_iseven(&u)) { - s_mp_div_2(&u); - - if(mp_iseven(&A) && mp_iseven(&B)) { - s_mp_div_2(&A); s_mp_div_2(&B); - } else { - if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&A); - if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&B); - } - } - - while(mp_iseven(&v)) { - s_mp_div_2(&v); - - if(mp_iseven(&C) && mp_iseven(&D)) { - s_mp_div_2(&C); s_mp_div_2(&D); - } else { - if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&C); - if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; - s_mp_div_2(&D); - } - } - - if(mp_cmp(&u, &v) >= 0) { - if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; - - } else { - if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; - if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; - - } - - /* If we're done, copy results to output */ - if(mp_cmp_z(&u) == 0) { - if(x) - if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; - - if(y) - if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; - - if(g) - if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; - - break; - } - } - - CLEANUP: - while(last >= 0) - mp_clear(clean[last--]); - - return res; - -} /* end mp_xgcd() */ - -/* }}} */ - -/* {{{ mp_invmod(a, m, c) */ - -/* - mp_invmod(a, m, c) - - Compute c = a^-1 (mod m), if there is an inverse for a (mod m). - This is equivalent to the question of whether (a, m) = 1. If not, - MP_UNDEF is returned, and there is no inverse. - */ - -mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) -{ - mp_int g, x; - mp_err res; - - ARGCHK(a && m && c, MP_BADARG); - - if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) - return MP_RANGE; - - if((res = mp_init(&g)) != MP_OKAY) - return res; - if((res = mp_init(&x)) != MP_OKAY) - goto X; - - if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) - goto CLEANUP; - - if(mp_cmp_d(&g, 1) != MP_EQ) { - res = MP_UNDEF; - goto CLEANUP; - } - - res = mp_mod(&x, m, c); - SIGN(c) = SIGN(a); - -CLEANUP: - mp_clear(&x); -X: - mp_clear(&g); - - return res; - -} /* end mp_invmod() */ - -/* }}} */ -#endif /* if MP_NUMTH */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ mp_print(mp, ofp) */ - -#if MP_IOFUNC -/* - mp_print(mp, ofp) - - Print a textual representation of the given mp_int on the output - stream 'ofp'. Output is generated using the internal radix. - */ - -void mp_print(mp_int *mp, FILE *ofp) -{ - int ix; - - if(mp == NULL || ofp == NULL) - return; - - fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); - - for(ix = USED(mp) - 1; ix >= 0; ix--) { - fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); - } - -} /* end mp_print() */ - -#endif /* if MP_IOFUNC */ - -/* }}} */ - -/*------------------------------------------------------------------------*/ -/* {{{ More I/O Functions */ - -/* {{{ mp_read_signed_bin(mp, str, len) */ - -/* - mp_read_signed_bin(mp, str, len) - - Read in a raw value (base 256) into the given mp_int - */ - -mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) -{ - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { - /* Get sign from first byte */ - if(str[0]) - SIGN(mp) = MP_NEG; - else - SIGN(mp) = MP_ZPOS; - } - - return res; - -} /* end mp_read_signed_bin() */ - -/* }}} */ - -/* {{{ mp_signed_bin_size(mp) */ - -int mp_signed_bin_size(mp_int *mp) -{ - ARGCHK(mp != NULL, 0); - - return mp_unsigned_bin_size(mp) + 1; - -} /* end mp_signed_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_signed_bin(mp, str) */ - -mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) -{ - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ - str[0] = (char)SIGN(mp); - - return mp_to_unsigned_bin(mp, str + 1); - -} /* end mp_to_signed_bin() */ - -/* }}} */ - -/* {{{ mp_read_unsigned_bin(mp, str, len) */ - -/* - mp_read_unsigned_bin(mp, str, len) - - Read in an unsigned value (base 256) into the given mp_int - */ - -mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) -{ - int ix; - mp_err res; - - ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); - - mp_zero(mp); - - for(ix = 0; ix < len; ix++) { - if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) - return res; - - if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) - return res; - } - - return MP_OKAY; - -} /* end mp_read_unsigned_bin() */ - -/* }}} */ - -/* {{{ mp_unsigned_bin_size(mp) */ - -int mp_unsigned_bin_size(mp_int *mp) -{ - mp_digit topdig; - int count; - - ARGCHK(mp != NULL, 0); - - /* Special case for the value zero */ - if(USED(mp) == 1 && DIGIT(mp, 0) == 0) - return 1; - - count = (USED(mp) - 1) * sizeof(mp_digit); - topdig = DIGIT(mp, USED(mp) - 1); - - while(topdig != 0) { - ++count; - topdig >>= CHAR_BIT; - } - - return count; - -} /* end mp_unsigned_bin_size() */ - -/* }}} */ - -/* {{{ mp_to_unsigned_bin(mp, str) */ - -mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) -{ - mp_digit *dp, *end, d; - unsigned char *spos; - - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - - dp = DIGITS(mp); - end = dp + USED(mp) - 1; - spos = str; - - /* Special case for zero, quick test */ - if(dp == end && *dp == 0) { - *str = '\0'; - return MP_OKAY; - } - - /* Generate digits in reverse order */ - while(dp < end) { - int ix; - - d = *dp; - for(ix = 0; ix < (int)sizeof(mp_digit); ++ix) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; - } - - ++dp; - } - - /* Now handle last digit specially, high order zeroes are not written */ - d = *end; - while(d != 0) { - *spos = d & UCHAR_MAX; - d >>= CHAR_BIT; - ++spos; - } - - /* Reverse everything to get digits in the correct order */ - while(--spos > str) { - unsigned char t = *str; - *str = *spos; - *spos = t; - - ++str; - } - - return MP_OKAY; - -} /* end mp_to_unsigned_bin() */ - -/* }}} */ - -/* {{{ mp_count_bits(mp) */ - -int mp_count_bits(mp_int *mp) -{ - int len; - mp_digit d; - - ARGCHK(mp != NULL, MP_BADARG); - - len = DIGIT_BIT * (USED(mp) - 1); - d = DIGIT(mp, USED(mp) - 1); - - while(d != 0) { - ++len; - d >>= 1; - } - - return len; - -} /* end mp_count_bits() */ - -/* }}} */ - -/* {{{ mp_read_radix(mp, str, radix) */ - -/* - mp_read_radix(mp, str, radix) - - Read an integer from the given string, and set mp to the resulting - value. The input is presumed to be in base 10. Leading non-digit - characters are ignored, and the function reads until a non-digit - character or the end of the string. - */ - -mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) -{ - int ix = 0, val = 0; - mp_err res; - mp_sign sig = MP_ZPOS; - - ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, - MP_BADARG); - - mp_zero(mp); - - /* Skip leading non-digit characters until a digit or '-' or '+' */ - while(str[ix] && - (s_mp_tovalue(str[ix], radix) < 0) && - str[ix] != '-' && - str[ix] != '+') { - ++ix; - } - - if(str[ix] == '-') { - sig = MP_NEG; - ++ix; - } else if(str[ix] == '+') { - sig = MP_ZPOS; /* this is the default anyway... */ - ++ix; - } - - while((val = s_mp_tovalue(str[ix], radix)) >= 0) { - if((res = s_mp_mul_d(mp, (mp_digit)radix)) != MP_OKAY) - return res; - if((res = s_mp_add_d(mp, (mp_digit)val)) != MP_OKAY) - return res; - ++ix; - } - - if(s_mp_cmp_d(mp, 0) == MP_EQ) - SIGN(mp) = MP_ZPOS; - else - SIGN(mp) = sig; - - return MP_OKAY; - -} /* end mp_read_radix() */ - -/* }}} */ - -/* {{{ mp_radix_size(mp, radix) */ - -int mp_radix_size(mp_int *mp, int radix) -{ - int len; - ARGCHK(mp != NULL, 0); - - len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ - - if(mp_cmp_z(mp) < 0) - ++len; /* for sign */ - - return len; - -} /* end mp_radix_size() */ - -/* }}} */ - -/* {{{ mp_value_radix_size(num, qty, radix) */ - -/* num = number of digits - qty = number of bits per digit - radix = target base - - Return the number of digits in the specified radix that would be - needed to express 'num' digits of 'qty' bits each. - */ -int mp_value_radix_size(int num, int qty, int radix) -{ - ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); - - return s_mp_outlen(num * qty, radix); - -} /* end mp_value_radix_size() */ - -/* }}} */ - -/* {{{ mp_toradix(mp, str, radix) */ - -mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) -{ - int ix, pos = 0; - - ARGCHK(mp != NULL && str != NULL, MP_BADARG); - ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); - - if(mp_cmp_z(mp) == MP_EQ) { - str[0] = '0'; - str[1] = '\0'; - } else { - mp_err res; - mp_int tmp; - mp_sign sgn; - mp_digit rem, rdx = (mp_digit)radix; - char ch; - - if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) - return res; - - /* Save sign for later, and take absolute value */ - sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; - - /* Generate output digits in reverse order */ - while(mp_cmp_z(&tmp) != 0) { - if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - /* Generate digits, use capital letters */ - ch = s_mp_todigit(rem, radix, 0); - - str[pos++] = ch; - } - - /* Add - sign if original value was negative */ - if(sgn == MP_NEG) - str[pos++] = '-'; - - /* Add trailing NUL to end the string */ - str[pos--] = '\0'; - - /* Reverse the digits and sign indicator */ - ix = 0; - while(ix < pos) { - char tmp = str[ix]; - - str[ix] = str[pos]; - str[pos] = tmp; - ++ix; - --pos; - } - - mp_clear(&tmp); - } - - return MP_OKAY; - -} /* end mp_toradix() */ - -/* }}} */ - -/* {{{ mp_char2value(ch, r) */ - -int mp_char2value(char ch, int r) -{ - return s_mp_tovalue(ch, r); - -} /* end mp_tovalue() */ - -/* }}} */ - -/* }}} */ - -/* {{{ mp_strerror(ec) */ - -/* - mp_strerror(ec) - - Return a string describing the meaning of error code 'ec'. The - string returned is allocated in static memory, so the caller should - not attempt to modify or free the memory associated with this - string. - */ -const char *mp_strerror(mp_err ec) -{ - int aec = (ec < 0) ? -ec : ec; - - /* Code values are negative, so the senses of these comparisons - are accurate */ - if(ec < MP_LAST_CODE || ec > MP_OKAY) { - return mp_err_string[0]; /* unknown error code */ - } else { - return mp_err_string[aec + 1]; - } - -} /* end mp_strerror() */ - -/* }}} */ - -/*========================================================================*/ -/*------------------------------------------------------------------------*/ -/* Static function definitions (internal use only) */ - -/* {{{ Memory management */ - -/* {{{ s_mp_grow(mp, min) */ - -/* Make sure there are at least 'min' digits allocated to mp */ -static mp_err s_mp_grow(mp_int *mp, mp_size min) -{ - if(min > ALLOC(mp)) { - mp_digit *tmp; - - /* Set min to next nearest default precision block size */ - min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; - - if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) - return MP_MEM; - - s_mp_copy(DIGITS(mp), tmp, USED(mp)); - -#if MP_CRYPTO - s_mp_setz(DIGITS(mp), ALLOC(mp)); -#endif - s_mp_free(DIGITS(mp)); - DIGITS(mp) = tmp; - ALLOC(mp) = min; - } - - return MP_OKAY; - -} /* end s_mp_grow() */ - -/* }}} */ - -/* {{{ s_mp_pad(mp, min) */ - -/* Make sure the used size of mp is at least 'min', growing if needed */ -static mp_err s_mp_pad(mp_int *mp, mp_size min) -{ - if(min > USED(mp)) { - mp_err res; - - /* Make sure there is room to increase precision */ - if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) - return res; - - /* Increase precision; should already be 0-filled */ - USED(mp) = min; - } - - return MP_OKAY; - -} /* end s_mp_pad() */ - -/* }}} */ - -/* {{{ s_mp_setz(dp, count) */ - -#if MP_MACRO == 0 -/* Set 'count' digits pointed to by dp to be zeroes */ -void s_mp_setz(mp_digit *dp, mp_size count) -{ -#if MP_MEMSET == 0 - int ix; - - for(ix = 0; ix < count; ix++) - dp[ix] = 0; -#else - memset(dp, 0, count * sizeof(mp_digit)); -#endif - -} /* end s_mp_setz() */ -#endif - -/* }}} */ - -/* {{{ s_mp_copy(sp, dp, count) */ - -#if MP_MACRO == 0 -/* Copy 'count' digits from sp to dp */ -void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) -{ -#if MP_MEMCPY == 0 - int ix; - - for(ix = 0; ix < count; ix++) - dp[ix] = sp[ix]; -#else - memcpy(dp, sp, count * sizeof(mp_digit)); -#endif - -} /* end s_mp_copy() */ -#endif - -/* }}} */ - -/* {{{ s_mp_alloc(nb, ni) */ - -#if MP_MACRO == 0 -/* Allocate ni records of nb bytes each, and return a pointer to that */ -void *s_mp_alloc(size_t nb, size_t ni) -{ - return XCALLOC(nb, ni); - -} /* end s_mp_alloc() */ -#endif - -/* }}} */ - -/* {{{ s_mp_free(ptr) */ - -#if MP_MACRO == 0 -/* Free the memory pointed to by ptr */ -void s_mp_free(void *ptr) -{ - if(ptr) - XFREE(ptr); - -} /* end s_mp_free() */ -#endif - -/* }}} */ - -/* {{{ s_mp_clamp(mp) */ - -/* Remove leading zeroes from the given value */ -void s_mp_clamp(mp_int *mp) -{ - mp_size du = USED(mp); - mp_digit *zp = DIGITS(mp) + du - 1; - - while(du > 1 && !*zp--) - --du; - - USED(mp) = du; - -} /* end s_mp_clamp() */ - - -/* }}} */ - -/* {{{ s_mp_exch(a, b) */ - -/* Exchange the data for a and b; (b, a) = (a, b) */ -void s_mp_exch(mp_int *a, mp_int *b) -{ - mp_int tmp; - - tmp = *a; - *a = *b; - *b = tmp; - -} /* end s_mp_exch() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Arithmetic helpers */ - -/* {{{ s_mp_lshd(mp, p) */ - -/* - Shift mp leftward by p digits, growing if needed, and zero-filling - the in-shifted digits at the right end. This is a convenient - alternative to multiplication by powers of the radix - */ - -static mp_err s_mp_lshd(mp_int *mp, mp_size p) -{ - mp_err res; - mp_size pos; - mp_digit *dp; - int ix; - - if(p == 0) - return MP_OKAY; - - if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) - return res; - - pos = USED(mp) - 1; - dp = DIGITS(mp); - - /* Shift all the significant figures over as needed */ - for(ix = pos - p; ix >= 0; ix--) - dp[ix + p] = dp[ix]; - - /* Fill the bottom digits with zeroes */ - for(ix = 0; ix < (int)p; ix++) - dp[ix] = 0; - - return MP_OKAY; - -} /* end s_mp_lshd() */ - -/* }}} */ - -/* {{{ s_mp_rshd(mp, p) */ - -/* - Shift mp rightward by p digits. Maintains the invariant that - digits above the precision are all zero. Digits shifted off the - end are lost. Cannot fail. - */ - -void s_mp_rshd(mp_int *mp, mp_size p) -{ - mp_size ix; - mp_digit *dp; - - if(p == 0) - return; - - /* Shortcut when all digits are to be shifted off */ - if(p >= USED(mp)) { - s_mp_setz(DIGITS(mp), ALLOC(mp)); - USED(mp) = 1; - SIGN(mp) = MP_ZPOS; - return; - } - - /* Shift all the significant figures over as needed */ - dp = DIGITS(mp); - for(ix = p; ix < USED(mp); ix++) - dp[ix - p] = dp[ix]; - - - /* Fill the top digits with zeroes */ - - ix -= p; - while(ix < USED(mp)) - dp[ix++] = 0; - - /* Strip off any leading zeroes */ - s_mp_clamp(mp); - -} /* end s_mp_rshd() */ - -/* }}} */ - -/* {{{ s_mp_div_2(mp) */ - -/* Divide by two -- take advantage of radix properties to do it fast */ -void s_mp_div_2(mp_int *mp) -{ - s_mp_div_2d(mp, 1); - -} /* end s_mp_div_2() */ - -/* }}} */ - -/* {{{ s_mp_mul_2(mp) */ - -static mp_err s_mp_mul_2(mp_int *mp) -{ - int ix; - mp_digit kin = 0, kout, *dp = DIGITS(mp); - mp_err res; - - /* Shift digits leftward by 1 bit */ - for(ix = 0; ix < (int)USED(mp); ix++) { - kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; - dp[ix] = (dp[ix] << 1) | kin; - - kin = kout; - } - - /* Deal with rollover from last digit */ - if(kin) { - if(ix >= (int)ALLOC(mp)) { - if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) - return res; - dp = DIGITS(mp); - } - - dp[ix] = kin; - USED(mp) += 1; - } - - return MP_OKAY; - -} /* end s_mp_mul_2() */ - -/* }}} */ - -/* {{{ s_mp_mod_2d(mp, d) */ - -/* - Remainder the integer by 2^d, where d is a number of bits. This - amounts to a bitwise AND of the value, and does not require the full - division code - */ -void s_mp_mod_2d(mp_int *mp, mp_digit d) -{ - unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); - unsigned int ix; - mp_digit dmask, *dp = DIGITS(mp); - - if(ndig >= USED(mp)) - return; - - /* Flush all the bits above 2^d in its digit */ - dmask = (1 << nbit) - 1; - dp[ndig] &= dmask; - - /* Flush all digits above the one with 2^d in it */ - for(ix = ndig + 1; ix < USED(mp); ix++) - dp[ix] = 0; - - s_mp_clamp(mp); -} /* end s_mp_mod_2d() */ - -/* }}} */ - -/* {{{ s_mp_mul_2d(mp, d) */ - -/* - Multiply by the integer 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full multiplication code. - */ -static mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) -{ - mp_err res; - mp_digit save, next, mask, *dp; - mp_size used; - int ix; - - if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) - return res; - - dp = DIGITS(mp); used = USED(mp); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - /* If the shift requires another digit, make sure we've got one to - work with */ - if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { - if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) - return res; - dp = DIGITS(mp); - } - - /* Do the shifting... */ - save = 0; - for(ix = 0; ix < (int)used; ix++) { - next = (dp[ix] >> (DIGIT_BIT - d)) & mask; - dp[ix] = (dp[ix] << d) | save; - save = next; - } - - /* If, at this point, we have a nonzero carryout into the next - digit, we'll increase the size by one digit, and store it... - */ - if(save) { - dp[used] = save; - USED(mp) += 1; - } - - s_mp_clamp(mp); - return MP_OKAY; - -} /* end s_mp_mul_2d() */ - -/* }}} */ - -/* {{{ s_mp_div_2d(mp, d) */ - -/* - Divide the integer by 2^d, where d is a number of bits. This - amounts to a bitwise shift of the value, and does not require the - full division code (used in Barrett reduction, see below) - */ -void s_mp_div_2d(mp_int *mp, mp_digit d) -{ - int ix; - mp_digit save, next, mask, *dp = DIGITS(mp); - - s_mp_rshd(mp, d / DIGIT_BIT); - d %= DIGIT_BIT; - - mask = (1 << d) - 1; - - save = 0; - for(ix = USED(mp) - 1; ix >= 0; ix--) { - next = dp[ix] & mask; - dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); - save = next; - } - - s_mp_clamp(mp); - -} /* end s_mp_div_2d() */ - -/* }}} */ - -/* {{{ s_mp_norm(a, b) */ - -/* - s_mp_norm(a, b) - - Normalize a and b for division, where b is the divisor. In order - that we might make good guesses for quotient digits, we want the - leading digit of b to be at least half the radix, which we - accomplish by multiplying a and b by a constant. This constant is - returned (so that it can be divided back out of the remainder at the - end of the division process). - - We multiply by the smallest power of 2 that gives us a leading digit - at least half the radix. By choosing a power of 2, we simplify the - multiplication and division steps to simple shifts. - */ -mp_digit s_mp_norm(mp_int *a, mp_int *b) -{ - mp_digit t, d = 0; - - t = DIGIT(b, USED(b) - 1); - while(t < (RADIX / 2)) { - t <<= 1; - ++d; - } - - if(d != 0) { - s_mp_mul_2d(a, d); - s_mp_mul_2d(b, d); - } - - return d; - -} /* end s_mp_norm() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive digit arithmetic */ - -/* {{{ s_mp_add_d(mp, d) */ - -/* Add d to |mp| in place */ -static mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ -{ - mp_word w, k = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - w = dp[0] + d; - dp[0] = ACCUM(w); - k = CARRYOUT(w); - - while(ix < used && k) { - w = dp[ix] + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - ++ix; - } - - if(k != 0) { - mp_err res; - - if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) - return res; - - DIGIT(mp, ix) = k; - } - - return MP_OKAY; - -} /* end s_mp_add_d() */ - -/* }}} */ - -/* {{{ s_mp_sub_d(mp, d) */ - -/* Subtract d from |mp| in place, assumes |mp| > d */ -static mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ -{ - mp_word w, b = 0; - mp_size ix = 1, used = USED(mp); - mp_digit *dp = DIGITS(mp); - - /* Compute initial subtraction */ - w = (RADIX + dp[0]) - d; - b = CARRYOUT(w) ? 0 : 1; - dp[0] = ACCUM(w); - - /* Propagate borrows leftward */ - while(b && ix < used) { - w = (RADIX + dp[ix]) - b; - b = CARRYOUT(w) ? 0 : 1; - dp[ix] = ACCUM(w); - ++ix; - } - - /* Remove leading zeroes */ - s_mp_clamp(mp); - - /* If we have a borrow out, it's a violation of the input invariant */ - if(b) - return MP_RANGE; - else - return MP_OKAY; - -} /* end s_mp_sub_d() */ - -/* }}} */ - -/* {{{ s_mp_mul_d(a, d) */ - -/* Compute a = a * d, single digit multiplication */ -static mp_err s_mp_mul_d(mp_int *a, mp_digit d) -{ - mp_word w, k = 0; - mp_size ix, max; - mp_err res; - mp_digit *dp = DIGITS(a); - - /* - Single-digit multiplication will increase the precision of the - output by at most one digit. However, we can detect when this - will happen -- if the high-order digit of a, times d, gives a - two-digit result, then the precision of the result will increase; - otherwise it won't. We use this fact to avoid calling s_mp_pad() - unless absolutely necessary. - */ - max = USED(a); - w = dp[max - 1] * d; - if(CARRYOUT(w) != 0) { - if((res = s_mp_pad(a, max + 1)) != MP_OKAY) - return res; - dp = DIGITS(a); - } - - for(ix = 0; ix < max; ix++) { - w = (dp[ix] * d) + k; - dp[ix] = ACCUM(w); - k = CARRYOUT(w); - } - - /* If there is a precision increase, take care of it here; the above - test guarantees we have enough storage to do this safely. - */ - if(k) { - dp[max] = k; - USED(a) = max + 1; - } - - s_mp_clamp(a); - - return MP_OKAY; - -} /* end s_mp_mul_d() */ - -/* }}} */ - -/* {{{ s_mp_div_d(mp, d, r) */ - -/* - s_mp_div_d(mp, d, r) - - Compute the quotient mp = mp / d and remainder r = mp mod d, for a - single digit d. If r is null, the remainder will be discarded. - */ - -static mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) -{ - mp_word w = 0, t; - mp_int quot; - mp_err res; - mp_digit *dp = DIGITS(mp), *qp; - int ix; - - if(d == 0) - return MP_RANGE; - - /* Make room for the quotient */ - if((res = mp_init_size(", USED(mp))) != MP_OKAY) - return res; - - USED(") = USED(mp); /* so clamping will work below */ - qp = DIGITS("); - - /* Divide without subtraction */ - for(ix = USED(mp) - 1; ix >= 0; ix--) { - w = (w << DIGIT_BIT) | dp[ix]; - - if(w >= d) { - t = w / d; - w = w % d; - } else { - t = 0; - } - - qp[ix] = t; - } - - /* Deliver the remainder, if desired */ - if(r) - *r = w; - - s_mp_clamp("); - mp_exch(", mp); - mp_clear("); - - return MP_OKAY; - -} /* end s_mp_div_d() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive full arithmetic */ - -/* {{{ s_mp_add(a, b) */ - -/* Compute a = |a| + |b| */ -static mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - mp_err res; - - /* Make sure a has enough precision for the output value */ - if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) - return res; - - /* - Add up all digits up to the precision of b. If b had initially - the same precision as a, or greater, we took care of it by the - padding step above, so there is no problem. If b had initially - less precision, we'll have to make sure the carry out is duly - propagated upward among the higher-order digits of the sum. - */ - pa = DIGITS(a); - pb = DIGITS(b); - for(ix = 0; ix < used; ++ix) { - w += *pa + *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - } - - /* If we run out of 'b' digits before we're actually done, make - sure the carries get propagated upward... - */ - used = USED(a); - while(w && ix < used) { - w += *pa; - *pa++ = ACCUM(w); - w = CARRYOUT(w); - ++ix; - } - - /* If there's an overall carry out, increase precision and include - it. We could have done this initially, but why touch the memory - allocator unless we're sure we have to? - */ - if(w) { - if((res = s_mp_pad(a, used + 1)) != MP_OKAY) - return res; - - DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ - } - - return MP_OKAY; - -} /* end s_mp_add() */ - -/* }}} */ - -/* {{{ s_mp_sub(a, b) */ - -/* Compute a = |a| - |b|, assumes |a| >= |b| */ -static mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ -{ - mp_word w = 0; - mp_digit *pa, *pb; - mp_size ix, used = USED(b); - - /* - Subtract and propagate borrow. Up to the precision of b, this - accounts for the digits of b; after that, we just make sure the - carries get to the right place. This saves having to pad b out to - the precision of a just to make the loops work right... - */ - pa = DIGITS(a); - pb = DIGITS(b); - - for(ix = 0; ix < used; ++ix) { - w = (RADIX + *pa) - w - *pb++; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - } - - used = USED(a); - while(ix < used) { - w = RADIX + *pa - w; - *pa++ = ACCUM(w); - w = CARRYOUT(w) ? 0 : 1; - ++ix; - } - - /* Clobber any leading zeroes we created */ - s_mp_clamp(a); - - /* - If there was a borrow out, then |b| > |a| in violation - of our input invariant. We've already done the work, - but we'll at least complain about it... - */ - if(w) - return MP_RANGE; - else - return MP_OKAY; - -} /* end s_mp_sub() */ - -/* }}} */ - -/* {{{ s_mp_mul(a, b) */ - -/* Compute a = |a| * |b| */ -static mp_err s_mp_mul(mp_int *a, mp_int *b) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, ua = USED(a), ub = USED(b); - mp_digit *pa, *pb, *pt, *pbt; - - if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) - return res; - - /* This has the effect of left-padding with zeroes... */ - USED(&tmp) = ua + ub; - - /* We're going to need the base value each iteration */ - pbt = DIGITS(&tmp); - - /* Outer loop: Digits of b */ - - pb = DIGITS(b); - for(ix = 0; ix < ub; ++ix, ++pb) { - if(*pb == 0) - continue; - - /* Inner product: Digits of a */ - pa = DIGITS(a); - for(jx = 0; jx < ua; ++jx, ++pa) { - pt = pbt + ix + jx; - w = *pb * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - - pbt[ix + jx] = k; - k = 0; - } - - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_mul() */ - -/* Compute a = |a| * |b| max of digs digits */ -static mp_err s_mp_mul_dig(mp_int *a, mp_int *b, int digs) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, ua = USED(a), ub = USED(b); - mp_digit *pa, *pb, *pt, *pbt; - - if((res = mp_init_size(&tmp, digs+1)) != MP_OKAY) - return res; - - /* This has the effect of left-padding with zeroes... */ - USED(&tmp) = digs+1; - - /* We're going to need the base value each iteration */ - pbt = DIGITS(&tmp); - - /* Outer loop: Digits of b */ - - ub = MIN(digs, (int)ub); - ua = MIN(digs, (int)ua); - - pb = DIGITS(b); - for(ix = 0; ix < ub; ++ix, ++pb) { - if(*pb == 0) - continue; - - /* Inner product: Digits of a */ - pa = DIGITS(a); - for(jx = 0; jx < ua; ++jx, ++pa) { - if ((int)(ix+jx) > digs) { break; } - pt = pbt + ix + jx; - w = *pb * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - if ((int)(ix + jx) < digs) { - pbt[ix + jx] = k; - } - k = 0; - } - - USED(&tmp) = digs; - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_mul() */ - -/* }}} */ - -/* {{{ s_mp_kmul(a, b, out, len) */ - -#if 0 -void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) -{ - mp_word w, k = 0; - mp_size ix, jx; - mp_digit *pa, *pt; - - for(ix = 0; ix < len; ++ix, ++b) { - if(*b == 0) - continue; - - pa = a; - for(jx = 0; jx < len; ++jx, ++pa) { - pt = out + ix + jx; - w = *b * *pa + k + *pt; - *pt = ACCUM(w); - k = CARRYOUT(w); - } - - out[ix + jx] = k; - k = 0; - } - -} /* end s_mp_kmul() */ -#endif - -/* }}} */ - -/* {{{ s_mp_sqr(a) */ - -/* - Computes the square of a, in place. This can be done more - efficiently than a general multiplication, because many of the - computation steps are redundant when squaring. The inner product - step is a bit more complicated, but we save a fair number of - iterations of the multiplication loop. - */ -#if MP_SQUARE -static mp_err s_mp_sqr(mp_int *a) -{ - mp_word w, k = 0; - mp_int tmp; - mp_err res; - mp_size ix, jx, kx, used = USED(a); - mp_digit *pa1, *pa2, *pt, *pbt; - - if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) - return res; - - /* Left-pad with zeroes */ - USED(&tmp) = 2 * used; - - /* We need the base value each time through the loop */ - pbt = DIGITS(&tmp); - - pa1 = DIGITS(a); - for(ix = 0; ix < used; ++ix, ++pa1) { - if(*pa1 == 0) - continue; - - w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); - - pbt[ix + ix] = ACCUM(w); - k = CARRYOUT(w); - - /* - The inner product is computed as: - - (C, S) = t[i,j] + 2 a[i] a[j] + C - - This can overflow what can be represented in an mp_word, and - since C arithmetic does not provide any way to check for - overflow, we have to check explicitly for overflow conditions - before they happen. - */ - for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { - mp_word u = 0, v; - - /* Store this in a temporary to avoid indirections later */ - pt = pbt + ix + jx; - - /* Compute the multiplicative step */ - w = *pa1 * *pa2; - - /* If w is more than half MP_WORD_MAX, the doubling will - overflow, and we need to record a carry out into the next - word */ - u = (w >> (MP_WORD_BIT - 1)) & 1; - - /* Double what we've got, overflow will be ignored as defined - for C arithmetic (we've already noted if it is to occur) - */ - w *= 2; - - /* Compute the additive step */ - v = *pt + k; - - /* If we do not already have an overflow carry, check to see - if the addition will cause one, and set the carry out if so - */ - u |= ((MP_WORD_MAX - v) < w); - - /* Add in the rest, again ignoring overflow */ - w += v; - - /* Set the i,j digit of the output */ - *pt = ACCUM(w); - - /* Save carry information for the next iteration of the loop. - This is why k must be an mp_word, instead of an mp_digit */ - k = CARRYOUT(w) | (u << DIGIT_BIT); - - } /* for(jx ...) */ - - /* Set the last digit in the cycle and reset the carry */ - k = DIGIT(&tmp, ix + jx) + k; - pbt[ix + jx] = ACCUM(k); - k = CARRYOUT(k); - - /* If we are carrying out, propagate the carry to the next digit - in the output. This may cascade, so we have to be somewhat - circumspect -- but we will have enough precision in the output - that we won't overflow - */ - kx = 1; - while(k) { - k = pbt[ix + jx + kx] + 1; - pbt[ix + jx + kx] = ACCUM(k); - k = CARRYOUT(k); - ++kx; - } - } /* for(ix ...) */ - - s_mp_clamp(&tmp); - s_mp_exch(&tmp, a); - - mp_clear(&tmp); - - return MP_OKAY; - -} /* end s_mp_sqr() */ -#endif - -/* }}} */ - -/* {{{ s_mp_div(a, b) */ - -/* - s_mp_div(a, b) - - Compute a = a / b and b = a mod b. Assumes b > a. - */ - -static mp_err s_mp_div(mp_int *a, mp_int *b) -{ - mp_int quot, rem, t; - mp_word q; - mp_err res; - mp_digit d; - int ix; - - if(mp_cmp_z(b) == 0) - return MP_RANGE; - - /* Shortcut if b is power of two */ - if((ix = s_mp_ispow2(b)) >= 0) { - mp_copy(a, b); /* need this for remainder */ - s_mp_div_2d(a, (mp_digit)ix); - s_mp_mod_2d(b, (mp_digit)ix); - - return MP_OKAY; - } - - /* Allocate space to store the quotient */ - if((res = mp_init_size(", USED(a))) != MP_OKAY) - return res; - - /* A working temporary for division */ - if((res = mp_init_size(&t, USED(a))) != MP_OKAY) - goto T; - - /* Allocate space for the remainder */ - if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) - goto REM; - - /* Normalize to optimize guessing */ - d = s_mp_norm(a, b); - - /* Perform the division itself...woo! */ - ix = USED(a) - 1; - - while(ix >= 0) { - /* Find a partial substring of a which is at least b */ - while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { - if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) - goto CLEANUP; - - if((res = s_mp_lshd(", 1)) != MP_OKAY) - goto CLEANUP; - - DIGIT(&rem, 0) = DIGIT(a, ix); - s_mp_clamp(&rem); - --ix; - } - - /* If we didn't find one, we're finished dividing */ - if(s_mp_cmp(&rem, b) < 0) - break; - - /* Compute a guess for the next quotient digit */ - q = DIGIT(&rem, USED(&rem) - 1); - if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) - q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); - - q /= DIGIT(b, USED(b) - 1); - - /* The guess can be as much as RADIX + 1 */ - if(q >= RADIX) - q = RADIX - 1; - - /* See what that multiplies out to */ - mp_copy(b, &t); - if((res = s_mp_mul_d(&t, (mp_digit)q)) != MP_OKAY) - goto CLEANUP; - - /* - If it's too big, back it off. We should not have to do this - more than once, or, in rare cases, twice. Knuth describes a - method by which this could be reduced to a maximum of once, but - I didn't implement that here. - */ - while(s_mp_cmp(&t, &rem) > 0) { - --q; - s_mp_sub(&t, b); - } - - /* At this point, q should be the right next digit */ - if((res = s_mp_sub(&rem, &t)) != MP_OKAY) - goto CLEANUP; - - /* - Include the digit in the quotient. We allocated enough memory - for any quotient we could ever possibly get, so we should not - have to check for failures here - */ - DIGIT(", 0) = q; - } - - /* Denormalize remainder */ - if(d != 0) - s_mp_div_2d(&rem, d); - - s_mp_clamp("); - s_mp_clamp(&rem); - - /* Copy quotient back to output */ - s_mp_exch(", a); - - /* Copy remainder back to output */ - s_mp_exch(&rem, b); - -CLEANUP: - mp_clear(&rem); -REM: - mp_clear(&t); -T: - mp_clear("); - - return res; - -} /* end s_mp_div() */ - -/* }}} */ - -/* {{{ s_mp_2expt(a, k) */ - -static mp_err s_mp_2expt(mp_int *a, mp_digit k) -{ - mp_err res; - mp_size dig, bit; - - dig = k / DIGIT_BIT; - bit = k % DIGIT_BIT; - - mp_zero(a); - if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) - return res; - - DIGIT(a, dig) |= (1 << bit); - - return MP_OKAY; - -} /* end s_mp_2expt() */ - -/* }}} */ - -/* {{{ s_mp_reduce(x, m, mu) */ - -/* - Compute Barrett reduction, x (mod m), given a precomputed value for - mu = b^2k / m, where b = RADIX and k = #digits(m). This should be - faster than straight division, when many reductions by the same - value of m are required (such as in modular exponentiation). This - can nearly halve the time required to do modular exponentiation, - as compared to using the full integer divide to reduce. - - This algorithm was derived from the _Handbook of Applied - Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, - pp. 603-604. - */ - -static mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) -{ - mp_int q; - mp_err res; - mp_size um = USED(m); - - if((res = mp_init_copy(&q, x)) != MP_OKAY) - return res; - - s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ - s_mp_mul(&q, mu); /* q2 = q1 * mu */ - s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ - - /* x = x mod b^(k+1), quick (no division) */ - s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1))); - - /* q = q * m mod b^(k+1), quick (no division) */ - s_mp_mul_dig(&q, m, um + 1); -// s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1))); - - /* 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_z(x) < 0) { - mp_set(&q, 1); - if((res = s_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) >= 0) { - if((res = s_mp_sub(x, m)) != MP_OKAY) - break; - } - - CLEANUP: - mp_clear(&q); - - return res; - -} /* end s_mp_reduce() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive comparisons */ - -/* {{{ s_mp_cmp(a, b) */ - -/* Compare |a| <=> |b|, return 0 if equal, <0 if a0 if a>b */ -static int s_mp_cmp(mp_int *a, mp_int *b) -{ - mp_size ua = USED(a), ub = USED(b); - - if(ua > ub) - return MP_GT; - else if(ua < ub) - return MP_LT; - else { - int ix = ua - 1; - mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; - - while(ix >= 0) { - if(*ap > *bp) - return MP_GT; - else if(*ap < *bp) - return MP_LT; - - --ap; --bp; --ix; - } - - return MP_EQ; - } - -} /* end s_mp_cmp() */ - -/* }}} */ - -/* {{{ s_mp_cmp_d(a, d) */ - -/* Compare |a| <=> d, return 0 if equal, <0 if a0 if a>d */ -static int s_mp_cmp_d(mp_int *a, mp_digit d) -{ - mp_size ua = USED(a); - mp_digit *ap = DIGITS(a); - - if(ua > 1) - return MP_GT; - - if(*ap < d) - return MP_LT; - else if(*ap > d) - return MP_GT; - else - return MP_EQ; - -} /* end s_mp_cmp_d() */ - -/* }}} */ - -/* {{{ s_mp_ispow2(v) */ - -/* - Returns -1 if the value is not a power of two; otherwise, it returns - k such that v = 2^k, i.e. lg(v). - */ -static int s_mp_ispow2(mp_int *v) -{ - mp_digit d, *dp; - mp_size uv = USED(v); - int extra = 0, ix; - - d = DIGIT(v, uv - 1); /* most significant digit of v */ - - while(d && ((d & 1) == 0)) { - d >>= 1; - ++extra; - } - - if(d == 1) { - ix = uv - 2; - dp = DIGITS(v) + ix; - - while(ix >= 0) { - if(*dp) - return -1; /* not a power of two */ - - --dp; --ix; - } - - return ((uv - 1) * DIGIT_BIT) + extra; - } - - return -1; - -} /* end s_mp_ispow2() */ - -/* }}} */ - -/* {{{ s_mp_ispow2d(d) */ - -static int s_mp_ispow2d(mp_digit d) -{ - int pow = 0; - - while((d & 1) == 0) { - ++pow; d >>= 1; - } - - if(d == 1) - return pow; - - return -1; - -} /* end s_mp_ispow2d() */ - -/* }}} */ - -/* }}} */ - -/* {{{ Primitive I/O helpers */ - -/* {{{ s_mp_tovalue(ch, r) */ - -/* - Convert the given character to its digit value, in the given radix. - If the given character is not understood in the given radix, -1 is - returned. Otherwise the digit's numeric value is returned. - - The results will be odd if you use a radix < 2 or > 62, you are - expected to know what you're up to. - */ -static int s_mp_tovalue(char ch, int r) -{ - int val, xch; - - if(r > 36) - xch = ch; - else - xch = toupper(ch); - - if(isdigit(xch)) - val = xch - '0'; - else if(isupper(xch)) - val = xch - 'A' + 10; - else if(islower(xch)) - val = xch - 'a' + 36; - else if(xch == '+') - val = 62; - else if(xch == '/') - val = 63; - else - return -1; - - if(val < 0 || val >= r) - return -1; - - return val; - -} /* end s_mp_tovalue() */ - -/* }}} */ - -/* {{{ s_mp_todigit(val, r, low) */ - -/* - Convert val to a radix-r digit, if possible. If val is out of range - for r, returns zero. Otherwise, returns an ASCII character denoting - the value in the given radix. - - The results may be odd if you use a radix < 2 or > 64, you are - expected to know what you're doing. - */ - -char s_mp_todigit(int val, int r, int low) -{ - char ch; - - if(val < 0 || val >= r) - return 0; - - ch = s_dmap_1[val]; - - if(r <= 36 && low) - ch = tolower(ch); - - return ch; - -} /* end s_mp_todigit() */ - -/* }}} */ - -/* {{{ s_mp_outlen(bits, radix) */ - -/* - Return an estimate for how long a string is needed to hold a radix - r representation of a number with 'bits' significant bits. - - Does not include space for a sign or a NUL terminator. - */ -static int s_mp_outlen(int bits, int r) -{ - return (int)((double)bits * LOG_V_2(r)); - -} /* end s_mp_outlen() */ - -/* }}} */ - -/* }}} */ - -#endif /* MPI */ - -/*------------------------------------------------------------------------*/ -/* HERE THERE BE DRAGONS */ - - diff --git a/mycrypt.h b/mycrypt.h index e96c9e9..a695c18 100644 --- a/mycrypt.h +++ b/mycrypt.h @@ -9,17 +9,15 @@ #include /* if there is a custom definition header file use it */ -#ifdef HAVE_CUSTOM - #include "mycrypt_custom.h" -#endif +#include #ifdef __cplusplus extern "C" { #endif /* version */ -#define CRYPT 0x0080 -#define SCRYPT "0.80" +#define CRYPT 0x0081 +#define SCRYPT "0.81" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 128 diff --git a/mycrypt_cfg.h b/mycrypt_cfg.h index daf4f63..e07758b 100644 --- a/mycrypt_cfg.h +++ b/mycrypt_cfg.h @@ -80,22 +80,5 @@ extern clock_t XCLOCK(void); #define PACKET_SUB_ENC_KEY 3 #endif -#ifdef MPI - #include "mpi.h" -#else - #ifdef MRSA - #error RSA requires the big int library - #endif - #ifdef MECC - #error ECC requires the big int library - #endif - #ifdef MDH - #error DH requires the big int library - #endif - #ifdef MDSA - #error DSA requires the big int library - #endif -#endif /* MPI */ - #endif /* MYCRYPT_CFG_H */ diff --git a/mycrypt_custom.h b/mycrypt_custom.h new file mode 100644 index 0000000..58203c4 --- /dev/null +++ b/mycrypt_custom.h @@ -0,0 +1,76 @@ +/* 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. + */ + +#ifndef MYCRYPT_CUSTOM_H_ +#define MYCRYPT_CUSTOM_H_ + +#ifdef CRYPT + #error mycrypt_custom.h should be included before mycrypt.h +#endif + +#define XMALLOC malloc +#define XREALLOC realloc +#define XCALLOC calloc +#define XFREE free +#define XCLOCK clock +#define XCLOCKS_PER_SEC CLOCKS_PER_SEC +#define SMALL_CODE +#define BLOWFISH +#define RC2 +#define RC5 +#define RC6 +#define SERPENT +#define SAFERP +#define SAFER +#define RIJNDAEL +#define XTEA +#define TWOFISH +#define DES +#define CAST5 +#define NOEKEON +#define CFB +#define OFB +#define ECB +#define CBC +#define CTR +#define SHA512 +#define SHA384 +#define SHA256 +#define TIGER +#define SHA1 +#define MD5 +#define MD4 +#define MD2 +#define HMAC +#define BASE64 +#define YARROW +#define SPRNG +#define RC4 +#define DEVRANDOM +#define MRSA +#define MDH +#define MECC +#define KR +#define DH768 +#define DH1024 +#define DH1280 +#define DH1536 +#define DH1792 +#define DH2048 +#define DH2560 +#define DH3072 +#define DH4096 +#define ECC160 +#define ECC192 +#define ECC224 +#define ECC256 +#define ECC384 +#define ECC521 +#define MPI + + +#include + +#endif + diff --git a/mycrypt_pk.h b/mycrypt_pk.h index 7c3e055..d08acdf 100644 --- a/mycrypt_pk.h +++ b/mycrypt_pk.h @@ -1,12 +1,28 @@ /* ---- NUMBER THEORY ---- */ #ifdef MPI +#include "tommath.h" + extern int is_prime(mp_int *, int *); extern int rand_prime(mp_int *N, long len, prng_state *prng, int wprng); extern mp_err mp_init_multi(mp_int* mp, ...); extern void mp_clear_multi(mp_int* mp, ...); -#endif +#else + #ifdef MRSA + #error RSA requires the big int library + #endif + #ifdef MECC + #error ECC requires the big int library + #endif + #ifdef MDH + #error DH requires the big int library + #endif + #ifdef MDSA + #error DSA requires the big int library + #endif +#endif /* MPI */ + /* ---- PUBLIC KEY CRYPTO ---- */ diff --git a/mycrypt_prng.h b/mycrypt_prng.h index f489e16..b96fa43 100644 --- a/mycrypt_prng.h +++ b/mycrypt_prng.h @@ -56,7 +56,11 @@ extern int prng_is_valid(int idx); /* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this * might not work on all platforms as planned */ -extern unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, void (*callback)(void)); +/* ch2-02-1 */ +extern unsigned long rng_get_bytes(unsigned char *buf, + unsigned long len, + void (*callback)(void)); +/* ch2-02-1 */ extern int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)); diff --git a/prime.c b/prime.c index 9697585..64e6e8e 100644 --- a/prime.c +++ b/prime.c @@ -147,11 +147,11 @@ static int next_prime(mp_int *N, mp_digit step) int res; mp_int n1, a, y, r; mp_digit dist, residues[UPPER_LIMIT]; - + _ARGCHK(N != NULL); /* first find the residues */ - for (x = 0; x < (long)UPPER_LIMIT; x++) { + for (x = 0; x < (long)UPPER_LIMIT; x++) { if (mp_mod_d(N, prime_tab[x], &residues[x]) != MP_OKAY) { return CRYPT_MEM; } @@ -193,7 +193,6 @@ loop: goto error; } } - for (x = 0; x < 8; x++) { /* choose a */ mp_set(&a, prime_tab[x]); diff --git a/rsa.c b/rsa.c index 1c6b7ef..c811997 100644 --- a/rsa.c +++ b/rsa.c @@ -73,7 +73,6 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) 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; } diff --git a/tommath.h b/tommath.h new file mode 100644 index 0000000..9db1781 --- /dev/null +++ b/tommath.h @@ -0,0 +1,352 @@ +/* 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://libtommath.iahu.ca + */ +#ifndef BN_H_ +#define BN_H_ + +#include +#include +#include +#include +#include + +#undef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#undef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) + +#ifdef __cplusplus +extern "C" { +#endif + + +/* 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 + * + * 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] + */ +#ifdef MP_8BIT + typedef unsigned char mp_digit; + typedef unsigned short mp_word; +#elif defined(MP_16BIT) + typedef unsigned short mp_digit; + typedef unsigned long mp_word; +#else +#ifndef CRYPT + #ifdef _MSC_VER + typedef unsigned __int64 ulong64; + typedef signed __int64 long64; + #else + typedef unsigned long long ulong64; + typedef signed long long long64; + #endif +#endif + + /* default case */ + typedef unsigned long mp_digit; + typedef ulong64 mp_word; + + #define DIGIT_BIT 28 +#endif + +#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 + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE MP_VAL + +typedef int mp_err; + +/* you'll have to tune these... */ +extern int KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF, + MONTGOMERY_EXPT_CUTOFF; + +#define MP_PREC 64 /* default digits of precision */ + +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + +#define USED(m) ((m)->used) +#define DIGIT(m,k) ((m)->dp[k]) +#define SIGN(m) ((m)->sign) + +/* ---> init and deinit bignum functions <--- */ + +/* init a bignum */ +int mp_init(mp_int *a); + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* exchange two ints */ +void mp_exch(mp_int *a, mp_int *b); + +/* shrink ram required for a bignum */ +int mp_shrink(mp_int *a); + +/* ---> Basic Manipulations <--- */ + +#define mp_iszero(a) (((a)->used == 0) ? 1 : 0) +#define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? 1 : 0) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? 1 : 0) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b); + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b); + +/* grow an int to a given size */ +int mp_grow(mp_int *a, int size); + +/* init to a given number of digits */ +int mp_init_size(mp_int *a, int size); + +/* copy, b = a */ +int mp_copy(mp_int *a, mp_int *b); + +/* inits and copies, a = b */ +int mp_init_copy(mp_int *a, mp_int *b); + +/* trim unused digits */ +void mp_clamp(mp_int *a); + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +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 */ +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 */ +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 */ +int mp_mod_2d(mp_int *a, int b, mp_int *c); + +/* computes a = 2^b */ +int mp_2expt(mp_int *a, int b); + +/* makes a pseudo-random int of a given size */ +int mp_rand(mp_int *a, int digits); + +/* ---> binary operations <--- */ +/* c = a XOR b */ +int mp_xor(mp_int *a, mp_int *b, mp_int *c); + +/* c = a OR b */ +int mp_or(mp_int *a, mp_int *b, mp_int *c); + +/* c = a AND b */ +int mp_and(mp_int *a, mp_int *b, mp_int *c); + +/* ---> Basic arithmetic <--- */ + +/* b = -a */ +int mp_neg(mp_int *a, mp_int *b); + +/* b = |a| */ +int mp_abs(mp_int *a, mp_int *b); + +/* compare a to b */ +int mp_cmp(mp_int *a, mp_int *b); + +/* compare |a| to |b| */ +int mp_cmp_mag(mp_int *a, mp_int *b); + +/* c = a + b */ +int mp_add(mp_int *a, mp_int *b, mp_int *c); + + +/* c = a - b */ +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 */ +int mp_sqr(mp_int *a, mp_int *b); + +/* a/b => cb + d == a */ +int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a mod b, 0 <= c < b */ +int mp_mod(mp_int *a, mp_int *b, mp_int *c); + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +int mp_cmp_d(mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +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 */ +int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a mod b, 0 <= c < b */ +int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +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| + * + * returns error if a < 0 and b is even + */ +int mp_n_root(mp_int *a, mp_digit b, mp_int *c); + +/* shortcut for square root */ +#define mp_sqrt(a, b) mp_n_root(a, 2, b) + +/* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +int mp_jacobi(mp_int *a, mp_int *n, int *c); + +/* used to setup the Barrett reduction for a given modulus b */ +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 + * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. + */ +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 + * 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 */ +int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); + +/* d = a^b (mod c) */ +int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* ---> radix conversion <--- */ +int mp_count_bits(mp_int *a); + +int mp_unsigned_bin_size(mp_int *a); +int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); + +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); + +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); + +#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)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/* lowlevel functions, do not call! */ +int s_mp_add(mp_int *a, mp_int *b, mp_int *c); +int s_mp_sub(mp_int *a, mp_int *b, mp_int *c); +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +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_karatsuba_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); +void bn_reverse(unsigned char *s, int len); + +#ifdef __cplusplus + } +#endif + +#endif +