From bd479d2bc15361cf2898cbb14bb2a401adfc92d2 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Fri, 11 Jul 2003 02:09:41 +0000 Subject: [PATCH] added libtomcrypt-0.88 --- aes.c | 29 +- aes_tab.c | 38 +- bits.c | 22 +- blowfish.c | 20 +- cast5.c | 40 +- changes | 10 + crypt.out | 152 +-- crypt.pdf | Bin 412260 -> 411351 bytes crypt.tex | 2 +- demos/test.c | 2 +- demos/tv_gen.c | 167 +++ demos/x86_prof.c | 574 ++++---- des.c | 1157 +++++++++++++++- dh.c | 6 +- ecc.c | 24 +- ecc_sys.c | 8 +- makefile | 70 +- makefile.msvc | 7 +- md5.c | 8 +- mpi.c | 3265 ++++++++++++++++++++++++++-------------------- mycrypt.h | 4 +- mycrypt_cipher.h | 22 +- mycrypt_custom.h | 4 +- mycrypt_macros.h | 5 + noekeon.c | 16 +- rc5.c | 47 +- rc6.c | 37 +- safer+.c | 14 +- safer.c | 17 +- sha1.c | 67 +- sha256.c | 79 +- sha512.c | 20 + tommath.h | 20 +- twofish.c | 92 +- 34 files changed, 3904 insertions(+), 2141 deletions(-) create mode 100644 demos/tv_gen.c diff --git a/aes.c b/aes.c index 462cd44..4a8d660 100644 --- a/aes.c +++ b/aes.c @@ -1,4 +1,4 @@ -/* AES implementation by Tom St Denis +/* AES implementation by Tom St Denis * * Derived from the Public Domain source code by @@ -48,7 +48,7 @@ const struct _cipher_descriptor aes_desc = int rijndael_setup(const unsigned char *key, int keylen, int rounds, symmetric_key *skey) { int i = 0, j; - unsigned long temp, *rk, *rrk; + ulong32 temp, *rk, *rrk; _ARGCHK(key != NULL); _ARGCHK(skey != NULL); @@ -235,7 +235,7 @@ int rijndael_setup(const unsigned char *key, int keylen, int rounds, symmetric_k void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) { - unsigned long s0, s1, s2, s3, t0, t1, t2, t3, *rk; + ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk; int Nr, r; _ARGCHK(pt != NULL); @@ -261,13 +261,6 @@ void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ for (;;) { /* Both of these blocks are equivalent except the top is more friendlier for x86 processors */ -#if defined(__GNUC__) - t0 = rk[4]; t1 = rk[5]; t2 = rk[6]; t3 = rk[7]; - t1 ^= Te3[byte(s0, 0)]; t2 ^= Te2[byte(s0, 1)]; t3 ^= Te1[byte(s0, 2)]; t0 ^= Te0[byte(s0, 3)]; - t2 ^= Te3[byte(s1, 0)]; t3 ^= Te2[byte(s1, 1)]; t0 ^= Te1[byte(s1, 2)]; t1 ^= Te0[byte(s1, 3)]; - t3 ^= Te3[byte(s2, 0)]; t0 ^= Te2[byte(s2, 1)]; t1 ^= Te1[byte(s2, 2)]; t2 ^= Te0[byte(s2, 3)]; - t0 ^= Te3[byte(s3, 0)]; t1 ^= Te2[byte(s3, 1)]; t2 ^= Te1[byte(s3, 2)]; t3 ^= Te0[byte(s3, 3)]; -#else t0 = Te0[byte(s0, 3)] ^ Te1[byte(s1, 2)] ^ @@ -292,21 +285,12 @@ void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ Te2[byte(s1, 1)] ^ Te3[byte(s2, 0)] ^ rk[7]; -#endif - + rk += 8; if (--r == 0) { break; } - -/* this second half optimization actually makes it slower on the Athlon, use with caution. */ -#if 0 - s1 = rk[1]; s2 = rk[2]; s3 = rk[3]; s0 = rk[0]; - s1 ^= Te3[byte(t0, 0)]; s2 ^= Te2[byte(t0, 1)]; s3 ^= Te1[byte(t0, 2)]; s0 ^= Te0[byte(t0, 3)]; - s2 ^= Te3[byte(t1, 0)]; s3 ^= Te2[byte(t1, 1)]; s0 ^= Te1[byte(t1, 2)]; s1 ^= Te0[byte(t1, 3)]; - s3 ^= Te3[byte(t2, 0)]; s0 ^= Te2[byte(t2, 1)]; s1 ^= Te1[byte(t2, 2)]; s2 ^= Te0[byte(t2, 3)]; - s0 ^= Te3[byte(t3, 0)]; s1 ^= Te2[byte(t3, 1)]; s2 ^= Te1[byte(t3, 2)]; s3 ^= Te0[byte(t3, 3)]; -#else + s0 = Te0[byte(t0, 3)] ^ Te1[byte(t1, 2)] ^ @@ -331,7 +315,6 @@ void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ Te2[byte(t1, 1)] ^ Te3[byte(t2, 0)] ^ rk[3]; -#endif } /* * apply last round and @@ -368,7 +351,7 @@ void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ } void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) { - unsigned long s0, s1, s2, s3, t0, t1, t2, t3, *rk; + ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk; int Nr, r; _ARGCHK(pt != NULL); diff --git a/aes_tab.c b/aes_tab.c index 78860c3..03a81ef 100644 --- a/aes_tab.c +++ b/aes_tab.c @@ -13,7 +13,7 @@ Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ -static const unsigned long Te0[256] = { +static const ulong32 Te0[256] = { 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, @@ -79,7 +79,7 @@ static const unsigned long Te0[256] = { 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, }; -static const unsigned long Te1[256] = { +static const ulong32 Te1[256] = { 0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL, 0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL, 0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL, @@ -145,7 +145,7 @@ static const unsigned long Te1[256] = { 0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL, 0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL, }; -static const unsigned long Te2[256] = { +static const ulong32 Te2[256] = { 0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL, 0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL, 0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL, @@ -211,7 +211,7 @@ static const unsigned long Te2[256] = { 0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL, 0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL, }; -static const unsigned long Te3[256] = { +static const ulong32 Te3[256] = { 0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL, 0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL, @@ -278,7 +278,7 @@ static const unsigned long Te3[256] = { 0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL, 0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL, }; -static const unsigned long Te4[256] = { +static const ulong32 Te4[256] = { 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, @@ -354,7 +354,7 @@ static const unsigned long Te4[256] = { #else -static const unsigned long Te4_0[] = { +static const ulong32 Te4_0[] = { 0x00000063UL, 0x0000007cUL, 0x00000077UL, 0x0000007bUL, 0x000000f2UL, 0x0000006bUL, 0x0000006fUL, 0x000000c5UL, 0x00000030UL, 0x00000001UL, 0x00000067UL, 0x0000002bUL, 0x000000feUL, 0x000000d7UL, 0x000000abUL, 0x00000076UL, 0x000000caUL, 0x00000082UL, 0x000000c9UL, 0x0000007dUL, 0x000000faUL, 0x00000059UL, 0x00000047UL, 0x000000f0UL, @@ -389,7 +389,7 @@ static const unsigned long Te4_0[] = { 0x00000041UL, 0x00000099UL, 0x0000002dUL, 0x0000000fUL, 0x000000b0UL, 0x00000054UL, 0x000000bbUL, 0x00000016UL }; -static const unsigned long Te4_1[] = { +static const ulong32 Te4_1[] = { 0x00006300UL, 0x00007c00UL, 0x00007700UL, 0x00007b00UL, 0x0000f200UL, 0x00006b00UL, 0x00006f00UL, 0x0000c500UL, 0x00003000UL, 0x00000100UL, 0x00006700UL, 0x00002b00UL, 0x0000fe00UL, 0x0000d700UL, 0x0000ab00UL, 0x00007600UL, 0x0000ca00UL, 0x00008200UL, 0x0000c900UL, 0x00007d00UL, 0x0000fa00UL, 0x00005900UL, 0x00004700UL, 0x0000f000UL, @@ -424,7 +424,7 @@ static const unsigned long Te4_1[] = { 0x00004100UL, 0x00009900UL, 0x00002d00UL, 0x00000f00UL, 0x0000b000UL, 0x00005400UL, 0x0000bb00UL, 0x00001600UL }; -static const unsigned long Te4_2[] = { +static const ulong32 Te4_2[] = { 0x00630000UL, 0x007c0000UL, 0x00770000UL, 0x007b0000UL, 0x00f20000UL, 0x006b0000UL, 0x006f0000UL, 0x00c50000UL, 0x00300000UL, 0x00010000UL, 0x00670000UL, 0x002b0000UL, 0x00fe0000UL, 0x00d70000UL, 0x00ab0000UL, 0x00760000UL, 0x00ca0000UL, 0x00820000UL, 0x00c90000UL, 0x007d0000UL, 0x00fa0000UL, 0x00590000UL, 0x00470000UL, 0x00f00000UL, @@ -459,7 +459,7 @@ static const unsigned long Te4_2[] = { 0x00410000UL, 0x00990000UL, 0x002d0000UL, 0x000f0000UL, 0x00b00000UL, 0x00540000UL, 0x00bb0000UL, 0x00160000UL }; -static const unsigned long Te4_3[] = { +static const ulong32 Te4_3[] = { 0x63000000UL, 0x7c000000UL, 0x77000000UL, 0x7b000000UL, 0xf2000000UL, 0x6b000000UL, 0x6f000000UL, 0xc5000000UL, 0x30000000UL, 0x01000000UL, 0x67000000UL, 0x2b000000UL, 0xfe000000UL, 0xd7000000UL, 0xab000000UL, 0x76000000UL, 0xca000000UL, 0x82000000UL, 0xc9000000UL, 0x7d000000UL, 0xfa000000UL, 0x59000000UL, 0x47000000UL, 0xf0000000UL, @@ -496,7 +496,7 @@ static const unsigned long Te4_3[] = { #endif -static const unsigned long Td0[256] = { +static const ulong32 Td0[256] = { 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, @@ -562,7 +562,7 @@ static const unsigned long Td0[256] = { 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, }; -static const unsigned long Td1[256] = { +static const ulong32 Td1[256] = { 0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL, 0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL, 0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL, @@ -628,7 +628,7 @@ static const unsigned long Td1[256] = { 0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL, 0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL, }; -static const unsigned long Td2[256] = { +static const ulong32 Td2[256] = { 0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL, 0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL, 0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL, @@ -695,7 +695,7 @@ static const unsigned long Td2[256] = { 0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL, 0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL, }; -static const unsigned long Td3[256] = { +static const ulong32 Td3[256] = { 0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL, 0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL, 0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL, @@ -761,7 +761,7 @@ static const unsigned long Td3[256] = { 0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL, 0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL, }; -static const unsigned long Td4[256] = { +static const ulong32 Td4[256] = { 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, @@ -827,14 +827,14 @@ static const unsigned long Td4[256] = { 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, }; -static const unsigned long rcon[] = { +static const ulong32 rcon[] = { 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #ifndef SMALL_CODE -static const unsigned long Tks0[] = { +static const ulong32 Tks0[] = { 0x00000000UL, 0x0e090d0bUL, 0x1c121a16UL, 0x121b171dUL, 0x3824342cUL, 0x362d3927UL, 0x24362e3aUL, 0x2a3f2331UL, 0x70486858UL, 0x7e416553UL, 0x6c5a724eUL, 0x62537f45UL, 0x486c5c74UL, 0x4665517fUL, 0x547e4662UL, 0x5a774b69UL, 0xe090d0b0UL, 0xee99ddbbUL, 0xfc82caa6UL, 0xf28bc7adUL, 0xd8b4e49cUL, 0xd6bde997UL, 0xc4a6fe8aUL, 0xcaaff381UL, @@ -869,7 +869,7 @@ static const unsigned long Tks0[] = { 0xa779b492UL, 0xa970b999UL, 0xbb6bae84UL, 0xb562a38fUL, 0x9f5d80beUL, 0x91548db5UL, 0x834f9aa8UL, 0x8d4697a3UL }; -static const unsigned long Tks1[] = { +static const ulong32 Tks1[] = { 0x00000000UL, 0x0b0e090dUL, 0x161c121aUL, 0x1d121b17UL, 0x2c382434UL, 0x27362d39UL, 0x3a24362eUL, 0x312a3f23UL, 0x58704868UL, 0x537e4165UL, 0x4e6c5a72UL, 0x4562537fUL, 0x74486c5cUL, 0x7f466551UL, 0x62547e46UL, 0x695a774bUL, 0xb0e090d0UL, 0xbbee99ddUL, 0xa6fc82caUL, 0xadf28bc7UL, 0x9cd8b4e4UL, 0x97d6bde9UL, 0x8ac4a6feUL, 0x81caaff3UL, @@ -904,7 +904,7 @@ static const unsigned long Tks1[] = { 0x92a779b4UL, 0x99a970b9UL, 0x84bb6baeUL, 0x8fb562a3UL, 0xbe9f5d80UL, 0xb591548dUL, 0xa8834f9aUL, 0xa38d4697UL }; -static const unsigned long Tks2[] = { +static const ulong32 Tks2[] = { 0x00000000UL, 0x0d0b0e09UL, 0x1a161c12UL, 0x171d121bUL, 0x342c3824UL, 0x3927362dUL, 0x2e3a2436UL, 0x23312a3fUL, 0x68587048UL, 0x65537e41UL, 0x724e6c5aUL, 0x7f456253UL, 0x5c74486cUL, 0x517f4665UL, 0x4662547eUL, 0x4b695a77UL, 0xd0b0e090UL, 0xddbbee99UL, 0xcaa6fc82UL, 0xc7adf28bUL, 0xe49cd8b4UL, 0xe997d6bdUL, 0xfe8ac4a6UL, 0xf381caafUL, @@ -939,7 +939,7 @@ static const unsigned long Tks2[] = { 0xb492a779UL, 0xb999a970UL, 0xae84bb6bUL, 0xa38fb562UL, 0x80be9f5dUL, 0x8db59154UL, 0x9aa8834fUL, 0x97a38d46UL }; -static const unsigned long Tks3[] = { +static const ulong32 Tks3[] = { 0x00000000UL, 0x090d0b0eUL, 0x121a161cUL, 0x1b171d12UL, 0x24342c38UL, 0x2d392736UL, 0x362e3a24UL, 0x3f23312aUL, 0x48685870UL, 0x4165537eUL, 0x5a724e6cUL, 0x537f4562UL, 0x6c5c7448UL, 0x65517f46UL, 0x7e466254UL, 0x774b695aUL, 0x90d0b0e0UL, 0x99ddbbeeUL, 0x82caa6fcUL, 0x8bc7adf2UL, 0xb4e49cd8UL, 0xbde997d6UL, 0xa6fe8ac4UL, 0xaff381caUL, diff --git a/bits.c b/bits.c index 60e3a43..19d2f0f 100644 --- a/bits.c +++ b/bits.c @@ -1,4 +1,6 @@ /* portable way to get secure random bits to feed a PRNG */ +#include +#include #include "mycrypt.h" #ifdef DEVRANDOM @@ -9,26 +11,20 @@ static unsigned long rng_nix(unsigned char *buf, unsigned long len, #ifdef NO_FILE return 0; #else - FILE *f; + int src; unsigned long x; #ifdef TRY_URANDOM_FIRST - f = fopen("/dev/urandom", "rb"); - if (f == NULL) + src = open("/dev/urandom", O_RDONLY); + if (src == -1) #endif /* TRY_URANDOM_FIRST */ - f = fopen("/dev/random", "rb"); + src = open("/dev/random", O_RDONLY); - if (f == NULL) { + if (src == -1) { return 0; } - /* disable buffering */ - if (setvbuf(f, NULL, _IONBF, 0) != 0) { - fclose(f); - return 0; - } - - x = (unsigned long)fread(buf, 1, (size_t)len, f); - fclose(f); + x = (unsigned long)read(src, buf, (size_t)len); + close(src); return x; #endif /* NO_FILE */ } diff --git a/blowfish.c b/blowfish.c index 72b2d8f..aba8a02 100644 --- a/blowfish.c +++ b/blowfish.c @@ -14,7 +14,7 @@ const struct _cipher_descriptor blowfish_desc = &blowfish_keysize }; -static const unsigned long ORIG_P[16 + 2] = { +static const ulong32 ORIG_P[16 + 2] = { 0x243F6A88UL, 0x85A308D3UL, 0x13198A2EUL, 0x03707344UL, 0xA4093822UL, 0x299F31D0UL, 0x082EFA98UL, 0xEC4E6C89UL, 0x452821E6UL, 0x38D01377UL, 0xBE5466CFUL, 0x34E90C6CUL, @@ -22,7 +22,7 @@ static const unsigned long ORIG_P[16 + 2] = { 0x9216D5D9UL, 0x8979FB1BUL }; -static const unsigned long ORIG_S[4][256] = { +static const ulong32 ORIG_S[4][256] = { { 0xD1310BA6UL, 0x98DFB5ACUL, 0x2FFD72DBUL, 0xD01ADFB7UL, 0xB8E1AFEDUL, 0x6A267E96UL, 0xBA7C9045UL, 0xF12C7F99UL, 0x24A19947UL, 0xB3916CF7UL, 0x0801F2E2UL, 0x858EFC16UL, @@ -284,7 +284,7 @@ static const unsigned long ORIG_S[4][256] = { int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) { - unsigned long x, y, z, A; + ulong32 x, y, z, A; unsigned char B[8]; _ARGCHK(key != NULL); @@ -304,7 +304,7 @@ int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, for (x = y = 0; x < 18; x++) { A = 0; for (z = 0; z < 4; z++) { - A = (A << 8) | ((unsigned long)key[y++ % keylen]); + A = (A << 8) | ((ulong32)key[y++ % keylen]); } skey->blowfish.K[x] = ORIG_P[x] ^ A; } @@ -362,10 +362,10 @@ static void _blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, sy void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) #endif { - unsigned long L, R; + ulong32 L, R; int r; #if !defined(TWOFISH_SMALL) && !defined(__GNUC__) - unsigned long *S1, *S2, *S3, *S4; + ulong32 *S1, *S2, *S3, *S4; #endif _ARGCHK(pt != NULL); @@ -404,7 +404,7 @@ void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { _blowfish_ecb_encrypt(pt, ct, key); - burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); + burn_stack(sizeof(ulong32) * 2 + sizeof(int)); } #endif @@ -414,10 +414,10 @@ static void _blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, sy void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) #endif { - unsigned long L, R; + ulong32 L, R; int r; #if !defined(TWOFISH_SMALL) && !defined(__GNUC__) - unsigned long *S1, *S2, *S3, *S4; + ulong32 *S1, *S2, *S3, *S4; #endif _ARGCHK(pt != NULL); @@ -456,7 +456,7 @@ void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { _blowfish_ecb_decrypt(ct, pt, key); - burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); + burn_stack(sizeof(ulong32) * 2 + sizeof(int)); } #endif diff --git a/cast5.c b/cast5.c index c85cd68..2d79b9d 100644 --- a/cast5.c +++ b/cast5.c @@ -14,7 +14,7 @@ const struct _cipher_descriptor cast5_desc = { &cast5_keysize }; -static const unsigned long S1[256] = { +static const ulong32 S1[256] = { 0x30fb40d4UL, 0x9fa0ff0bUL, 0x6beccd2fUL, 0x3f258c7aUL, 0x1e213f2fUL, 0x9c004dd3UL, 0x6003e540UL, 0xcf9fc949UL, 0xbfd4af27UL, 0x88bbbdb5UL, 0xe2034090UL, 0x98d09675UL, 0x6e63a0e0UL, 0x15c361d2UL, 0xc2e7661dUL, 0x22d4ff8eUL, 0x28683b6fUL, 0xc07fd059UL, @@ -59,7 +59,7 @@ static const unsigned long S1[256] = { 0xb141ab08UL, 0x7cca89b9UL, 0x1a69e783UL, 0x02cc4843UL, 0xa2f7c579UL, 0x429ef47dUL, 0x427b169cUL, 0x5ac9f049UL, 0xdd8f0f00UL, 0x5c8165bfUL}; -static const unsigned long S2[256] = { +static const ulong32 S2[256] = { 0x1f201094UL, 0xef0ba75bUL, 0x69e3cf7eUL, 0x393f4380UL, 0xfe61cf7aUL, 0xeec5207aUL, 0x55889c94UL, 0x72fc0651UL, 0xada7ef79UL, 0x4e1d7235UL, 0xd55a63ceUL, 0xde0436baUL, 0x99c430efUL, 0x5f0c0794UL, 0x18dcdb7dUL, 0xa1d6eff3UL, 0xa0b52f7bUL, 0x59e83605UL, @@ -104,7 +104,7 @@ static const unsigned long S2[256] = { 0x5c038323UL, 0x3e5d3bb9UL, 0x43d79572UL, 0x7e6dd07cUL, 0x06dfdf1eUL, 0x6c6cc4efUL, 0x7160a539UL, 0x73bfbe70UL, 0x83877605UL, 0x4523ecf1UL}; -static const unsigned long S3[256] = { +static const ulong32 S3[256] = { 0x8defc240UL, 0x25fa5d9fUL, 0xeb903dbfUL, 0xe810c907UL, 0x47607fffUL, 0x369fe44bUL, 0x8c1fc644UL, 0xaececa90UL, 0xbeb1f9bfUL, 0xeefbcaeaUL, 0xe8cf1950UL, 0x51df07aeUL, 0x920e8806UL, 0xf0ad0548UL, 0xe13c8d83UL, 0x927010d5UL, 0x11107d9fUL, 0x07647db9UL, @@ -149,7 +149,7 @@ static const unsigned long S3[256] = { 0x52bce688UL, 0x1b03588aUL, 0xf7baefd5UL, 0x4142ed9cUL, 0xa4315c11UL, 0x83323ec5UL, 0xdfef4636UL, 0xa133c501UL, 0xe9d3531cUL, 0xee353783UL}; -static const unsigned long S4[256] = { +static const ulong32 S4[256] = { 0x9db30420UL, 0x1fb6e9deUL, 0xa7be7befUL, 0xd273a298UL, 0x4a4f7bdbUL, 0x64ad8c57UL, 0x85510443UL, 0xfa020ed1UL, 0x7e287affUL, 0xe60fb663UL, 0x095f35a1UL, 0x79ebf120UL, 0xfd059d43UL, 0x6497b7b1UL, 0xf3641f63UL, 0x241e4adfUL, 0x28147f5fUL, 0x4fa2b8cdUL, @@ -194,7 +194,7 @@ static const unsigned long S4[256] = { 0xb657c34dUL, 0x4edfd282UL, 0x7ae5290cUL, 0x3cb9536bUL, 0x851e20feUL, 0x9833557eUL, 0x13ecf0b0UL, 0xd3ffb372UL, 0x3f85c5c1UL, 0x0aef7ed2UL}; -static const unsigned long S5[256] = { +static const ulong32 S5[256] = { 0x7ec90c04UL, 0x2c6e74b9UL, 0x9b0e66dfUL, 0xa6337911UL, 0xb86a7fffUL, 0x1dd358f5UL, 0x44dd9d44UL, 0x1731167fUL, 0x08fbf1faUL, 0xe7f511ccUL, 0xd2051b00UL, 0x735aba00UL, 0x2ab722d8UL, 0x386381cbUL, 0xacf6243aUL, 0x69befd7aUL, 0xe6a2e77fUL, 0xf0c720cdUL, @@ -239,7 +239,7 @@ static const unsigned long S5[256] = { 0x34010718UL, 0xbb30cab8UL, 0xe822fe15UL, 0x88570983UL, 0x750e6249UL, 0xda627e55UL, 0x5e76ffa8UL, 0xb1534546UL, 0x6d47de08UL, 0xefe9e7d4UL}; -static const unsigned long S6[256] = { +static const ulong32 S6[256] = { 0xf6fa8f9dUL, 0x2cac6ce1UL, 0x4ca34867UL, 0xe2337f7cUL, 0x95db08e7UL, 0x016843b4UL, 0xeced5cbcUL, 0x325553acUL, 0xbf9f0960UL, 0xdfa1e2edUL, 0x83f0579dUL, 0x63ed86b9UL, 0x1ab6a6b8UL, 0xde5ebe39UL, 0xf38ff732UL, 0x8989b138UL, 0x33f14961UL, 0xc01937bdUL, @@ -284,7 +284,7 @@ static const unsigned long S6[256] = { 0xb0e93524UL, 0xbebb8fbdUL, 0xa2d762cfUL, 0x49c92f54UL, 0x38b5f331UL, 0x7128a454UL, 0x48392905UL, 0xa65b1db8UL, 0x851c97bdUL, 0xd675cf2fUL}; -static const unsigned long S7[256] = { +static const ulong32 S7[256] = { 0x85e04019UL, 0x332bf567UL, 0x662dbfffUL, 0xcfc65693UL, 0x2a8d7f6fUL, 0xab9bc912UL, 0xde6008a1UL, 0x2028da1fUL, 0x0227bce7UL, 0x4d642916UL, 0x18fac300UL, 0x50f18b82UL, 0x2cb2cb11UL, 0xb232e75cUL, 0x4b3695f2UL, 0xb28707deUL, 0xa05fbcf6UL, 0xcd4181e9UL, @@ -329,7 +329,7 @@ static const unsigned long S7[256] = { 0xc3c0bdaeUL, 0x4958c24cUL, 0x518f36b2UL, 0x84b1d370UL, 0x0fedce83UL, 0x878ddadaUL, 0xf2a279c7UL, 0x94e01be8UL, 0x90716f4bUL, 0x954b8aa3UL}; -static const unsigned long S8[256] = { +static const ulong32 S8[256] = { 0xe216300dUL, 0xbbddfffcUL, 0xa7ebdabdUL, 0x35648095UL, 0x7789f8b7UL, 0xe6c1121bUL, 0x0e241600UL, 0x052ce8b5UL, 0x11a9cfb0UL, 0xe5952f11UL, 0xece7990aUL, 0x9386d174UL, 0x2a42931cUL, 0x76e38111UL, 0xb12def3aUL, 0x37ddddfcUL, 0xde9adeb1UL, 0x0a0cc32cUL, @@ -375,11 +375,15 @@ static const unsigned long S8[256] = { 0x50b2ad80UL, 0xeaee6801UL, 0x8db2a283UL, 0xea8bf59eUL}; /* returns the i'th byte of a variable */ -#define GB(x, i) (((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))&255) +#ifdef _MSC_VER + #define GB(x, i) ((unsigned char)((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))) +#else + #define GB(x, i) (((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))&255) +#endif int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) { - unsigned long x[4], z[4]; + ulong32 x[4], z[4]; unsigned char buf[16]; int y, i; @@ -464,25 +468,25 @@ int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ #define INLINE #endif -INLINE static unsigned long FI(unsigned long R, unsigned long Km, unsigned long Kr) +INLINE static ulong32 FI(ulong32 R, ulong32 Km, ulong32 Kr) { - unsigned long I; + ulong32 I; I = (Km + R); I = ROL(I, Kr); return ((S1[byte(I, 3)] ^ S2[byte(I,2)]) - S3[byte(I,1)]) + S4[byte(I,0)]; } -INLINE static unsigned long FII(unsigned long R, unsigned long Km, unsigned long Kr) +INLINE static ulong32 FII(ulong32 R, ulong32 Km, ulong32 Kr) { - unsigned long I; + ulong32 I; I = (Km ^ R); I = ROL(I, Kr); return ((S1[byte(I, 3)] - S2[byte(I,2)]) + S3[byte(I,1)]) ^ S4[byte(I,0)]; } -INLINE static unsigned long FIII(unsigned long R, unsigned long Km, unsigned long Kr) +INLINE static ulong32 FIII(ulong32 R, ulong32 Km, ulong32 Kr) { - unsigned long I; + ulong32 I; I = (Km - R); I = ROL(I, Kr); return ((S1[byte(I, 3)] + S2[byte(I,2)]) ^ S3[byte(I,1)]) - S4[byte(I,0)]; @@ -490,7 +494,7 @@ INLINE static unsigned long FIII(unsigned long R, unsigned long Km, unsigned lon void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { - unsigned long R, L; + ulong32 R, L; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); @@ -523,7 +527,7 @@ void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { - unsigned long R, L; + ulong32 R, L; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); diff --git a/changes b/changes index 5acc5f5..5f5e4a2 100644 --- a/changes +++ b/changes @@ -1,3 +1,13 @@ +Jul 10th, 2003 +v0.88 -- Sped up CAST5 key schedule for MSVC + -- added "ulong32" which allows people on 64-bit platforms to force the 32-bit tables in + ciphers like blowfish and AES to be 32-bits. E.g. when unsigned long is 64-bits. + -- Optimized the SAFER-SK64, SAFER-SK128, SAFER+, RC5 and RC6 key schedule [big time!] + -- Optimized SHA-1 and SHA-256 quite a bit too. + -- Fixed up the makefile to use -fomit-frame-pointer more liberally + -- Added tv_gen program which makes test vectors for ciphers/hashes + -- Merged in LibTomMath v0.22 + Jun 19th, 2003 v0.87 -- Many MSVC optimizations to the code base -- Improved the AES and Twofish key schedule [faster, more constant time] diff --git a/crypt.out b/crypt.out index 7471011..7a3feac 100644 --- a/crypt.out +++ b/crypt.out @@ -1,76 +1,76 @@ -\BOOKMARK [0][-]{chapter.1}{Introduction}{} -\BOOKMARK [1][-]{section.1.1}{What is the LibTomCrypt?}{chapter.1} -\BOOKMARK [2][-]{subsection.1.1.1}{What the library IS for?}{section.1.1} -\BOOKMARK [2][-]{subsection.1.1.2}{What the library IS NOT for?}{section.1.1} -\BOOKMARK [1][-]{section.1.2}{Why did I write it?}{chapter.1} -\BOOKMARK [2][-]{subsection.1.2.1}{Modular}{section.1.2} -\BOOKMARK [1][-]{section.1.3}{License}{chapter.1} -\BOOKMARK [1][-]{section.1.4}{Patent Disclosure}{chapter.1} -\BOOKMARK [1][-]{section.1.5}{Building the library}{chapter.1} -\BOOKMARK [1][-]{section.1.6}{Building against the library}{chapter.1} -\BOOKMARK [1][-]{section.1.7}{Thanks}{chapter.1} -\BOOKMARK [0][-]{chapter.2}{The Application Programming Interface \(API\)}{} -\BOOKMARK [1][-]{section.2.1}{Introduction}{chapter.2} -\BOOKMARK [1][-]{section.2.2}{Macros}{chapter.2} -\BOOKMARK [1][-]{section.2.3}{Functions with Variable Length Output}{chapter.2} -\BOOKMARK [1][-]{section.2.4}{Functions that need a PRNG}{chapter.2} -\BOOKMARK [1][-]{section.2.5}{Functions that use Arrays of Octets}{chapter.2} -\BOOKMARK [0][-]{chapter.3}{Symmetric Block Ciphers}{} -\BOOKMARK [1][-]{section.3.1}{Core Functions}{chapter.3} -\BOOKMARK [1][-]{section.3.2}{Key Sizes and Number of Rounds}{chapter.3} -\BOOKMARK [1][-]{section.3.3}{The Cipher Descriptors}{chapter.3} -\BOOKMARK [2][-]{subsection.3.3.1}{Notes}{section.3.3} -\BOOKMARK [1][-]{section.3.4}{Symmetric Modes of Operations}{chapter.3} -\BOOKMARK [2][-]{subsection.3.4.1}{Background}{section.3.4} -\BOOKMARK [2][-]{subsection.3.4.2}{Choice of Mode}{section.3.4} -\BOOKMARK [2][-]{subsection.3.4.3}{Implementation}{section.3.4} -\BOOKMARK [0][-]{chapter.4}{One-Way Cryptographic Hash Functions}{} -\BOOKMARK [1][-]{section.4.1}{Core Functions}{chapter.4} -\BOOKMARK [1][-]{section.4.2}{Hash Descriptors}{chapter.4} -\BOOKMARK [2][-]{subsection.4.2.1}{Notice}{section.4.2} -\BOOKMARK [1][-]{section.4.3}{Hash based Message Authenication Codes}{chapter.4} -\BOOKMARK [0][-]{chapter.5}{Pseudo-Random Number Generators}{} -\BOOKMARK [1][-]{section.5.1}{Core Functions}{chapter.5} -\BOOKMARK [2][-]{subsection.5.1.1}{Remarks}{section.5.1} -\BOOKMARK [2][-]{subsection.5.1.2}{Example}{section.5.1} -\BOOKMARK [1][-]{section.5.2}{PRNG Descriptors}{chapter.5} -\BOOKMARK [1][-]{section.5.3}{The Secure RNG}{chapter.5} -\BOOKMARK [2][-]{subsection.5.3.1}{The Secure PRNG Interface}{section.5.3} -\BOOKMARK [0][-]{chapter.6}{RSA Routines}{} -\BOOKMARK [1][-]{section.6.1}{Background}{chapter.6} -\BOOKMARK [1][-]{section.6.2}{Core Functions}{chapter.6} -\BOOKMARK [1][-]{section.6.3}{Packet Routines}{chapter.6} -\BOOKMARK [1][-]{section.6.4}{Remarks}{chapter.6} -\BOOKMARK [0][-]{chapter.7}{Diffie-Hellman Key Exchange}{} -\BOOKMARK [1][-]{section.7.1}{Background}{chapter.7} -\BOOKMARK [1][-]{section.7.2}{Core Functions}{chapter.7} -\BOOKMARK [2][-]{subsection.7.2.1}{Remarks on Usage}{section.7.2} -\BOOKMARK [2][-]{subsection.7.2.2}{Remarks on The Snippet}{section.7.2} -\BOOKMARK [1][-]{section.7.3}{Other Diffie-Hellman Functions}{chapter.7} -\BOOKMARK [1][-]{section.7.4}{DH Packet}{chapter.7} -\BOOKMARK [0][-]{chapter.8}{Elliptic Curve Cryptography}{} -\BOOKMARK [1][-]{section.8.1}{Background}{chapter.8} -\BOOKMARK [1][-]{section.8.2}{Core Functions}{chapter.8} -\BOOKMARK [1][-]{section.8.3}{ECC Packet}{chapter.8} -\BOOKMARK [1][-]{section.8.4}{ECC Keysizes}{chapter.8} -\BOOKMARK [0][-]{chapter.9}{Public Keyrings}{} -\BOOKMARK [1][-]{section.9.1}{Introduction}{chapter.9} -\BOOKMARK [1][-]{section.9.2}{The Keyring API}{chapter.9} -\BOOKMARK [0][-]{chapter.10}{GF\(2w\) Math Routines}{} -\BOOKMARK [0][-]{chapter.11}{Miscellaneous}{} -\BOOKMARK [1][-]{section.11.1}{Base64 Encoding and Decoding}{chapter.11} -\BOOKMARK [1][-]{section.11.2}{The Multiple Precision Integer Library \(MPI\)}{chapter.11} -\BOOKMARK [2][-]{subsection.11.2.1}{Binary Forms of ``mp\137int'' Variables}{section.11.2} -\BOOKMARK [2][-]{subsection.11.2.2}{Primality Testing}{section.11.2} -\BOOKMARK [0][-]{chapter.12}{Programming Guidelines}{} -\BOOKMARK [1][-]{section.12.1}{Secure Pseudo Random Number Generators}{chapter.12} -\BOOKMARK [1][-]{section.12.2}{Preventing Trivial Errors}{chapter.12} -\BOOKMARK [1][-]{section.12.3}{Registering Your Algorithms}{chapter.12} -\BOOKMARK [1][-]{section.12.4}{Key Sizes}{chapter.12} -\BOOKMARK [2][-]{subsection.12.4.1}{Symmetric Ciphers}{section.12.4} -\BOOKMARK [2][-]{subsection.12.4.2}{Assymetric Ciphers}{section.12.4} -\BOOKMARK [1][-]{section.12.5}{Thread Safety}{chapter.12} -\BOOKMARK [0][-]{chapter.13}{Configuring the Library}{} -\BOOKMARK [1][-]{section.13.1}{Introduction}{chapter.13} -\BOOKMARK [1][-]{section.13.2}{mycrypt\137cfg.h}{chapter.13} -\BOOKMARK [1][-]{section.13.3}{The Configure Script}{chapter.13} +\BOOKMARK [0][-]{chapter.1}{Introduction}{} +\BOOKMARK [1][-]{section.1.1}{What is the LibTomCrypt?}{chapter.1} +\BOOKMARK [2][-]{subsection.1.1.1}{What the library IS for?}{section.1.1} +\BOOKMARK [2][-]{subsection.1.1.2}{What the library IS NOT for?}{section.1.1} +\BOOKMARK [1][-]{section.1.2}{Why did I write it?}{chapter.1} +\BOOKMARK [2][-]{subsection.1.2.1}{Modular}{section.1.2} +\BOOKMARK [1][-]{section.1.3}{License}{chapter.1} +\BOOKMARK [1][-]{section.1.4}{Patent Disclosure}{chapter.1} +\BOOKMARK [1][-]{section.1.5}{Building the library}{chapter.1} +\BOOKMARK [1][-]{section.1.6}{Building against the library}{chapter.1} +\BOOKMARK [1][-]{section.1.7}{Thanks}{chapter.1} +\BOOKMARK [0][-]{chapter.2}{The Application Programming Interface \(API\)}{} +\BOOKMARK [1][-]{section.2.1}{Introduction}{chapter.2} +\BOOKMARK [1][-]{section.2.2}{Macros}{chapter.2} +\BOOKMARK [1][-]{section.2.3}{Functions with Variable Length Output}{chapter.2} +\BOOKMARK [1][-]{section.2.4}{Functions that need a PRNG}{chapter.2} +\BOOKMARK [1][-]{section.2.5}{Functions that use Arrays of Octets}{chapter.2} +\BOOKMARK [0][-]{chapter.3}{Symmetric Block Ciphers}{} +\BOOKMARK [1][-]{section.3.1}{Core Functions}{chapter.3} +\BOOKMARK [1][-]{section.3.2}{Key Sizes and Number of Rounds}{chapter.3} +\BOOKMARK [1][-]{section.3.3}{The Cipher Descriptors}{chapter.3} +\BOOKMARK [2][-]{subsection.3.3.1}{Notes}{section.3.3} +\BOOKMARK [1][-]{section.3.4}{Symmetric Modes of Operations}{chapter.3} +\BOOKMARK [2][-]{subsection.3.4.1}{Background}{section.3.4} +\BOOKMARK [2][-]{subsection.3.4.2}{Choice of Mode}{section.3.4} +\BOOKMARK [2][-]{subsection.3.4.3}{Implementation}{section.3.4} +\BOOKMARK [0][-]{chapter.4}{One-Way Cryptographic Hash Functions}{} +\BOOKMARK [1][-]{section.4.1}{Core Functions}{chapter.4} +\BOOKMARK [1][-]{section.4.2}{Hash Descriptors}{chapter.4} +\BOOKMARK [2][-]{subsection.4.2.1}{Notice}{section.4.2} +\BOOKMARK [1][-]{section.4.3}{Hash based Message Authenication Codes}{chapter.4} +\BOOKMARK [0][-]{chapter.5}{Pseudo-Random Number Generators}{} +\BOOKMARK [1][-]{section.5.1}{Core Functions}{chapter.5} +\BOOKMARK [2][-]{subsection.5.1.1}{Remarks}{section.5.1} +\BOOKMARK [2][-]{subsection.5.1.2}{Example}{section.5.1} +\BOOKMARK [1][-]{section.5.2}{PRNG Descriptors}{chapter.5} +\BOOKMARK [1][-]{section.5.3}{The Secure RNG}{chapter.5} +\BOOKMARK [2][-]{subsection.5.3.1}{The Secure PRNG Interface}{section.5.3} +\BOOKMARK [0][-]{chapter.6}{RSA Routines}{} +\BOOKMARK [1][-]{section.6.1}{Background}{chapter.6} +\BOOKMARK [1][-]{section.6.2}{Core Functions}{chapter.6} +\BOOKMARK [1][-]{section.6.3}{Packet Routines}{chapter.6} +\BOOKMARK [1][-]{section.6.4}{Remarks}{chapter.6} +\BOOKMARK [0][-]{chapter.7}{Diffie-Hellman Key Exchange}{} +\BOOKMARK [1][-]{section.7.1}{Background}{chapter.7} +\BOOKMARK [1][-]{section.7.2}{Core Functions}{chapter.7} +\BOOKMARK [2][-]{subsection.7.2.1}{Remarks on Usage}{section.7.2} +\BOOKMARK [2][-]{subsection.7.2.2}{Remarks on The Snippet}{section.7.2} +\BOOKMARK [1][-]{section.7.3}{Other Diffie-Hellman Functions}{chapter.7} +\BOOKMARK [1][-]{section.7.4}{DH Packet}{chapter.7} +\BOOKMARK [0][-]{chapter.8}{Elliptic Curve Cryptography}{} +\BOOKMARK [1][-]{section.8.1}{Background}{chapter.8} +\BOOKMARK [1][-]{section.8.2}{Core Functions}{chapter.8} +\BOOKMARK [1][-]{section.8.3}{ECC Packet}{chapter.8} +\BOOKMARK [1][-]{section.8.4}{ECC Keysizes}{chapter.8} +\BOOKMARK [0][-]{chapter.9}{Public Keyrings}{} +\BOOKMARK [1][-]{section.9.1}{Introduction}{chapter.9} +\BOOKMARK [1][-]{section.9.2}{The Keyring API}{chapter.9} +\BOOKMARK [0][-]{chapter.10}{GF\(2w\) Math Routines}{} +\BOOKMARK [0][-]{chapter.11}{Miscellaneous}{} +\BOOKMARK [1][-]{section.11.1}{Base64 Encoding and Decoding}{chapter.11} +\BOOKMARK [1][-]{section.11.2}{The Multiple Precision Integer Library \(MPI\)}{chapter.11} +\BOOKMARK [2][-]{subsection.11.2.1}{Binary Forms of ``mp\137int'' Variables}{section.11.2} +\BOOKMARK [2][-]{subsection.11.2.2}{Primality Testing}{section.11.2} +\BOOKMARK [0][-]{chapter.12}{Programming Guidelines}{} +\BOOKMARK [1][-]{section.12.1}{Secure Pseudo Random Number Generators}{chapter.12} +\BOOKMARK [1][-]{section.12.2}{Preventing Trivial Errors}{chapter.12} +\BOOKMARK [1][-]{section.12.3}{Registering Your Algorithms}{chapter.12} +\BOOKMARK [1][-]{section.12.4}{Key Sizes}{chapter.12} +\BOOKMARK [2][-]{subsection.12.4.1}{Symmetric Ciphers}{section.12.4} +\BOOKMARK [2][-]{subsection.12.4.2}{Assymetric Ciphers}{section.12.4} +\BOOKMARK [1][-]{section.12.5}{Thread Safety}{chapter.12} +\BOOKMARK [0][-]{chapter.13}{Configuring the Library}{} +\BOOKMARK [1][-]{section.13.1}{Introduction}{chapter.13} +\BOOKMARK [1][-]{section.13.2}{mycrypt\137cfg.h}{chapter.13} +\BOOKMARK [1][-]{section.13.3}{The Configure Script}{chapter.13} diff --git a/crypt.pdf b/crypt.pdf index f5133baf87cfa81b534437979f2e77ac7a5e3e08..d60aca098205ff00fbf037df6610024390cbb0aa 100644 GIT binary patch delta 97594 zcmdSA1yo#3vo?ymLxQ^`0m9%AAh-sCTL?Dzz`zik0NGfu;0X-wEi|8YjX?_6avBXu-K;$j;lgeaVe4}mwI{i;DkI}12srq z=f2XUUC{pQ%nI}Cw{-jl6SwLVPk{{QZJaO38!J^MDy8qLKoyF)Zk;a#aeBK~ zxCtt+rkf4V^`I%r^kJTtjg5L;k|$}~@*xyX4w)~lFnG`US1-A(ru|*r+QfM#XqSWq zrg&L2O8ioYgv08vaUOMicc8hDoRWc4gbzHK<;{4gQF7K<9iyk$u&;R+?+S3>RL6kA zi|l1D-Ky6UPL9VPe1o?;OxcTuau1`?1qTz!S$!p`9gQh@-mS}2Jmj@MZO|C6-GV*I z(YwMp`I;%&FNT!H;r=_?^J`v$E7vAwPE%nA*3UsADksei1cmjF3Y}k?u1DKwq0780 z#uG94L8GMQHuzjN2K<3*|D%?fN}<}znX9^5TR}z@CVJh_nO6ejM|?M&e)HxMA^Hq1 zv)=;VkllyNzae(y7m@OokB@bAu4RS#BGYD!pv0u59+y5oDbasKj9DXwvFc+w$Goq2-gpsqeEy&sl>}Cl9o4dML zg3Q5A2t#I0mI#SG*!&mcglG_CZfOC5Lct(wODB70t58n5Fⅈb&;HQ343 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%0AY%_tF5D#>qA2!3hv2Kkv7;EI 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�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 z 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 bQeyV-v~>6U{j3h?2Oh? delta 97745 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�JUoC{L+rD9|;TFIB`({ol)=}G9DmU7N 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¨z_V@* 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%0DvaS3Cy3mg}?wr{@Y0Xi~lev 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 Z>vT##{kiLZyXKPkIShuh+r7NMrhh=`@D>07 diff --git a/crypt.tex b/crypt.tex index d040e73..0cfeff3 100644 --- a/crypt.tex +++ b/crypt.tex @@ -47,7 +47,7 @@ \def\gap{\vspace{0.5ex}} \makeindex \begin{document} -\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.87} +\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.88} \author{Tom St Denis \\ Algonquin College \\ \\ diff --git a/demos/test.c b/demos/test.c index 420c8fe..cc6ff98 100644 --- a/demos/test.c +++ b/demos/test.c @@ -1261,7 +1261,7 @@ gf_tests (void) void test_prime (void) { - unsigned char buf[1024]; + char buf[1024]; mp_int a; int x; diff --git a/demos/tv_gen.c b/demos/tv_gen.c new file mode 100644 index 0000000..5230559 --- /dev/null +++ b/demos/tv_gen.c @@ -0,0 +1,167 @@ +#include + +void reg_algs(void) +{ +#ifdef RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 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 + +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif +} + +void hash_gen(void) +{ + unsigned char md[MAXBLOCKSIZE], buf[MAXBLOCKSIZE*2+2]; + unsigned long outlen, x, y, z; + FILE *out; + + out = fopen("hash_tv.txt", "w"); + + fprintf(out, "Hash Test Vectors:\n\nThese are the hashes of nn bytes '00 01 02 03 .. (nn-1)'\n\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + fprintf(out, "Hash: %s\n", hash_descriptor[x].name); + + for (y = 0; y <= (hash_descriptor[x].blocksize * 2); y++) { + for (z = 0; z < y; z++) { + buf[z] = (unsigned char)z; + } + outlen = sizeof(md); + hash_memory(x, buf, y, md, &outlen); + fprintf(out, "%3lu: ", y); + for (z = 0; z < outlen; z++) { + fprintf(out, "%02X", md[z]); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + fclose(out); +} + +void cipher_gen(void) +{ + unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; + unsigned long x, y, z, w; + int kl, lastkl; + FILE *out; + symmetric_key skey; + + out = fopen("cipher_tv.txt", "w"); + + fprintf(out, "Cipher Test Vectors\n\nThese are test encryptions with key of nn bytes '00 01 02 03 .. (nn-1)' and original PT of the same style.\n\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + fprintf(out, "Cipher: %s\n", cipher_descriptor[x].name); + + /* three modes, smallest, medium, large keys */ + lastkl = 10000; + for (y = 0; y < 3; y++) { + switch (y) { + case 0: kl = cipher_descriptor[x].min_key_length; break; + case 1: kl = (cipher_descriptor[x].min_key_length + cipher_descriptor[x].max_key_length)/2; break; + case 2: kl = cipher_descriptor[x].max_key_length; break; + } + cipher_descriptor[x].keysize(&kl); + if (kl == lastkl) break; + lastkl = kl; + fprintf(out, "Key Size: %d bytes\n", kl); + + for (z = 0; (int)z < kl; z++) { + key[z] = (unsigned char)z; + } + cipher_descriptor[x].setup(key, kl, 0, &skey); + + for (z = 0; (int)z < cipher_descriptor[x].block_length; z++) { + pt[z] = (unsigned char)z; + } + for (w = 0; w < 25; w++) { + cipher_descriptor[x].ecb_encrypt(pt, pt, &skey); + fprintf(out, "%2lu: ", w); + for (z = 0; (int)z < cipher_descriptor[x].block_length; z++) { + fprintf(out, "%02X", pt[z]); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + fclose(out); +} + + +int main(void) +{ + reg_algs(); + hash_gen(); + cipher_gen(); + + return 0; +} + + + + + + + + diff --git a/demos/x86_prof.c b/demos/x86_prof.c index 87d6caf..72a2eb6 100644 --- a/demos/x86_prof.c +++ b/demos/x86_prof.c @@ -1,291 +1,283 @@ -#include - -#define KTIMES 25 -#define TIMES 10000 - -/* RDTSC from Scott Duplichan */ -static ulong64 rdtsc (void) - { - #if defined __GNUC__ - #ifdef i386 - ulong64 a; - asm volatile("rdtsc ":"=A" (a)); - return a; - #else /* gcc-IA64 version */ - unsigned long result; - __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); - while (__builtin_expect ((int) result == -1, 0)) - __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); - return result; - #endif - - // Microsoft and Intel Windows compilers - #elif defined _M_IX86 - __asm rdtsc - #elif defined _M_AMD64 - return __rdtsc (); - #elif defined _M_IA64 - #if defined __INTEL_COMPILER - #include - #endif - return __getReg (3116); - #else - #error need rdtsc function for this build - #endif - } - -ulong64 timer, skew = 0; - -void t_start(void) -{ - timer = rdtsc(); -} - -ulong64 t_read(void) -{ - return rdtsc() - timer; -} - -void init_timer(void) -{ - ulong64 c1, c2, t1, t2, t3; - unsigned long y1; - - c1 = c2 = (ulong64)-1; - for (y1 = 0; y1 < TIMES*100; y1++) { - t_start(); - t1 = t_read(); - t3 = t_read(); - t2 = t_read() - t1; - - c1 = (c1 > t1) ? t1 : c1; - c2 = (c2 > t2) ? t2 : c2; - } - skew = c2 - c1; - printf("Clock Skew: %lu\n", (unsigned long)skew); -} - -void reg_algs(void) -{ -#ifdef RIJNDAEL - register_cipher (&aes_desc); -#endif -#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 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 - -#ifdef TIGER - register_hash (&tiger_desc); -#endif -#ifdef MD2 - register_hash (&md2_desc); -#endif -#ifdef MD4 - register_hash (&md4_desc); -#endif -#ifdef MD5 - register_hash (&md5_desc); -#endif -#ifdef SHA1 - register_hash (&sha1_desc); -#endif -#ifdef SHA256 - register_hash (&sha256_desc); -#endif -#ifdef SHA384 - register_hash (&sha384_desc); -#endif -#ifdef SHA512 - register_hash (&sha512_desc); -#endif - -} - -int time_keysched(void) -{ - unsigned long x, i, y1; - ulong64 t1, c1; - symmetric_key skey; - int kl; - int (*func) (const unsigned char *, int , int , symmetric_key *); - unsigned char key[256][MAXBLOCKSIZE]; - - - printf ("\n\nKey Schedule Time Trials for the Symmetric Ciphers:\n(Times are cycles per key)\n"); - for (x = 0; cipher_descriptor[x].name != NULL; x++) { -#define DO1(k) func(k, kl, 0, &skey); - - func = cipher_descriptor[x].setup; - kl = cipher_descriptor[x].min_key_length; - c1 = (ulong64)-1; - for (y1 = 0; y1 < KTIMES; y1++) { - for (i = 0; i < 256; i++) { - rng_get_bytes(key[i], kl, NULL); - } - - t_start(); - for (i = 0; i < 256; i++) { - DO1(key[i]); - } - t1 = t_read() >> 8; - if (t1 < c1) { if (y1 > 0) --y1; } - c1 = (t1 > c1) ? c1 : t1; - } - t1 = c1 - skew; - printf - ("%-20s: Schedule at %6lu\n", cipher_descriptor[x].name, (unsigned long)t1); - -#undef DO1 - } - - return 0; -} - -int time_cipher(void) -{ - unsigned long x, y1; - ulong64 t1, t2, c1, c2, a1, a2; - symmetric_key skey; - void (*func) (const unsigned char *, unsigned char *, symmetric_key *); - unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; - - - printf ("\n\nECB 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 - - func = cipher_descriptor[x].ecb_encrypt; - c1 = c2 = (ulong64)-1; - for (y1 = 0; y1 < TIMES; y1++) { - t_start(); - DO1; - t1 = t_read(); - DO2; - t2 = t_read(); - t2 -= t1; - - c1 = (t1 > c1 ? c1 : t1); - c2 = (t2 > c2 ? c2 : t2); - } - a1 = c2 - c1 - skew; - - - func = cipher_descriptor[x].ecb_decrypt; - c1 = c2 = (ulong64)-1; - for (y1 = 0; y1 < TIMES; y1++) { - t_start(); - DO1; - t1 = t_read(); - DO2; - t2 = t_read(); - t2 -= t1; - - c1 = (t1 > c1 ? c1 : t1); - c2 = (t2 > c2 ? c2 : t2); - } - a2 = c2 - c1 - skew; - - printf - ("%-20s: Encrypt at %7.3f, Decrypt at %7.3f\n", cipher_descriptor[x].name, a1/(double)cipher_descriptor[x].block_length, a2/(double)cipher_descriptor[x].block_length); - -#undef DO2 -#undef DO1 - } - - return 0; -} - -int time_hash(void) -{ - unsigned long x, y1, len; - ulong64 t1, t2, c1, c2; - hash_state md; - void (*func)(hash_state *, const unsigned char *, unsigned long); - unsigned char pt[MAXBLOCKSIZE]; - - - printf ("\n\nHASH Time Trials for:\n"); - for (x = 0; hash_descriptor[x].name != NULL; x++) { - hash_descriptor[x].init(&md); - -#define DO1 func(&md,pt,len); -#define DO2 DO1 DO1 - - func = hash_descriptor[x].process; - len = hash_descriptor[x].blocksize; - - c1 = c2 = (ulong64)-1; - for (y1 = 0; y1 < TIMES; y1++) { - t_start(); - DO1; - t1 = t_read(); - DO2; - t2 = t_read() - t1; - c1 = (t1 > c1) ? c1 : t1; - c2 = (t2 > c2) ? c2 : t2; - } - t1 = c2 - c1 - skew; - t1 = ((t1 * CONST64(1000))) / ((ulong64)hash_descriptor[x].blocksize); - - printf - ("%-20s: Process at %9.3f\n", hash_descriptor[x].name, t1 / 1000.0); - -#undef DO2 -#undef DO1 - } - - return 0; -} - -int main(void) -{ - reg_algs(); - - printf("Timings for ciphers and hashes. Times are listed as cycles per byte processed.\n\n"); - -// init_timer(); - time_keysched(); - time_cipher(); - time_hash(); - - return EXIT_SUCCESS; -} - +#include + +#define KTIMES 25 +#define TIMES 100000 + +/* RDTSC from Scott Duplichan */ +static ulong64 rdtsc (void) + { + #if defined __GNUC__ + #ifdef i386 + ulong64 a; + asm volatile("rdtsc ":"=A" (a)); + return a; + #else /* gcc-IA64 version */ + unsigned long result; + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + while (__builtin_expect ((int) result == -1, 0)) + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + return result; + #endif + + // Microsoft and Intel Windows compilers + #elif defined _M_IX86 + __asm rdtsc + #elif defined _M_AMD64 + return __rdtsc (); + #elif defined _M_IA64 + #if defined __INTEL_COMPILER + #include + #endif + return __getReg (3116); + #else + #error need rdtsc function for this build + #endif + } + +ulong64 timer, skew = 0; + +void t_start(void) +{ + timer = rdtsc(); +} + +ulong64 t_read(void) +{ + return rdtsc() - timer; +} + +void init_timer(void) +{ + ulong64 c1, c2, t1, t2, t3; + unsigned long y1; + + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES*100; y1++) { + t_start(); + t1 = t_read(); + t3 = t_read(); + t2 = t_read() - t1; + + c1 = (c1 > t1) ? t1 : c1; + c2 = (c2 > t2) ? t2 : c2; + } + skew = c2 - c1; + printf("Clock Skew: %lu\n", (unsigned long)skew); +} + +void reg_algs(void) +{ +#ifdef RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 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 + +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif + +} + +int time_keysched(void) +{ + unsigned long x, i, y1; + ulong64 t1, c1; + symmetric_key skey; + int kl; + int (*func) (const unsigned char *, int , int , symmetric_key *); + unsigned char key[MAXBLOCKSIZE]; + + printf ("\n\nKey Schedule Time Trials for the Symmetric Ciphers:\n(Times are cycles per key)\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { +#define DO1(k) func(k, kl, 0, &skey); + + func = cipher_descriptor[x].setup; + kl = cipher_descriptor[x].min_key_length; + c1 = (ulong64)-1; + for (y1 = 0; y1 < KTIMES; y1++) { + rng_get_bytes(key, kl, NULL); + t_start(); + DO1(key); + t1 = t_read(); + c1 = (t1 > c1) ? c1 : t1; + } + t1 = c1 - skew; + printf("%-20s: Schedule at %6lu\n", cipher_descriptor[x].name, (unsigned long)t1); + +#undef DO1 + } + + return 0; +} + +int time_cipher(void) +{ + unsigned long x, y1; + ulong64 t1, t2, c1, c2, a1, a2; + symmetric_key skey; + void (*func) (const unsigned char *, unsigned char *, symmetric_key *); + unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; + + + printf ("\n\nECB 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 + + func = cipher_descriptor[x].ecb_encrypt; + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read(); + t2 -= t1; + + c1 = (t1 > c1 ? c1 : t1); + c2 = (t2 > c2 ? c2 : t2); + } + a1 = c2 - c1 - skew; + + + func = cipher_descriptor[x].ecb_decrypt; + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read(); + t2 -= t1; + + c1 = (t1 > c1 ? c1 : t1); + c2 = (t2 > c2 ? c2 : t2); + } + a2 = c2 - c1 - skew; + + printf + ("%-20s: Encrypt at %7.3f, Decrypt at %7.3f\n", cipher_descriptor[x].name, a1/(double)cipher_descriptor[x].block_length, a2/(double)cipher_descriptor[x].block_length); + +#undef DO2 +#undef DO1 + } + + return 0; +} + +int time_hash(void) +{ + unsigned long x, y1, len; + ulong64 t1, t2, c1, c2; + hash_state md; + void (*func)(hash_state *, const unsigned char *, unsigned long); + unsigned char pt[MAXBLOCKSIZE]; + + + printf ("\n\nHASH Time Trials for:\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + hash_descriptor[x].init(&md); + +#define DO1 func(&md,pt,len); +#define DO2 DO1 DO1 + + func = hash_descriptor[x].process; + len = hash_descriptor[x].blocksize; + + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read() - t1; + c1 = (t1 > c1) ? c1 : t1; + c2 = (t2 > c2) ? c2 : t2; + } + t1 = c2 - c1 - skew; + t1 = ((t1 * CONST64(1000))) / ((ulong64)hash_descriptor[x].blocksize); + + printf + ("%-20s: Process at %9.3f\n", hash_descriptor[x].name, t1 / 1000.0); + +#undef DO2 +#undef DO1 + } + + return 0; +} + +int main(void) +{ + reg_algs(); + + printf("Timings for ciphers and hashes. Times are listed as cycles per byte processed.\n\n"); + +// init_timer(); + time_cipher(); + time_keysched(); + time_hash(); + + return EXIT_SUCCESS; +} + diff --git a/des.c b/des.c index eb8aa61..6c5ac35 100644 --- a/des.c +++ b/des.c @@ -30,12 +30,12 @@ const struct _cipher_descriptor des3_desc = &des3_keysize }; -static const unsigned long bytebit[8] = +static const ulong32 bytebit[8] = { 0200, 0100, 040, 020, 010, 04, 02, 01 }; -static const unsigned long bigbyte[24] = +static const ulong32 bigbyte[24] = { 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, @@ -69,7 +69,7 @@ static const unsigned char pc2[48] = { }; -static const unsigned long SP1[64] = +static const ulong32 SP1[64] = { 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, @@ -89,7 +89,7 @@ static const unsigned long SP1[64] = 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL }; -static const unsigned long SP2[64] = +static const ulong32 SP2[64] = { 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, @@ -109,7 +109,7 @@ static const unsigned long SP2[64] = 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL }; -static const unsigned long SP3[64] = +static const ulong32 SP3[64] = { 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, @@ -129,7 +129,7 @@ static const unsigned long SP3[64] = 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL }; -static const unsigned long SP4[64] = +static const ulong32 SP4[64] = { 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, @@ -149,7 +149,7 @@ static const unsigned long SP4[64] = 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL }; -static const unsigned long SP5[64] = +static const ulong32 SP5[64] = { 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, @@ -169,7 +169,7 @@ static const unsigned long SP5[64] = 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL }; -static const unsigned long SP6[64] = +static const ulong32 SP6[64] = { 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, @@ -189,7 +189,7 @@ static const unsigned long SP6[64] = 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL }; -static const unsigned long SP7[64] = +static const ulong32 SP7[64] = { 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, @@ -209,7 +209,7 @@ static const unsigned long SP7[64] = 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL }; -static const unsigned long SP8[64] = +static const ulong32 SP8[64] = { 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, @@ -229,20 +229,1070 @@ static const unsigned long SP8[64] = 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL }; +#ifndef SMALL_CODE -static void cookey(const unsigned long *raw1, unsigned long *keyout); +static const ulong64 des_ip[8][256] = { + +{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000000000010), CONST64(0x0000001000000010), + CONST64(0x0000100000000000), CONST64(0x0000101000000000), CONST64(0x0000100000000010), CONST64(0x0000101000000010), + CONST64(0x0000000000001000), CONST64(0x0000001000001000), CONST64(0x0000000000001010), CONST64(0x0000001000001010), + CONST64(0x0000100000001000), CONST64(0x0000101000001000), CONST64(0x0000100000001010), CONST64(0x0000101000001010), + CONST64(0x0010000000000000), CONST64(0x0010001000000000), CONST64(0x0010000000000010), CONST64(0x0010001000000010), + CONST64(0x0010100000000000), CONST64(0x0010101000000000), CONST64(0x0010100000000010), CONST64(0x0010101000000010), + CONST64(0x0010000000001000), CONST64(0x0010001000001000), CONST64(0x0010000000001010), CONST64(0x0010001000001010), + CONST64(0x0010100000001000), CONST64(0x0010101000001000), CONST64(0x0010100000001010), CONST64(0x0010101000001010), + CONST64(0x0000000000100000), CONST64(0x0000001000100000), CONST64(0x0000000000100010), CONST64(0x0000001000100010), + CONST64(0x0000100000100000), CONST64(0x0000101000100000), CONST64(0x0000100000100010), CONST64(0x0000101000100010), + CONST64(0x0000000000101000), CONST64(0x0000001000101000), CONST64(0x0000000000101010), CONST64(0x0000001000101010), + CONST64(0x0000100000101000), CONST64(0x0000101000101000), CONST64(0x0000100000101010), CONST64(0x0000101000101010), + CONST64(0x0010000000100000), CONST64(0x0010001000100000), CONST64(0x0010000000100010), CONST64(0x0010001000100010), + CONST64(0x0010100000100000), CONST64(0x0010101000100000), CONST64(0x0010100000100010), CONST64(0x0010101000100010), + CONST64(0x0010000000101000), CONST64(0x0010001000101000), CONST64(0x0010000000101010), CONST64(0x0010001000101010), + CONST64(0x0010100000101000), CONST64(0x0010101000101000), CONST64(0x0010100000101010), CONST64(0x0010101000101010), + CONST64(0x1000000000000000), CONST64(0x1000001000000000), CONST64(0x1000000000000010), CONST64(0x1000001000000010), + CONST64(0x1000100000000000), CONST64(0x1000101000000000), CONST64(0x1000100000000010), CONST64(0x1000101000000010), + CONST64(0x1000000000001000), CONST64(0x1000001000001000), CONST64(0x1000000000001010), CONST64(0x1000001000001010), + CONST64(0x1000100000001000), CONST64(0x1000101000001000), CONST64(0x1000100000001010), CONST64(0x1000101000001010), + CONST64(0x1010000000000000), CONST64(0x1010001000000000), CONST64(0x1010000000000010), CONST64(0x1010001000000010), + CONST64(0x1010100000000000), CONST64(0x1010101000000000), CONST64(0x1010100000000010), CONST64(0x1010101000000010), + CONST64(0x1010000000001000), CONST64(0x1010001000001000), CONST64(0x1010000000001010), CONST64(0x1010001000001010), + CONST64(0x1010100000001000), CONST64(0x1010101000001000), CONST64(0x1010100000001010), CONST64(0x1010101000001010), + CONST64(0x1000000000100000), CONST64(0x1000001000100000), CONST64(0x1000000000100010), CONST64(0x1000001000100010), + CONST64(0x1000100000100000), CONST64(0x1000101000100000), CONST64(0x1000100000100010), CONST64(0x1000101000100010), + CONST64(0x1000000000101000), CONST64(0x1000001000101000), CONST64(0x1000000000101010), CONST64(0x1000001000101010), + CONST64(0x1000100000101000), CONST64(0x1000101000101000), CONST64(0x1000100000101010), CONST64(0x1000101000101010), + CONST64(0x1010000000100000), CONST64(0x1010001000100000), CONST64(0x1010000000100010), CONST64(0x1010001000100010), + CONST64(0x1010100000100000), CONST64(0x1010101000100000), CONST64(0x1010100000100010), CONST64(0x1010101000100010), + CONST64(0x1010000000101000), CONST64(0x1010001000101000), CONST64(0x1010000000101010), CONST64(0x1010001000101010), + CONST64(0x1010100000101000), CONST64(0x1010101000101000), CONST64(0x1010100000101010), CONST64(0x1010101000101010), + CONST64(0x0000000010000000), CONST64(0x0000001010000000), CONST64(0x0000000010000010), CONST64(0x0000001010000010), + CONST64(0x0000100010000000), CONST64(0x0000101010000000), CONST64(0x0000100010000010), CONST64(0x0000101010000010), + CONST64(0x0000000010001000), CONST64(0x0000001010001000), CONST64(0x0000000010001010), CONST64(0x0000001010001010), + CONST64(0x0000100010001000), CONST64(0x0000101010001000), CONST64(0x0000100010001010), CONST64(0x0000101010001010), + CONST64(0x0010000010000000), CONST64(0x0010001010000000), CONST64(0x0010000010000010), CONST64(0x0010001010000010), + CONST64(0x0010100010000000), CONST64(0x0010101010000000), CONST64(0x0010100010000010), CONST64(0x0010101010000010), + CONST64(0x0010000010001000), CONST64(0x0010001010001000), CONST64(0x0010000010001010), CONST64(0x0010001010001010), + CONST64(0x0010100010001000), CONST64(0x0010101010001000), CONST64(0x0010100010001010), CONST64(0x0010101010001010), + CONST64(0x0000000010100000), CONST64(0x0000001010100000), CONST64(0x0000000010100010), CONST64(0x0000001010100010), + CONST64(0x0000100010100000), CONST64(0x0000101010100000), CONST64(0x0000100010100010), CONST64(0x0000101010100010), + CONST64(0x0000000010101000), CONST64(0x0000001010101000), CONST64(0x0000000010101010), CONST64(0x0000001010101010), + CONST64(0x0000100010101000), CONST64(0x0000101010101000), CONST64(0x0000100010101010), CONST64(0x0000101010101010), + CONST64(0x0010000010100000), CONST64(0x0010001010100000), CONST64(0x0010000010100010), CONST64(0x0010001010100010), + CONST64(0x0010100010100000), CONST64(0x0010101010100000), CONST64(0x0010100010100010), CONST64(0x0010101010100010), + CONST64(0x0010000010101000), CONST64(0x0010001010101000), CONST64(0x0010000010101010), CONST64(0x0010001010101010), + CONST64(0x0010100010101000), CONST64(0x0010101010101000), CONST64(0x0010100010101010), CONST64(0x0010101010101010), + CONST64(0x1000000010000000), CONST64(0x1000001010000000), CONST64(0x1000000010000010), CONST64(0x1000001010000010), + CONST64(0x1000100010000000), CONST64(0x1000101010000000), CONST64(0x1000100010000010), CONST64(0x1000101010000010), + CONST64(0x1000000010001000), CONST64(0x1000001010001000), CONST64(0x1000000010001010), CONST64(0x1000001010001010), + CONST64(0x1000100010001000), CONST64(0x1000101010001000), CONST64(0x1000100010001010), CONST64(0x1000101010001010), + CONST64(0x1010000010000000), CONST64(0x1010001010000000), CONST64(0x1010000010000010), CONST64(0x1010001010000010), + CONST64(0x1010100010000000), CONST64(0x1010101010000000), CONST64(0x1010100010000010), CONST64(0x1010101010000010), + CONST64(0x1010000010001000), CONST64(0x1010001010001000), CONST64(0x1010000010001010), CONST64(0x1010001010001010), + CONST64(0x1010100010001000), CONST64(0x1010101010001000), CONST64(0x1010100010001010), CONST64(0x1010101010001010), + CONST64(0x1000000010100000), CONST64(0x1000001010100000), CONST64(0x1000000010100010), CONST64(0x1000001010100010), + CONST64(0x1000100010100000), CONST64(0x1000101010100000), CONST64(0x1000100010100010), CONST64(0x1000101010100010), + CONST64(0x1000000010101000), CONST64(0x1000001010101000), CONST64(0x1000000010101010), CONST64(0x1000001010101010), + CONST64(0x1000100010101000), CONST64(0x1000101010101000), CONST64(0x1000100010101010), CONST64(0x1000101010101010), + CONST64(0x1010000010100000), CONST64(0x1010001010100000), CONST64(0x1010000010100010), CONST64(0x1010001010100010), + CONST64(0x1010100010100000), CONST64(0x1010101010100000), CONST64(0x1010100010100010), CONST64(0x1010101010100010), + CONST64(0x1010000010101000), CONST64(0x1010001010101000), CONST64(0x1010000010101010), CONST64(0x1010001010101010), + CONST64(0x1010100010101000), CONST64(0x1010101010101000), CONST64(0x1010100010101010), CONST64(0x1010101010101010) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000000000008), CONST64(0x0000000800000008), + CONST64(0x0000080000000000), CONST64(0x0000080800000000), CONST64(0x0000080000000008), CONST64(0x0000080800000008), + CONST64(0x0000000000000800), CONST64(0x0000000800000800), CONST64(0x0000000000000808), CONST64(0x0000000800000808), + CONST64(0x0000080000000800), CONST64(0x0000080800000800), CONST64(0x0000080000000808), CONST64(0x0000080800000808), + CONST64(0x0008000000000000), CONST64(0x0008000800000000), CONST64(0x0008000000000008), CONST64(0x0008000800000008), + CONST64(0x0008080000000000), CONST64(0x0008080800000000), CONST64(0x0008080000000008), CONST64(0x0008080800000008), + CONST64(0x0008000000000800), CONST64(0x0008000800000800), CONST64(0x0008000000000808), CONST64(0x0008000800000808), + CONST64(0x0008080000000800), CONST64(0x0008080800000800), CONST64(0x0008080000000808), CONST64(0x0008080800000808), + CONST64(0x0000000000080000), CONST64(0x0000000800080000), CONST64(0x0000000000080008), CONST64(0x0000000800080008), + CONST64(0x0000080000080000), CONST64(0x0000080800080000), CONST64(0x0000080000080008), CONST64(0x0000080800080008), + CONST64(0x0000000000080800), CONST64(0x0000000800080800), CONST64(0x0000000000080808), CONST64(0x0000000800080808), + CONST64(0x0000080000080800), CONST64(0x0000080800080800), CONST64(0x0000080000080808), CONST64(0x0000080800080808), + CONST64(0x0008000000080000), CONST64(0x0008000800080000), CONST64(0x0008000000080008), CONST64(0x0008000800080008), + CONST64(0x0008080000080000), CONST64(0x0008080800080000), CONST64(0x0008080000080008), CONST64(0x0008080800080008), + CONST64(0x0008000000080800), CONST64(0x0008000800080800), CONST64(0x0008000000080808), CONST64(0x0008000800080808), + CONST64(0x0008080000080800), CONST64(0x0008080800080800), CONST64(0x0008080000080808), CONST64(0x0008080800080808), + CONST64(0x0800000000000000), CONST64(0x0800000800000000), CONST64(0x0800000000000008), CONST64(0x0800000800000008), + CONST64(0x0800080000000000), CONST64(0x0800080800000000), CONST64(0x0800080000000008), CONST64(0x0800080800000008), + CONST64(0x0800000000000800), CONST64(0x0800000800000800), CONST64(0x0800000000000808), CONST64(0x0800000800000808), + CONST64(0x0800080000000800), CONST64(0x0800080800000800), CONST64(0x0800080000000808), CONST64(0x0800080800000808), + CONST64(0x0808000000000000), CONST64(0x0808000800000000), CONST64(0x0808000000000008), CONST64(0x0808000800000008), + CONST64(0x0808080000000000), CONST64(0x0808080800000000), CONST64(0x0808080000000008), CONST64(0x0808080800000008), + CONST64(0x0808000000000800), CONST64(0x0808000800000800), CONST64(0x0808000000000808), CONST64(0x0808000800000808), + CONST64(0x0808080000000800), CONST64(0x0808080800000800), CONST64(0x0808080000000808), CONST64(0x0808080800000808), + CONST64(0x0800000000080000), CONST64(0x0800000800080000), CONST64(0x0800000000080008), CONST64(0x0800000800080008), + CONST64(0x0800080000080000), CONST64(0x0800080800080000), CONST64(0x0800080000080008), CONST64(0x0800080800080008), + CONST64(0x0800000000080800), CONST64(0x0800000800080800), CONST64(0x0800000000080808), CONST64(0x0800000800080808), + CONST64(0x0800080000080800), CONST64(0x0800080800080800), CONST64(0x0800080000080808), CONST64(0x0800080800080808), + CONST64(0x0808000000080000), CONST64(0x0808000800080000), CONST64(0x0808000000080008), CONST64(0x0808000800080008), + CONST64(0x0808080000080000), CONST64(0x0808080800080000), CONST64(0x0808080000080008), CONST64(0x0808080800080008), + CONST64(0x0808000000080800), CONST64(0x0808000800080800), CONST64(0x0808000000080808), CONST64(0x0808000800080808), + CONST64(0x0808080000080800), CONST64(0x0808080800080800), CONST64(0x0808080000080808), CONST64(0x0808080800080808), + CONST64(0x0000000008000000), CONST64(0x0000000808000000), CONST64(0x0000000008000008), CONST64(0x0000000808000008), + CONST64(0x0000080008000000), CONST64(0x0000080808000000), CONST64(0x0000080008000008), CONST64(0x0000080808000008), + CONST64(0x0000000008000800), CONST64(0x0000000808000800), CONST64(0x0000000008000808), CONST64(0x0000000808000808), + CONST64(0x0000080008000800), CONST64(0x0000080808000800), CONST64(0x0000080008000808), CONST64(0x0000080808000808), + CONST64(0x0008000008000000), CONST64(0x0008000808000000), CONST64(0x0008000008000008), CONST64(0x0008000808000008), + CONST64(0x0008080008000000), CONST64(0x0008080808000000), CONST64(0x0008080008000008), CONST64(0x0008080808000008), + CONST64(0x0008000008000800), CONST64(0x0008000808000800), CONST64(0x0008000008000808), CONST64(0x0008000808000808), + CONST64(0x0008080008000800), CONST64(0x0008080808000800), CONST64(0x0008080008000808), CONST64(0x0008080808000808), + CONST64(0x0000000008080000), CONST64(0x0000000808080000), CONST64(0x0000000008080008), CONST64(0x0000000808080008), + CONST64(0x0000080008080000), CONST64(0x0000080808080000), CONST64(0x0000080008080008), CONST64(0x0000080808080008), + CONST64(0x0000000008080800), CONST64(0x0000000808080800), CONST64(0x0000000008080808), CONST64(0x0000000808080808), + CONST64(0x0000080008080800), CONST64(0x0000080808080800), CONST64(0x0000080008080808), CONST64(0x0000080808080808), + CONST64(0x0008000008080000), CONST64(0x0008000808080000), CONST64(0x0008000008080008), CONST64(0x0008000808080008), + CONST64(0x0008080008080000), CONST64(0x0008080808080000), CONST64(0x0008080008080008), CONST64(0x0008080808080008), + CONST64(0x0008000008080800), CONST64(0x0008000808080800), CONST64(0x0008000008080808), CONST64(0x0008000808080808), + CONST64(0x0008080008080800), CONST64(0x0008080808080800), CONST64(0x0008080008080808), CONST64(0x0008080808080808), + CONST64(0x0800000008000000), CONST64(0x0800000808000000), CONST64(0x0800000008000008), CONST64(0x0800000808000008), + CONST64(0x0800080008000000), CONST64(0x0800080808000000), CONST64(0x0800080008000008), CONST64(0x0800080808000008), + CONST64(0x0800000008000800), CONST64(0x0800000808000800), CONST64(0x0800000008000808), CONST64(0x0800000808000808), + CONST64(0x0800080008000800), CONST64(0x0800080808000800), CONST64(0x0800080008000808), CONST64(0x0800080808000808), + CONST64(0x0808000008000000), CONST64(0x0808000808000000), CONST64(0x0808000008000008), CONST64(0x0808000808000008), + CONST64(0x0808080008000000), CONST64(0x0808080808000000), CONST64(0x0808080008000008), CONST64(0x0808080808000008), + CONST64(0x0808000008000800), CONST64(0x0808000808000800), CONST64(0x0808000008000808), CONST64(0x0808000808000808), + CONST64(0x0808080008000800), CONST64(0x0808080808000800), CONST64(0x0808080008000808), CONST64(0x0808080808000808), + CONST64(0x0800000008080000), CONST64(0x0800000808080000), CONST64(0x0800000008080008), CONST64(0x0800000808080008), + CONST64(0x0800080008080000), CONST64(0x0800080808080000), CONST64(0x0800080008080008), CONST64(0x0800080808080008), + CONST64(0x0800000008080800), CONST64(0x0800000808080800), CONST64(0x0800000008080808), CONST64(0x0800000808080808), + CONST64(0x0800080008080800), CONST64(0x0800080808080800), CONST64(0x0800080008080808), CONST64(0x0800080808080808), + CONST64(0x0808000008080000), CONST64(0x0808000808080000), CONST64(0x0808000008080008), CONST64(0x0808000808080008), + CONST64(0x0808080008080000), CONST64(0x0808080808080000), CONST64(0x0808080008080008), CONST64(0x0808080808080008), + CONST64(0x0808000008080800), CONST64(0x0808000808080800), CONST64(0x0808000008080808), CONST64(0x0808000808080808), + CONST64(0x0808080008080800), CONST64(0x0808080808080800), CONST64(0x0808080008080808), CONST64(0x0808080808080808) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000000000004), CONST64(0x0000000400000004), + CONST64(0x0000040000000000), CONST64(0x0000040400000000), CONST64(0x0000040000000004), CONST64(0x0000040400000004), + CONST64(0x0000000000000400), CONST64(0x0000000400000400), CONST64(0x0000000000000404), CONST64(0x0000000400000404), + CONST64(0x0000040000000400), CONST64(0x0000040400000400), CONST64(0x0000040000000404), CONST64(0x0000040400000404), + CONST64(0x0004000000000000), CONST64(0x0004000400000000), CONST64(0x0004000000000004), CONST64(0x0004000400000004), + CONST64(0x0004040000000000), CONST64(0x0004040400000000), CONST64(0x0004040000000004), CONST64(0x0004040400000004), + CONST64(0x0004000000000400), CONST64(0x0004000400000400), CONST64(0x0004000000000404), CONST64(0x0004000400000404), + CONST64(0x0004040000000400), CONST64(0x0004040400000400), CONST64(0x0004040000000404), CONST64(0x0004040400000404), + CONST64(0x0000000000040000), CONST64(0x0000000400040000), CONST64(0x0000000000040004), CONST64(0x0000000400040004), + CONST64(0x0000040000040000), CONST64(0x0000040400040000), CONST64(0x0000040000040004), CONST64(0x0000040400040004), + CONST64(0x0000000000040400), CONST64(0x0000000400040400), CONST64(0x0000000000040404), CONST64(0x0000000400040404), + CONST64(0x0000040000040400), CONST64(0x0000040400040400), CONST64(0x0000040000040404), CONST64(0x0000040400040404), + CONST64(0x0004000000040000), CONST64(0x0004000400040000), CONST64(0x0004000000040004), CONST64(0x0004000400040004), + CONST64(0x0004040000040000), CONST64(0x0004040400040000), CONST64(0x0004040000040004), CONST64(0x0004040400040004), + CONST64(0x0004000000040400), CONST64(0x0004000400040400), CONST64(0x0004000000040404), CONST64(0x0004000400040404), + CONST64(0x0004040000040400), CONST64(0x0004040400040400), CONST64(0x0004040000040404), CONST64(0x0004040400040404), + CONST64(0x0400000000000000), CONST64(0x0400000400000000), CONST64(0x0400000000000004), CONST64(0x0400000400000004), + CONST64(0x0400040000000000), CONST64(0x0400040400000000), CONST64(0x0400040000000004), CONST64(0x0400040400000004), + CONST64(0x0400000000000400), CONST64(0x0400000400000400), CONST64(0x0400000000000404), CONST64(0x0400000400000404), + CONST64(0x0400040000000400), CONST64(0x0400040400000400), CONST64(0x0400040000000404), CONST64(0x0400040400000404), + CONST64(0x0404000000000000), CONST64(0x0404000400000000), CONST64(0x0404000000000004), CONST64(0x0404000400000004), + CONST64(0x0404040000000000), CONST64(0x0404040400000000), CONST64(0x0404040000000004), CONST64(0x0404040400000004), + CONST64(0x0404000000000400), CONST64(0x0404000400000400), CONST64(0x0404000000000404), CONST64(0x0404000400000404), + CONST64(0x0404040000000400), CONST64(0x0404040400000400), CONST64(0x0404040000000404), CONST64(0x0404040400000404), + CONST64(0x0400000000040000), CONST64(0x0400000400040000), CONST64(0x0400000000040004), CONST64(0x0400000400040004), + CONST64(0x0400040000040000), CONST64(0x0400040400040000), CONST64(0x0400040000040004), CONST64(0x0400040400040004), + CONST64(0x0400000000040400), CONST64(0x0400000400040400), CONST64(0x0400000000040404), CONST64(0x0400000400040404), + CONST64(0x0400040000040400), CONST64(0x0400040400040400), CONST64(0x0400040000040404), CONST64(0x0400040400040404), + CONST64(0x0404000000040000), CONST64(0x0404000400040000), CONST64(0x0404000000040004), CONST64(0x0404000400040004), + CONST64(0x0404040000040000), CONST64(0x0404040400040000), CONST64(0x0404040000040004), CONST64(0x0404040400040004), + CONST64(0x0404000000040400), CONST64(0x0404000400040400), CONST64(0x0404000000040404), CONST64(0x0404000400040404), + CONST64(0x0404040000040400), CONST64(0x0404040400040400), CONST64(0x0404040000040404), CONST64(0x0404040400040404), + CONST64(0x0000000004000000), CONST64(0x0000000404000000), CONST64(0x0000000004000004), CONST64(0x0000000404000004), + CONST64(0x0000040004000000), CONST64(0x0000040404000000), CONST64(0x0000040004000004), CONST64(0x0000040404000004), + CONST64(0x0000000004000400), CONST64(0x0000000404000400), CONST64(0x0000000004000404), CONST64(0x0000000404000404), + CONST64(0x0000040004000400), CONST64(0x0000040404000400), CONST64(0x0000040004000404), CONST64(0x0000040404000404), + CONST64(0x0004000004000000), CONST64(0x0004000404000000), CONST64(0x0004000004000004), CONST64(0x0004000404000004), + CONST64(0x0004040004000000), CONST64(0x0004040404000000), CONST64(0x0004040004000004), CONST64(0x0004040404000004), + CONST64(0x0004000004000400), CONST64(0x0004000404000400), CONST64(0x0004000004000404), CONST64(0x0004000404000404), + CONST64(0x0004040004000400), CONST64(0x0004040404000400), CONST64(0x0004040004000404), CONST64(0x0004040404000404), + CONST64(0x0000000004040000), CONST64(0x0000000404040000), CONST64(0x0000000004040004), CONST64(0x0000000404040004), + CONST64(0x0000040004040000), CONST64(0x0000040404040000), CONST64(0x0000040004040004), CONST64(0x0000040404040004), + CONST64(0x0000000004040400), CONST64(0x0000000404040400), CONST64(0x0000000004040404), CONST64(0x0000000404040404), + CONST64(0x0000040004040400), CONST64(0x0000040404040400), CONST64(0x0000040004040404), CONST64(0x0000040404040404), + CONST64(0x0004000004040000), CONST64(0x0004000404040000), CONST64(0x0004000004040004), CONST64(0x0004000404040004), + CONST64(0x0004040004040000), CONST64(0x0004040404040000), CONST64(0x0004040004040004), CONST64(0x0004040404040004), + CONST64(0x0004000004040400), CONST64(0x0004000404040400), CONST64(0x0004000004040404), CONST64(0x0004000404040404), + CONST64(0x0004040004040400), CONST64(0x0004040404040400), CONST64(0x0004040004040404), CONST64(0x0004040404040404), + CONST64(0x0400000004000000), CONST64(0x0400000404000000), CONST64(0x0400000004000004), CONST64(0x0400000404000004), + CONST64(0x0400040004000000), CONST64(0x0400040404000000), CONST64(0x0400040004000004), CONST64(0x0400040404000004), + CONST64(0x0400000004000400), CONST64(0x0400000404000400), CONST64(0x0400000004000404), CONST64(0x0400000404000404), + CONST64(0x0400040004000400), CONST64(0x0400040404000400), CONST64(0x0400040004000404), CONST64(0x0400040404000404), + CONST64(0x0404000004000000), CONST64(0x0404000404000000), CONST64(0x0404000004000004), CONST64(0x0404000404000004), + CONST64(0x0404040004000000), CONST64(0x0404040404000000), CONST64(0x0404040004000004), CONST64(0x0404040404000004), + CONST64(0x0404000004000400), CONST64(0x0404000404000400), CONST64(0x0404000004000404), CONST64(0x0404000404000404), + CONST64(0x0404040004000400), CONST64(0x0404040404000400), CONST64(0x0404040004000404), CONST64(0x0404040404000404), + CONST64(0x0400000004040000), CONST64(0x0400000404040000), CONST64(0x0400000004040004), CONST64(0x0400000404040004), + CONST64(0x0400040004040000), CONST64(0x0400040404040000), CONST64(0x0400040004040004), CONST64(0x0400040404040004), + CONST64(0x0400000004040400), CONST64(0x0400000404040400), CONST64(0x0400000004040404), CONST64(0x0400000404040404), + CONST64(0x0400040004040400), CONST64(0x0400040404040400), CONST64(0x0400040004040404), CONST64(0x0400040404040404), + CONST64(0x0404000004040000), CONST64(0x0404000404040000), CONST64(0x0404000004040004), CONST64(0x0404000404040004), + CONST64(0x0404040004040000), CONST64(0x0404040404040000), CONST64(0x0404040004040004), CONST64(0x0404040404040004), + CONST64(0x0404000004040400), CONST64(0x0404000404040400), CONST64(0x0404000004040404), CONST64(0x0404000404040404), + CONST64(0x0404040004040400), CONST64(0x0404040404040400), CONST64(0x0404040004040404), CONST64(0x0404040404040404) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000000000002), CONST64(0x0000000200000002), + CONST64(0x0000020000000000), CONST64(0x0000020200000000), CONST64(0x0000020000000002), CONST64(0x0000020200000002), + CONST64(0x0000000000000200), CONST64(0x0000000200000200), CONST64(0x0000000000000202), CONST64(0x0000000200000202), + CONST64(0x0000020000000200), CONST64(0x0000020200000200), CONST64(0x0000020000000202), CONST64(0x0000020200000202), + CONST64(0x0002000000000000), CONST64(0x0002000200000000), CONST64(0x0002000000000002), CONST64(0x0002000200000002), + CONST64(0x0002020000000000), CONST64(0x0002020200000000), CONST64(0x0002020000000002), CONST64(0x0002020200000002), + CONST64(0x0002000000000200), CONST64(0x0002000200000200), CONST64(0x0002000000000202), CONST64(0x0002000200000202), + CONST64(0x0002020000000200), CONST64(0x0002020200000200), CONST64(0x0002020000000202), CONST64(0x0002020200000202), + CONST64(0x0000000000020000), CONST64(0x0000000200020000), CONST64(0x0000000000020002), CONST64(0x0000000200020002), + CONST64(0x0000020000020000), CONST64(0x0000020200020000), CONST64(0x0000020000020002), CONST64(0x0000020200020002), + CONST64(0x0000000000020200), CONST64(0x0000000200020200), CONST64(0x0000000000020202), CONST64(0x0000000200020202), + CONST64(0x0000020000020200), CONST64(0x0000020200020200), CONST64(0x0000020000020202), CONST64(0x0000020200020202), + CONST64(0x0002000000020000), CONST64(0x0002000200020000), CONST64(0x0002000000020002), CONST64(0x0002000200020002), + CONST64(0x0002020000020000), CONST64(0x0002020200020000), CONST64(0x0002020000020002), CONST64(0x0002020200020002), + CONST64(0x0002000000020200), CONST64(0x0002000200020200), CONST64(0x0002000000020202), CONST64(0x0002000200020202), + CONST64(0x0002020000020200), CONST64(0x0002020200020200), CONST64(0x0002020000020202), CONST64(0x0002020200020202), + CONST64(0x0200000000000000), CONST64(0x0200000200000000), CONST64(0x0200000000000002), CONST64(0x0200000200000002), + CONST64(0x0200020000000000), CONST64(0x0200020200000000), CONST64(0x0200020000000002), CONST64(0x0200020200000002), + CONST64(0x0200000000000200), CONST64(0x0200000200000200), CONST64(0x0200000000000202), CONST64(0x0200000200000202), + CONST64(0x0200020000000200), CONST64(0x0200020200000200), CONST64(0x0200020000000202), CONST64(0x0200020200000202), + CONST64(0x0202000000000000), CONST64(0x0202000200000000), CONST64(0x0202000000000002), CONST64(0x0202000200000002), + CONST64(0x0202020000000000), CONST64(0x0202020200000000), CONST64(0x0202020000000002), CONST64(0x0202020200000002), + CONST64(0x0202000000000200), CONST64(0x0202000200000200), CONST64(0x0202000000000202), CONST64(0x0202000200000202), + CONST64(0x0202020000000200), CONST64(0x0202020200000200), CONST64(0x0202020000000202), CONST64(0x0202020200000202), + CONST64(0x0200000000020000), CONST64(0x0200000200020000), CONST64(0x0200000000020002), CONST64(0x0200000200020002), + CONST64(0x0200020000020000), CONST64(0x0200020200020000), CONST64(0x0200020000020002), CONST64(0x0200020200020002), + CONST64(0x0200000000020200), CONST64(0x0200000200020200), CONST64(0x0200000000020202), CONST64(0x0200000200020202), + CONST64(0x0200020000020200), CONST64(0x0200020200020200), CONST64(0x0200020000020202), CONST64(0x0200020200020202), + CONST64(0x0202000000020000), CONST64(0x0202000200020000), CONST64(0x0202000000020002), CONST64(0x0202000200020002), + CONST64(0x0202020000020000), CONST64(0x0202020200020000), CONST64(0x0202020000020002), CONST64(0x0202020200020002), + CONST64(0x0202000000020200), CONST64(0x0202000200020200), CONST64(0x0202000000020202), CONST64(0x0202000200020202), + CONST64(0x0202020000020200), CONST64(0x0202020200020200), CONST64(0x0202020000020202), CONST64(0x0202020200020202), + CONST64(0x0000000002000000), CONST64(0x0000000202000000), CONST64(0x0000000002000002), CONST64(0x0000000202000002), + CONST64(0x0000020002000000), CONST64(0x0000020202000000), CONST64(0x0000020002000002), CONST64(0x0000020202000002), + CONST64(0x0000000002000200), CONST64(0x0000000202000200), CONST64(0x0000000002000202), CONST64(0x0000000202000202), + CONST64(0x0000020002000200), CONST64(0x0000020202000200), CONST64(0x0000020002000202), CONST64(0x0000020202000202), + CONST64(0x0002000002000000), CONST64(0x0002000202000000), CONST64(0x0002000002000002), CONST64(0x0002000202000002), + CONST64(0x0002020002000000), CONST64(0x0002020202000000), CONST64(0x0002020002000002), CONST64(0x0002020202000002), + CONST64(0x0002000002000200), CONST64(0x0002000202000200), CONST64(0x0002000002000202), CONST64(0x0002000202000202), + CONST64(0x0002020002000200), CONST64(0x0002020202000200), CONST64(0x0002020002000202), CONST64(0x0002020202000202), + CONST64(0x0000000002020000), CONST64(0x0000000202020000), CONST64(0x0000000002020002), CONST64(0x0000000202020002), + CONST64(0x0000020002020000), CONST64(0x0000020202020000), CONST64(0x0000020002020002), CONST64(0x0000020202020002), + CONST64(0x0000000002020200), CONST64(0x0000000202020200), CONST64(0x0000000002020202), CONST64(0x0000000202020202), + CONST64(0x0000020002020200), CONST64(0x0000020202020200), CONST64(0x0000020002020202), CONST64(0x0000020202020202), + CONST64(0x0002000002020000), CONST64(0x0002000202020000), CONST64(0x0002000002020002), CONST64(0x0002000202020002), + CONST64(0x0002020002020000), CONST64(0x0002020202020000), CONST64(0x0002020002020002), CONST64(0x0002020202020002), + CONST64(0x0002000002020200), CONST64(0x0002000202020200), CONST64(0x0002000002020202), CONST64(0x0002000202020202), + CONST64(0x0002020002020200), CONST64(0x0002020202020200), CONST64(0x0002020002020202), CONST64(0x0002020202020202), + CONST64(0x0200000002000000), CONST64(0x0200000202000000), CONST64(0x0200000002000002), CONST64(0x0200000202000002), + CONST64(0x0200020002000000), CONST64(0x0200020202000000), CONST64(0x0200020002000002), CONST64(0x0200020202000002), + CONST64(0x0200000002000200), CONST64(0x0200000202000200), CONST64(0x0200000002000202), CONST64(0x0200000202000202), + CONST64(0x0200020002000200), CONST64(0x0200020202000200), CONST64(0x0200020002000202), CONST64(0x0200020202000202), + CONST64(0x0202000002000000), CONST64(0x0202000202000000), CONST64(0x0202000002000002), CONST64(0x0202000202000002), + CONST64(0x0202020002000000), CONST64(0x0202020202000000), CONST64(0x0202020002000002), CONST64(0x0202020202000002), + CONST64(0x0202000002000200), CONST64(0x0202000202000200), CONST64(0x0202000002000202), CONST64(0x0202000202000202), + CONST64(0x0202020002000200), CONST64(0x0202020202000200), CONST64(0x0202020002000202), CONST64(0x0202020202000202), + CONST64(0x0200000002020000), CONST64(0x0200000202020000), CONST64(0x0200000002020002), CONST64(0x0200000202020002), + CONST64(0x0200020002020000), CONST64(0x0200020202020000), CONST64(0x0200020002020002), CONST64(0x0200020202020002), + CONST64(0x0200000002020200), CONST64(0x0200000202020200), CONST64(0x0200000002020202), CONST64(0x0200000202020202), + CONST64(0x0200020002020200), CONST64(0x0200020202020200), CONST64(0x0200020002020202), CONST64(0x0200020202020202), + CONST64(0x0202000002020000), CONST64(0x0202000202020000), CONST64(0x0202000002020002), CONST64(0x0202000202020002), + CONST64(0x0202020002020000), CONST64(0x0202020202020000), CONST64(0x0202020002020002), CONST64(0x0202020202020002), + CONST64(0x0202000002020200), CONST64(0x0202000202020200), CONST64(0x0202000002020202), CONST64(0x0202000202020202), + CONST64(0x0202020002020200), CONST64(0x0202020202020200), CONST64(0x0202020002020202), CONST64(0x0202020202020202) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000010000000000), CONST64(0x0000000000000100), CONST64(0x0000010000000100), + CONST64(0x0001000000000000), CONST64(0x0001010000000000), CONST64(0x0001000000000100), CONST64(0x0001010000000100), + CONST64(0x0000000000010000), CONST64(0x0000010000010000), CONST64(0x0000000000010100), CONST64(0x0000010000010100), + CONST64(0x0001000000010000), CONST64(0x0001010000010000), CONST64(0x0001000000010100), CONST64(0x0001010000010100), + CONST64(0x0100000000000000), CONST64(0x0100010000000000), CONST64(0x0100000000000100), CONST64(0x0100010000000100), + CONST64(0x0101000000000000), CONST64(0x0101010000000000), CONST64(0x0101000000000100), CONST64(0x0101010000000100), + CONST64(0x0100000000010000), CONST64(0x0100010000010000), CONST64(0x0100000000010100), CONST64(0x0100010000010100), + CONST64(0x0101000000010000), CONST64(0x0101010000010000), CONST64(0x0101000000010100), CONST64(0x0101010000010100), + CONST64(0x0000000001000000), CONST64(0x0000010001000000), CONST64(0x0000000001000100), CONST64(0x0000010001000100), + CONST64(0x0001000001000000), CONST64(0x0001010001000000), CONST64(0x0001000001000100), CONST64(0x0001010001000100), + CONST64(0x0000000001010000), CONST64(0x0000010001010000), CONST64(0x0000000001010100), CONST64(0x0000010001010100), + CONST64(0x0001000001010000), CONST64(0x0001010001010000), CONST64(0x0001000001010100), CONST64(0x0001010001010100), + CONST64(0x0100000001000000), CONST64(0x0100010001000000), CONST64(0x0100000001000100), CONST64(0x0100010001000100), + CONST64(0x0101000001000000), CONST64(0x0101010001000000), CONST64(0x0101000001000100), CONST64(0x0101010001000100), + CONST64(0x0100000001010000), CONST64(0x0100010001010000), CONST64(0x0100000001010100), CONST64(0x0100010001010100), + CONST64(0x0101000001010000), CONST64(0x0101010001010000), CONST64(0x0101000001010100), CONST64(0x0101010001010100), + CONST64(0x0000000100000000), CONST64(0x0000010100000000), CONST64(0x0000000100000100), CONST64(0x0000010100000100), + CONST64(0x0001000100000000), CONST64(0x0001010100000000), CONST64(0x0001000100000100), CONST64(0x0001010100000100), + CONST64(0x0000000100010000), CONST64(0x0000010100010000), CONST64(0x0000000100010100), CONST64(0x0000010100010100), + CONST64(0x0001000100010000), CONST64(0x0001010100010000), CONST64(0x0001000100010100), CONST64(0x0001010100010100), + CONST64(0x0100000100000000), CONST64(0x0100010100000000), CONST64(0x0100000100000100), CONST64(0x0100010100000100), + CONST64(0x0101000100000000), CONST64(0x0101010100000000), CONST64(0x0101000100000100), CONST64(0x0101010100000100), + CONST64(0x0100000100010000), CONST64(0x0100010100010000), CONST64(0x0100000100010100), CONST64(0x0100010100010100), + CONST64(0x0101000100010000), CONST64(0x0101010100010000), CONST64(0x0101000100010100), CONST64(0x0101010100010100), + CONST64(0x0000000101000000), CONST64(0x0000010101000000), CONST64(0x0000000101000100), CONST64(0x0000010101000100), + CONST64(0x0001000101000000), CONST64(0x0001010101000000), CONST64(0x0001000101000100), CONST64(0x0001010101000100), + CONST64(0x0000000101010000), CONST64(0x0000010101010000), CONST64(0x0000000101010100), CONST64(0x0000010101010100), + CONST64(0x0001000101010000), CONST64(0x0001010101010000), CONST64(0x0001000101010100), CONST64(0x0001010101010100), + CONST64(0x0100000101000000), CONST64(0x0100010101000000), CONST64(0x0100000101000100), CONST64(0x0100010101000100), + CONST64(0x0101000101000000), CONST64(0x0101010101000000), CONST64(0x0101000101000100), CONST64(0x0101010101000100), + CONST64(0x0100000101010000), CONST64(0x0100010101010000), CONST64(0x0100000101010100), CONST64(0x0100010101010100), + CONST64(0x0101000101010000), CONST64(0x0101010101010000), CONST64(0x0101000101010100), CONST64(0x0101010101010100), + CONST64(0x0000000000000001), CONST64(0x0000010000000001), CONST64(0x0000000000000101), CONST64(0x0000010000000101), + CONST64(0x0001000000000001), CONST64(0x0001010000000001), CONST64(0x0001000000000101), CONST64(0x0001010000000101), + CONST64(0x0000000000010001), CONST64(0x0000010000010001), CONST64(0x0000000000010101), CONST64(0x0000010000010101), + CONST64(0x0001000000010001), CONST64(0x0001010000010001), CONST64(0x0001000000010101), CONST64(0x0001010000010101), + CONST64(0x0100000000000001), CONST64(0x0100010000000001), CONST64(0x0100000000000101), CONST64(0x0100010000000101), + CONST64(0x0101000000000001), CONST64(0x0101010000000001), CONST64(0x0101000000000101), CONST64(0x0101010000000101), + CONST64(0x0100000000010001), CONST64(0x0100010000010001), CONST64(0x0100000000010101), CONST64(0x0100010000010101), + CONST64(0x0101000000010001), CONST64(0x0101010000010001), CONST64(0x0101000000010101), CONST64(0x0101010000010101), + CONST64(0x0000000001000001), CONST64(0x0000010001000001), CONST64(0x0000000001000101), CONST64(0x0000010001000101), + CONST64(0x0001000001000001), CONST64(0x0001010001000001), CONST64(0x0001000001000101), CONST64(0x0001010001000101), + CONST64(0x0000000001010001), CONST64(0x0000010001010001), CONST64(0x0000000001010101), CONST64(0x0000010001010101), + CONST64(0x0001000001010001), CONST64(0x0001010001010001), CONST64(0x0001000001010101), CONST64(0x0001010001010101), + CONST64(0x0100000001000001), CONST64(0x0100010001000001), CONST64(0x0100000001000101), CONST64(0x0100010001000101), + CONST64(0x0101000001000001), CONST64(0x0101010001000001), CONST64(0x0101000001000101), CONST64(0x0101010001000101), + CONST64(0x0100000001010001), CONST64(0x0100010001010001), CONST64(0x0100000001010101), CONST64(0x0100010001010101), + CONST64(0x0101000001010001), CONST64(0x0101010001010001), CONST64(0x0101000001010101), CONST64(0x0101010001010101), + CONST64(0x0000000100000001), CONST64(0x0000010100000001), CONST64(0x0000000100000101), CONST64(0x0000010100000101), + CONST64(0x0001000100000001), CONST64(0x0001010100000001), CONST64(0x0001000100000101), CONST64(0x0001010100000101), + CONST64(0x0000000100010001), CONST64(0x0000010100010001), CONST64(0x0000000100010101), CONST64(0x0000010100010101), + CONST64(0x0001000100010001), CONST64(0x0001010100010001), CONST64(0x0001000100010101), CONST64(0x0001010100010101), + CONST64(0x0100000100000001), CONST64(0x0100010100000001), CONST64(0x0100000100000101), CONST64(0x0100010100000101), + CONST64(0x0101000100000001), CONST64(0x0101010100000001), CONST64(0x0101000100000101), CONST64(0x0101010100000101), + CONST64(0x0100000100010001), CONST64(0x0100010100010001), CONST64(0x0100000100010101), CONST64(0x0100010100010101), + CONST64(0x0101000100010001), CONST64(0x0101010100010001), CONST64(0x0101000100010101), CONST64(0x0101010100010101), + CONST64(0x0000000101000001), CONST64(0x0000010101000001), CONST64(0x0000000101000101), CONST64(0x0000010101000101), + CONST64(0x0001000101000001), CONST64(0x0001010101000001), CONST64(0x0001000101000101), CONST64(0x0001010101000101), + CONST64(0x0000000101010001), CONST64(0x0000010101010001), CONST64(0x0000000101010101), CONST64(0x0000010101010101), + CONST64(0x0001000101010001), CONST64(0x0001010101010001), CONST64(0x0001000101010101), CONST64(0x0001010101010101), + CONST64(0x0100000101000001), CONST64(0x0100010101000001), CONST64(0x0100000101000101), CONST64(0x0100010101000101), + CONST64(0x0101000101000001), CONST64(0x0101010101000001), CONST64(0x0101000101000101), CONST64(0x0101010101000101), + CONST64(0x0100000101010001), CONST64(0x0100010101010001), CONST64(0x0100000101010101), CONST64(0x0100010101010101), + CONST64(0x0101000101010001), CONST64(0x0101010101010001), CONST64(0x0101000101010101), CONST64(0x0101010101010101) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000000000080), CONST64(0x0000008000000080), + CONST64(0x0000800000000000), CONST64(0x0000808000000000), CONST64(0x0000800000000080), CONST64(0x0000808000000080), + CONST64(0x0000000000008000), CONST64(0x0000008000008000), CONST64(0x0000000000008080), CONST64(0x0000008000008080), + CONST64(0x0000800000008000), CONST64(0x0000808000008000), CONST64(0x0000800000008080), CONST64(0x0000808000008080), + CONST64(0x0080000000000000), CONST64(0x0080008000000000), CONST64(0x0080000000000080), CONST64(0x0080008000000080), + CONST64(0x0080800000000000), CONST64(0x0080808000000000), CONST64(0x0080800000000080), CONST64(0x0080808000000080), + CONST64(0x0080000000008000), CONST64(0x0080008000008000), CONST64(0x0080000000008080), CONST64(0x0080008000008080), + CONST64(0x0080800000008000), CONST64(0x0080808000008000), CONST64(0x0080800000008080), CONST64(0x0080808000008080), + CONST64(0x0000000000800000), CONST64(0x0000008000800000), CONST64(0x0000000000800080), CONST64(0x0000008000800080), + CONST64(0x0000800000800000), CONST64(0x0000808000800000), CONST64(0x0000800000800080), CONST64(0x0000808000800080), + CONST64(0x0000000000808000), CONST64(0x0000008000808000), CONST64(0x0000000000808080), CONST64(0x0000008000808080), + CONST64(0x0000800000808000), CONST64(0x0000808000808000), CONST64(0x0000800000808080), CONST64(0x0000808000808080), + CONST64(0x0080000000800000), CONST64(0x0080008000800000), CONST64(0x0080000000800080), CONST64(0x0080008000800080), + CONST64(0x0080800000800000), CONST64(0x0080808000800000), CONST64(0x0080800000800080), CONST64(0x0080808000800080), + CONST64(0x0080000000808000), CONST64(0x0080008000808000), CONST64(0x0080000000808080), CONST64(0x0080008000808080), + CONST64(0x0080800000808000), CONST64(0x0080808000808000), CONST64(0x0080800000808080), CONST64(0x0080808000808080), + CONST64(0x8000000000000000), CONST64(0x8000008000000000), CONST64(0x8000000000000080), CONST64(0x8000008000000080), + CONST64(0x8000800000000000), CONST64(0x8000808000000000), CONST64(0x8000800000000080), CONST64(0x8000808000000080), + CONST64(0x8000000000008000), CONST64(0x8000008000008000), CONST64(0x8000000000008080), CONST64(0x8000008000008080), + CONST64(0x8000800000008000), CONST64(0x8000808000008000), CONST64(0x8000800000008080), CONST64(0x8000808000008080), + CONST64(0x8080000000000000), CONST64(0x8080008000000000), CONST64(0x8080000000000080), CONST64(0x8080008000000080), + CONST64(0x8080800000000000), CONST64(0x8080808000000000), CONST64(0x8080800000000080), CONST64(0x8080808000000080), + CONST64(0x8080000000008000), CONST64(0x8080008000008000), CONST64(0x8080000000008080), CONST64(0x8080008000008080), + CONST64(0x8080800000008000), CONST64(0x8080808000008000), CONST64(0x8080800000008080), CONST64(0x8080808000008080), + CONST64(0x8000000000800000), CONST64(0x8000008000800000), CONST64(0x8000000000800080), CONST64(0x8000008000800080), + CONST64(0x8000800000800000), CONST64(0x8000808000800000), CONST64(0x8000800000800080), CONST64(0x8000808000800080), + CONST64(0x8000000000808000), CONST64(0x8000008000808000), CONST64(0x8000000000808080), CONST64(0x8000008000808080), + CONST64(0x8000800000808000), CONST64(0x8000808000808000), CONST64(0x8000800000808080), CONST64(0x8000808000808080), + CONST64(0x8080000000800000), CONST64(0x8080008000800000), CONST64(0x8080000000800080), CONST64(0x8080008000800080), + CONST64(0x8080800000800000), CONST64(0x8080808000800000), CONST64(0x8080800000800080), CONST64(0x8080808000800080), + CONST64(0x8080000000808000), CONST64(0x8080008000808000), CONST64(0x8080000000808080), CONST64(0x8080008000808080), + CONST64(0x8080800000808000), CONST64(0x8080808000808000), CONST64(0x8080800000808080), CONST64(0x8080808000808080), + CONST64(0x0000000080000000), CONST64(0x0000008080000000), CONST64(0x0000000080000080), CONST64(0x0000008080000080), + CONST64(0x0000800080000000), CONST64(0x0000808080000000), CONST64(0x0000800080000080), CONST64(0x0000808080000080), + CONST64(0x0000000080008000), CONST64(0x0000008080008000), CONST64(0x0000000080008080), CONST64(0x0000008080008080), + CONST64(0x0000800080008000), CONST64(0x0000808080008000), CONST64(0x0000800080008080), CONST64(0x0000808080008080), + CONST64(0x0080000080000000), CONST64(0x0080008080000000), CONST64(0x0080000080000080), CONST64(0x0080008080000080), + CONST64(0x0080800080000000), CONST64(0x0080808080000000), CONST64(0x0080800080000080), CONST64(0x0080808080000080), + CONST64(0x0080000080008000), CONST64(0x0080008080008000), CONST64(0x0080000080008080), CONST64(0x0080008080008080), + CONST64(0x0080800080008000), CONST64(0x0080808080008000), CONST64(0x0080800080008080), CONST64(0x0080808080008080), + CONST64(0x0000000080800000), CONST64(0x0000008080800000), CONST64(0x0000000080800080), CONST64(0x0000008080800080), + CONST64(0x0000800080800000), CONST64(0x0000808080800000), CONST64(0x0000800080800080), CONST64(0x0000808080800080), + CONST64(0x0000000080808000), CONST64(0x0000008080808000), CONST64(0x0000000080808080), CONST64(0x0000008080808080), + CONST64(0x0000800080808000), CONST64(0x0000808080808000), CONST64(0x0000800080808080), CONST64(0x0000808080808080), + CONST64(0x0080000080800000), CONST64(0x0080008080800000), CONST64(0x0080000080800080), CONST64(0x0080008080800080), + CONST64(0x0080800080800000), CONST64(0x0080808080800000), CONST64(0x0080800080800080), CONST64(0x0080808080800080), + CONST64(0x0080000080808000), CONST64(0x0080008080808000), CONST64(0x0080000080808080), CONST64(0x0080008080808080), + CONST64(0x0080800080808000), CONST64(0x0080808080808000), CONST64(0x0080800080808080), CONST64(0x0080808080808080), + CONST64(0x8000000080000000), CONST64(0x8000008080000000), CONST64(0x8000000080000080), CONST64(0x8000008080000080), + CONST64(0x8000800080000000), CONST64(0x8000808080000000), CONST64(0x8000800080000080), CONST64(0x8000808080000080), + CONST64(0x8000000080008000), CONST64(0x8000008080008000), CONST64(0x8000000080008080), CONST64(0x8000008080008080), + CONST64(0x8000800080008000), CONST64(0x8000808080008000), CONST64(0x8000800080008080), CONST64(0x8000808080008080), + CONST64(0x8080000080000000), CONST64(0x8080008080000000), CONST64(0x8080000080000080), CONST64(0x8080008080000080), + CONST64(0x8080800080000000), CONST64(0x8080808080000000), CONST64(0x8080800080000080), CONST64(0x8080808080000080), + CONST64(0x8080000080008000), CONST64(0x8080008080008000), CONST64(0x8080000080008080), CONST64(0x8080008080008080), + CONST64(0x8080800080008000), CONST64(0x8080808080008000), CONST64(0x8080800080008080), CONST64(0x8080808080008080), + CONST64(0x8000000080800000), CONST64(0x8000008080800000), CONST64(0x8000000080800080), CONST64(0x8000008080800080), + CONST64(0x8000800080800000), CONST64(0x8000808080800000), CONST64(0x8000800080800080), CONST64(0x8000808080800080), + CONST64(0x8000000080808000), CONST64(0x8000008080808000), CONST64(0x8000000080808080), CONST64(0x8000008080808080), + CONST64(0x8000800080808000), CONST64(0x8000808080808000), CONST64(0x8000800080808080), CONST64(0x8000808080808080), + CONST64(0x8080000080800000), CONST64(0x8080008080800000), CONST64(0x8080000080800080), CONST64(0x8080008080800080), + CONST64(0x8080800080800000), CONST64(0x8080808080800000), CONST64(0x8080800080800080), CONST64(0x8080808080800080), + CONST64(0x8080000080808000), CONST64(0x8080008080808000), CONST64(0x8080000080808080), CONST64(0x8080008080808080), + CONST64(0x8080800080808000), CONST64(0x8080808080808000), CONST64(0x8080800080808080), CONST64(0x8080808080808080) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000000000040), CONST64(0x0000004000000040), + CONST64(0x0000400000000000), CONST64(0x0000404000000000), CONST64(0x0000400000000040), CONST64(0x0000404000000040), + CONST64(0x0000000000004000), CONST64(0x0000004000004000), CONST64(0x0000000000004040), CONST64(0x0000004000004040), + CONST64(0x0000400000004000), CONST64(0x0000404000004000), CONST64(0x0000400000004040), CONST64(0x0000404000004040), + CONST64(0x0040000000000000), CONST64(0x0040004000000000), CONST64(0x0040000000000040), CONST64(0x0040004000000040), + CONST64(0x0040400000000000), CONST64(0x0040404000000000), CONST64(0x0040400000000040), CONST64(0x0040404000000040), + CONST64(0x0040000000004000), CONST64(0x0040004000004000), CONST64(0x0040000000004040), CONST64(0x0040004000004040), + CONST64(0x0040400000004000), CONST64(0x0040404000004000), CONST64(0x0040400000004040), CONST64(0x0040404000004040), + CONST64(0x0000000000400000), CONST64(0x0000004000400000), CONST64(0x0000000000400040), CONST64(0x0000004000400040), + CONST64(0x0000400000400000), CONST64(0x0000404000400000), CONST64(0x0000400000400040), CONST64(0x0000404000400040), + CONST64(0x0000000000404000), CONST64(0x0000004000404000), CONST64(0x0000000000404040), CONST64(0x0000004000404040), + CONST64(0x0000400000404000), CONST64(0x0000404000404000), CONST64(0x0000400000404040), CONST64(0x0000404000404040), + CONST64(0x0040000000400000), CONST64(0x0040004000400000), CONST64(0x0040000000400040), CONST64(0x0040004000400040), + CONST64(0x0040400000400000), CONST64(0x0040404000400000), CONST64(0x0040400000400040), CONST64(0x0040404000400040), + CONST64(0x0040000000404000), CONST64(0x0040004000404000), CONST64(0x0040000000404040), CONST64(0x0040004000404040), + CONST64(0x0040400000404000), CONST64(0x0040404000404000), CONST64(0x0040400000404040), CONST64(0x0040404000404040), + CONST64(0x4000000000000000), CONST64(0x4000004000000000), CONST64(0x4000000000000040), CONST64(0x4000004000000040), + CONST64(0x4000400000000000), CONST64(0x4000404000000000), CONST64(0x4000400000000040), CONST64(0x4000404000000040), + CONST64(0x4000000000004000), CONST64(0x4000004000004000), CONST64(0x4000000000004040), CONST64(0x4000004000004040), + CONST64(0x4000400000004000), CONST64(0x4000404000004000), CONST64(0x4000400000004040), CONST64(0x4000404000004040), + CONST64(0x4040000000000000), CONST64(0x4040004000000000), CONST64(0x4040000000000040), CONST64(0x4040004000000040), + CONST64(0x4040400000000000), CONST64(0x4040404000000000), CONST64(0x4040400000000040), CONST64(0x4040404000000040), + CONST64(0x4040000000004000), CONST64(0x4040004000004000), CONST64(0x4040000000004040), CONST64(0x4040004000004040), + CONST64(0x4040400000004000), CONST64(0x4040404000004000), CONST64(0x4040400000004040), CONST64(0x4040404000004040), + CONST64(0x4000000000400000), CONST64(0x4000004000400000), CONST64(0x4000000000400040), CONST64(0x4000004000400040), + CONST64(0x4000400000400000), CONST64(0x4000404000400000), CONST64(0x4000400000400040), CONST64(0x4000404000400040), + CONST64(0x4000000000404000), CONST64(0x4000004000404000), CONST64(0x4000000000404040), CONST64(0x4000004000404040), + CONST64(0x4000400000404000), CONST64(0x4000404000404000), CONST64(0x4000400000404040), CONST64(0x4000404000404040), + CONST64(0x4040000000400000), CONST64(0x4040004000400000), CONST64(0x4040000000400040), CONST64(0x4040004000400040), + CONST64(0x4040400000400000), CONST64(0x4040404000400000), CONST64(0x4040400000400040), CONST64(0x4040404000400040), + CONST64(0x4040000000404000), CONST64(0x4040004000404000), CONST64(0x4040000000404040), CONST64(0x4040004000404040), + CONST64(0x4040400000404000), CONST64(0x4040404000404000), CONST64(0x4040400000404040), CONST64(0x4040404000404040), + CONST64(0x0000000040000000), CONST64(0x0000004040000000), CONST64(0x0000000040000040), CONST64(0x0000004040000040), + CONST64(0x0000400040000000), CONST64(0x0000404040000000), CONST64(0x0000400040000040), CONST64(0x0000404040000040), + CONST64(0x0000000040004000), CONST64(0x0000004040004000), CONST64(0x0000000040004040), CONST64(0x0000004040004040), + CONST64(0x0000400040004000), CONST64(0x0000404040004000), CONST64(0x0000400040004040), CONST64(0x0000404040004040), + CONST64(0x0040000040000000), CONST64(0x0040004040000000), CONST64(0x0040000040000040), CONST64(0x0040004040000040), + CONST64(0x0040400040000000), CONST64(0x0040404040000000), CONST64(0x0040400040000040), CONST64(0x0040404040000040), + CONST64(0x0040000040004000), CONST64(0x0040004040004000), CONST64(0x0040000040004040), CONST64(0x0040004040004040), + CONST64(0x0040400040004000), CONST64(0x0040404040004000), CONST64(0x0040400040004040), CONST64(0x0040404040004040), + CONST64(0x0000000040400000), CONST64(0x0000004040400000), CONST64(0x0000000040400040), CONST64(0x0000004040400040), + CONST64(0x0000400040400000), CONST64(0x0000404040400000), CONST64(0x0000400040400040), CONST64(0x0000404040400040), + CONST64(0x0000000040404000), CONST64(0x0000004040404000), CONST64(0x0000000040404040), CONST64(0x0000004040404040), + CONST64(0x0000400040404000), CONST64(0x0000404040404000), CONST64(0x0000400040404040), CONST64(0x0000404040404040), + CONST64(0x0040000040400000), CONST64(0x0040004040400000), CONST64(0x0040000040400040), CONST64(0x0040004040400040), + CONST64(0x0040400040400000), CONST64(0x0040404040400000), CONST64(0x0040400040400040), CONST64(0x0040404040400040), + CONST64(0x0040000040404000), CONST64(0x0040004040404000), CONST64(0x0040000040404040), CONST64(0x0040004040404040), + CONST64(0x0040400040404000), CONST64(0x0040404040404000), CONST64(0x0040400040404040), CONST64(0x0040404040404040), + CONST64(0x4000000040000000), CONST64(0x4000004040000000), CONST64(0x4000000040000040), CONST64(0x4000004040000040), + CONST64(0x4000400040000000), CONST64(0x4000404040000000), CONST64(0x4000400040000040), CONST64(0x4000404040000040), + CONST64(0x4000000040004000), CONST64(0x4000004040004000), CONST64(0x4000000040004040), CONST64(0x4000004040004040), + CONST64(0x4000400040004000), CONST64(0x4000404040004000), CONST64(0x4000400040004040), CONST64(0x4000404040004040), + CONST64(0x4040000040000000), CONST64(0x4040004040000000), CONST64(0x4040000040000040), CONST64(0x4040004040000040), + CONST64(0x4040400040000000), CONST64(0x4040404040000000), CONST64(0x4040400040000040), CONST64(0x4040404040000040), + CONST64(0x4040000040004000), CONST64(0x4040004040004000), CONST64(0x4040000040004040), CONST64(0x4040004040004040), + CONST64(0x4040400040004000), CONST64(0x4040404040004000), CONST64(0x4040400040004040), CONST64(0x4040404040004040), + CONST64(0x4000000040400000), CONST64(0x4000004040400000), CONST64(0x4000000040400040), CONST64(0x4000004040400040), + CONST64(0x4000400040400000), CONST64(0x4000404040400000), CONST64(0x4000400040400040), CONST64(0x4000404040400040), + CONST64(0x4000000040404000), CONST64(0x4000004040404000), CONST64(0x4000000040404040), CONST64(0x4000004040404040), + CONST64(0x4000400040404000), CONST64(0x4000404040404000), CONST64(0x4000400040404040), CONST64(0x4000404040404040), + CONST64(0x4040000040400000), CONST64(0x4040004040400000), CONST64(0x4040000040400040), CONST64(0x4040004040400040), + CONST64(0x4040400040400000), CONST64(0x4040404040400000), CONST64(0x4040400040400040), CONST64(0x4040404040400040), + CONST64(0x4040000040404000), CONST64(0x4040004040404000), CONST64(0x4040000040404040), CONST64(0x4040004040404040), + CONST64(0x4040400040404000), CONST64(0x4040404040404000), CONST64(0x4040400040404040), CONST64(0x4040404040404040) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000000000020), CONST64(0x0000002000000020), + CONST64(0x0000200000000000), CONST64(0x0000202000000000), CONST64(0x0000200000000020), CONST64(0x0000202000000020), + CONST64(0x0000000000002000), CONST64(0x0000002000002000), CONST64(0x0000000000002020), CONST64(0x0000002000002020), + CONST64(0x0000200000002000), CONST64(0x0000202000002000), CONST64(0x0000200000002020), CONST64(0x0000202000002020), + CONST64(0x0020000000000000), CONST64(0x0020002000000000), CONST64(0x0020000000000020), CONST64(0x0020002000000020), + CONST64(0x0020200000000000), CONST64(0x0020202000000000), CONST64(0x0020200000000020), CONST64(0x0020202000000020), + CONST64(0x0020000000002000), CONST64(0x0020002000002000), CONST64(0x0020000000002020), CONST64(0x0020002000002020), + CONST64(0x0020200000002000), CONST64(0x0020202000002000), CONST64(0x0020200000002020), CONST64(0x0020202000002020), + CONST64(0x0000000000200000), CONST64(0x0000002000200000), CONST64(0x0000000000200020), CONST64(0x0000002000200020), + CONST64(0x0000200000200000), CONST64(0x0000202000200000), CONST64(0x0000200000200020), CONST64(0x0000202000200020), + CONST64(0x0000000000202000), CONST64(0x0000002000202000), CONST64(0x0000000000202020), CONST64(0x0000002000202020), + CONST64(0x0000200000202000), CONST64(0x0000202000202000), CONST64(0x0000200000202020), CONST64(0x0000202000202020), + CONST64(0x0020000000200000), CONST64(0x0020002000200000), CONST64(0x0020000000200020), CONST64(0x0020002000200020), + CONST64(0x0020200000200000), CONST64(0x0020202000200000), CONST64(0x0020200000200020), CONST64(0x0020202000200020), + CONST64(0x0020000000202000), CONST64(0x0020002000202000), CONST64(0x0020000000202020), CONST64(0x0020002000202020), + CONST64(0x0020200000202000), CONST64(0x0020202000202000), CONST64(0x0020200000202020), CONST64(0x0020202000202020), + CONST64(0x2000000000000000), CONST64(0x2000002000000000), CONST64(0x2000000000000020), CONST64(0x2000002000000020), + CONST64(0x2000200000000000), CONST64(0x2000202000000000), CONST64(0x2000200000000020), CONST64(0x2000202000000020), + CONST64(0x2000000000002000), CONST64(0x2000002000002000), CONST64(0x2000000000002020), CONST64(0x2000002000002020), + CONST64(0x2000200000002000), CONST64(0x2000202000002000), CONST64(0x2000200000002020), CONST64(0x2000202000002020), + CONST64(0x2020000000000000), CONST64(0x2020002000000000), CONST64(0x2020000000000020), CONST64(0x2020002000000020), + CONST64(0x2020200000000000), CONST64(0x2020202000000000), CONST64(0x2020200000000020), CONST64(0x2020202000000020), + CONST64(0x2020000000002000), CONST64(0x2020002000002000), CONST64(0x2020000000002020), CONST64(0x2020002000002020), + CONST64(0x2020200000002000), CONST64(0x2020202000002000), CONST64(0x2020200000002020), CONST64(0x2020202000002020), + CONST64(0x2000000000200000), CONST64(0x2000002000200000), CONST64(0x2000000000200020), CONST64(0x2000002000200020), + CONST64(0x2000200000200000), CONST64(0x2000202000200000), CONST64(0x2000200000200020), CONST64(0x2000202000200020), + CONST64(0x2000000000202000), CONST64(0x2000002000202000), CONST64(0x2000000000202020), CONST64(0x2000002000202020), + CONST64(0x2000200000202000), CONST64(0x2000202000202000), CONST64(0x2000200000202020), CONST64(0x2000202000202020), + CONST64(0x2020000000200000), CONST64(0x2020002000200000), CONST64(0x2020000000200020), CONST64(0x2020002000200020), + CONST64(0x2020200000200000), CONST64(0x2020202000200000), CONST64(0x2020200000200020), CONST64(0x2020202000200020), + CONST64(0x2020000000202000), CONST64(0x2020002000202000), CONST64(0x2020000000202020), CONST64(0x2020002000202020), + CONST64(0x2020200000202000), CONST64(0x2020202000202000), CONST64(0x2020200000202020), CONST64(0x2020202000202020), + CONST64(0x0000000020000000), CONST64(0x0000002020000000), CONST64(0x0000000020000020), CONST64(0x0000002020000020), + CONST64(0x0000200020000000), CONST64(0x0000202020000000), CONST64(0x0000200020000020), CONST64(0x0000202020000020), + CONST64(0x0000000020002000), CONST64(0x0000002020002000), CONST64(0x0000000020002020), CONST64(0x0000002020002020), + CONST64(0x0000200020002000), CONST64(0x0000202020002000), CONST64(0x0000200020002020), CONST64(0x0000202020002020), + CONST64(0x0020000020000000), CONST64(0x0020002020000000), CONST64(0x0020000020000020), CONST64(0x0020002020000020), + CONST64(0x0020200020000000), CONST64(0x0020202020000000), CONST64(0x0020200020000020), CONST64(0x0020202020000020), + CONST64(0x0020000020002000), CONST64(0x0020002020002000), CONST64(0x0020000020002020), CONST64(0x0020002020002020), + CONST64(0x0020200020002000), CONST64(0x0020202020002000), CONST64(0x0020200020002020), CONST64(0x0020202020002020), + CONST64(0x0000000020200000), CONST64(0x0000002020200000), CONST64(0x0000000020200020), CONST64(0x0000002020200020), + CONST64(0x0000200020200000), CONST64(0x0000202020200000), CONST64(0x0000200020200020), CONST64(0x0000202020200020), + CONST64(0x0000000020202000), CONST64(0x0000002020202000), CONST64(0x0000000020202020), CONST64(0x0000002020202020), + CONST64(0x0000200020202000), CONST64(0x0000202020202000), CONST64(0x0000200020202020), CONST64(0x0000202020202020), + CONST64(0x0020000020200000), CONST64(0x0020002020200000), CONST64(0x0020000020200020), CONST64(0x0020002020200020), + CONST64(0x0020200020200000), CONST64(0x0020202020200000), CONST64(0x0020200020200020), CONST64(0x0020202020200020), + CONST64(0x0020000020202000), CONST64(0x0020002020202000), CONST64(0x0020000020202020), CONST64(0x0020002020202020), + CONST64(0x0020200020202000), CONST64(0x0020202020202000), CONST64(0x0020200020202020), CONST64(0x0020202020202020), + CONST64(0x2000000020000000), CONST64(0x2000002020000000), CONST64(0x2000000020000020), CONST64(0x2000002020000020), + CONST64(0x2000200020000000), CONST64(0x2000202020000000), CONST64(0x2000200020000020), CONST64(0x2000202020000020), + CONST64(0x2000000020002000), CONST64(0x2000002020002000), CONST64(0x2000000020002020), CONST64(0x2000002020002020), + CONST64(0x2000200020002000), CONST64(0x2000202020002000), CONST64(0x2000200020002020), CONST64(0x2000202020002020), + CONST64(0x2020000020000000), CONST64(0x2020002020000000), CONST64(0x2020000020000020), CONST64(0x2020002020000020), + CONST64(0x2020200020000000), CONST64(0x2020202020000000), CONST64(0x2020200020000020), CONST64(0x2020202020000020), + CONST64(0x2020000020002000), CONST64(0x2020002020002000), CONST64(0x2020000020002020), CONST64(0x2020002020002020), + CONST64(0x2020200020002000), CONST64(0x2020202020002000), CONST64(0x2020200020002020), CONST64(0x2020202020002020), + CONST64(0x2000000020200000), CONST64(0x2000002020200000), CONST64(0x2000000020200020), CONST64(0x2000002020200020), + CONST64(0x2000200020200000), CONST64(0x2000202020200000), CONST64(0x2000200020200020), CONST64(0x2000202020200020), + CONST64(0x2000000020202000), CONST64(0x2000002020202000), CONST64(0x2000000020202020), CONST64(0x2000002020202020), + CONST64(0x2000200020202000), CONST64(0x2000202020202000), CONST64(0x2000200020202020), CONST64(0x2000202020202020), + CONST64(0x2020000020200000), CONST64(0x2020002020200000), CONST64(0x2020000020200020), CONST64(0x2020002020200020), + CONST64(0x2020200020200000), CONST64(0x2020202020200000), CONST64(0x2020200020200020), CONST64(0x2020202020200020), + CONST64(0x2020000020202000), CONST64(0x2020002020202000), CONST64(0x2020000020202020), CONST64(0x2020002020202020), + CONST64(0x2020200020202000), CONST64(0x2020202020202000), CONST64(0x2020200020202020), CONST64(0x2020202020202020) + }}; + +static const ulong64 des_fp[8][256] = { + +{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000002000000), CONST64(0x0000008002000000), + CONST64(0x0000000000020000), CONST64(0x0000008000020000), CONST64(0x0000000002020000), CONST64(0x0000008002020000), + CONST64(0x0000000000000200), CONST64(0x0000008000000200), CONST64(0x0000000002000200), CONST64(0x0000008002000200), + CONST64(0x0000000000020200), CONST64(0x0000008000020200), CONST64(0x0000000002020200), CONST64(0x0000008002020200), + CONST64(0x0000000000000002), CONST64(0x0000008000000002), CONST64(0x0000000002000002), CONST64(0x0000008002000002), + CONST64(0x0000000000020002), CONST64(0x0000008000020002), CONST64(0x0000000002020002), CONST64(0x0000008002020002), + CONST64(0x0000000000000202), CONST64(0x0000008000000202), CONST64(0x0000000002000202), CONST64(0x0000008002000202), + CONST64(0x0000000000020202), CONST64(0x0000008000020202), CONST64(0x0000000002020202), CONST64(0x0000008002020202), + CONST64(0x0200000000000000), CONST64(0x0200008000000000), CONST64(0x0200000002000000), CONST64(0x0200008002000000), + CONST64(0x0200000000020000), CONST64(0x0200008000020000), CONST64(0x0200000002020000), CONST64(0x0200008002020000), + CONST64(0x0200000000000200), CONST64(0x0200008000000200), CONST64(0x0200000002000200), CONST64(0x0200008002000200), + CONST64(0x0200000000020200), CONST64(0x0200008000020200), CONST64(0x0200000002020200), CONST64(0x0200008002020200), + CONST64(0x0200000000000002), CONST64(0x0200008000000002), CONST64(0x0200000002000002), CONST64(0x0200008002000002), + CONST64(0x0200000000020002), CONST64(0x0200008000020002), CONST64(0x0200000002020002), CONST64(0x0200008002020002), + CONST64(0x0200000000000202), CONST64(0x0200008000000202), CONST64(0x0200000002000202), CONST64(0x0200008002000202), + CONST64(0x0200000000020202), CONST64(0x0200008000020202), CONST64(0x0200000002020202), CONST64(0x0200008002020202), + CONST64(0x0002000000000000), CONST64(0x0002008000000000), CONST64(0x0002000002000000), CONST64(0x0002008002000000), + CONST64(0x0002000000020000), CONST64(0x0002008000020000), CONST64(0x0002000002020000), CONST64(0x0002008002020000), + CONST64(0x0002000000000200), CONST64(0x0002008000000200), CONST64(0x0002000002000200), CONST64(0x0002008002000200), + CONST64(0x0002000000020200), CONST64(0x0002008000020200), CONST64(0x0002000002020200), CONST64(0x0002008002020200), + CONST64(0x0002000000000002), CONST64(0x0002008000000002), CONST64(0x0002000002000002), CONST64(0x0002008002000002), + CONST64(0x0002000000020002), CONST64(0x0002008000020002), CONST64(0x0002000002020002), CONST64(0x0002008002020002), + CONST64(0x0002000000000202), CONST64(0x0002008000000202), CONST64(0x0002000002000202), CONST64(0x0002008002000202), + CONST64(0x0002000000020202), CONST64(0x0002008000020202), CONST64(0x0002000002020202), CONST64(0x0002008002020202), + CONST64(0x0202000000000000), CONST64(0x0202008000000000), CONST64(0x0202000002000000), CONST64(0x0202008002000000), + CONST64(0x0202000000020000), CONST64(0x0202008000020000), CONST64(0x0202000002020000), CONST64(0x0202008002020000), + CONST64(0x0202000000000200), CONST64(0x0202008000000200), CONST64(0x0202000002000200), CONST64(0x0202008002000200), + CONST64(0x0202000000020200), CONST64(0x0202008000020200), CONST64(0x0202000002020200), CONST64(0x0202008002020200), + CONST64(0x0202000000000002), CONST64(0x0202008000000002), CONST64(0x0202000002000002), CONST64(0x0202008002000002), + CONST64(0x0202000000020002), CONST64(0x0202008000020002), CONST64(0x0202000002020002), CONST64(0x0202008002020002), + CONST64(0x0202000000000202), CONST64(0x0202008000000202), CONST64(0x0202000002000202), CONST64(0x0202008002000202), + CONST64(0x0202000000020202), CONST64(0x0202008000020202), CONST64(0x0202000002020202), CONST64(0x0202008002020202), + CONST64(0x0000020000000000), CONST64(0x0000028000000000), CONST64(0x0000020002000000), CONST64(0x0000028002000000), + CONST64(0x0000020000020000), CONST64(0x0000028000020000), CONST64(0x0000020002020000), CONST64(0x0000028002020000), + CONST64(0x0000020000000200), CONST64(0x0000028000000200), CONST64(0x0000020002000200), CONST64(0x0000028002000200), + CONST64(0x0000020000020200), CONST64(0x0000028000020200), CONST64(0x0000020002020200), CONST64(0x0000028002020200), + CONST64(0x0000020000000002), CONST64(0x0000028000000002), CONST64(0x0000020002000002), CONST64(0x0000028002000002), + CONST64(0x0000020000020002), CONST64(0x0000028000020002), CONST64(0x0000020002020002), CONST64(0x0000028002020002), + CONST64(0x0000020000000202), CONST64(0x0000028000000202), CONST64(0x0000020002000202), CONST64(0x0000028002000202), + CONST64(0x0000020000020202), CONST64(0x0000028000020202), CONST64(0x0000020002020202), CONST64(0x0000028002020202), + CONST64(0x0200020000000000), CONST64(0x0200028000000000), CONST64(0x0200020002000000), CONST64(0x0200028002000000), + CONST64(0x0200020000020000), CONST64(0x0200028000020000), CONST64(0x0200020002020000), CONST64(0x0200028002020000), + CONST64(0x0200020000000200), CONST64(0x0200028000000200), CONST64(0x0200020002000200), CONST64(0x0200028002000200), + CONST64(0x0200020000020200), CONST64(0x0200028000020200), CONST64(0x0200020002020200), CONST64(0x0200028002020200), + CONST64(0x0200020000000002), CONST64(0x0200028000000002), CONST64(0x0200020002000002), CONST64(0x0200028002000002), + CONST64(0x0200020000020002), CONST64(0x0200028000020002), CONST64(0x0200020002020002), CONST64(0x0200028002020002), + CONST64(0x0200020000000202), CONST64(0x0200028000000202), CONST64(0x0200020002000202), CONST64(0x0200028002000202), + CONST64(0x0200020000020202), CONST64(0x0200028000020202), CONST64(0x0200020002020202), CONST64(0x0200028002020202), + CONST64(0x0002020000000000), CONST64(0x0002028000000000), CONST64(0x0002020002000000), CONST64(0x0002028002000000), + CONST64(0x0002020000020000), CONST64(0x0002028000020000), CONST64(0x0002020002020000), CONST64(0x0002028002020000), + CONST64(0x0002020000000200), CONST64(0x0002028000000200), CONST64(0x0002020002000200), CONST64(0x0002028002000200), + CONST64(0x0002020000020200), CONST64(0x0002028000020200), CONST64(0x0002020002020200), CONST64(0x0002028002020200), + CONST64(0x0002020000000002), CONST64(0x0002028000000002), CONST64(0x0002020002000002), CONST64(0x0002028002000002), + CONST64(0x0002020000020002), CONST64(0x0002028000020002), CONST64(0x0002020002020002), CONST64(0x0002028002020002), + CONST64(0x0002020000000202), CONST64(0x0002028000000202), CONST64(0x0002020002000202), CONST64(0x0002028002000202), + CONST64(0x0002020000020202), CONST64(0x0002028000020202), CONST64(0x0002020002020202), CONST64(0x0002028002020202), + CONST64(0x0202020000000000), CONST64(0x0202028000000000), CONST64(0x0202020002000000), CONST64(0x0202028002000000), + CONST64(0x0202020000020000), CONST64(0x0202028000020000), CONST64(0x0202020002020000), CONST64(0x0202028002020000), + CONST64(0x0202020000000200), CONST64(0x0202028000000200), CONST64(0x0202020002000200), CONST64(0x0202028002000200), + CONST64(0x0202020000020200), CONST64(0x0202028000020200), CONST64(0x0202020002020200), CONST64(0x0202028002020200), + CONST64(0x0202020000000002), CONST64(0x0202028000000002), CONST64(0x0202020002000002), CONST64(0x0202028002000002), + CONST64(0x0202020000020002), CONST64(0x0202028000020002), CONST64(0x0202020002020002), CONST64(0x0202028002020002), + CONST64(0x0202020000000202), CONST64(0x0202028000000202), CONST64(0x0202020002000202), CONST64(0x0202028002000202), + CONST64(0x0202020000020202), CONST64(0x0202028000020202), CONST64(0x0202020002020202), CONST64(0x0202028002020202) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000008000000), CONST64(0x0000000208000000), + CONST64(0x0000000000080000), CONST64(0x0000000200080000), CONST64(0x0000000008080000), CONST64(0x0000000208080000), + CONST64(0x0000000000000800), CONST64(0x0000000200000800), CONST64(0x0000000008000800), CONST64(0x0000000208000800), + CONST64(0x0000000000080800), CONST64(0x0000000200080800), CONST64(0x0000000008080800), CONST64(0x0000000208080800), + CONST64(0x0000000000000008), CONST64(0x0000000200000008), CONST64(0x0000000008000008), CONST64(0x0000000208000008), + CONST64(0x0000000000080008), CONST64(0x0000000200080008), CONST64(0x0000000008080008), CONST64(0x0000000208080008), + CONST64(0x0000000000000808), CONST64(0x0000000200000808), CONST64(0x0000000008000808), CONST64(0x0000000208000808), + CONST64(0x0000000000080808), CONST64(0x0000000200080808), CONST64(0x0000000008080808), CONST64(0x0000000208080808), + CONST64(0x0800000000000000), CONST64(0x0800000200000000), CONST64(0x0800000008000000), CONST64(0x0800000208000000), + CONST64(0x0800000000080000), CONST64(0x0800000200080000), CONST64(0x0800000008080000), CONST64(0x0800000208080000), + CONST64(0x0800000000000800), CONST64(0x0800000200000800), CONST64(0x0800000008000800), CONST64(0x0800000208000800), + CONST64(0x0800000000080800), CONST64(0x0800000200080800), CONST64(0x0800000008080800), CONST64(0x0800000208080800), + CONST64(0x0800000000000008), CONST64(0x0800000200000008), CONST64(0x0800000008000008), CONST64(0x0800000208000008), + CONST64(0x0800000000080008), CONST64(0x0800000200080008), CONST64(0x0800000008080008), CONST64(0x0800000208080008), + CONST64(0x0800000000000808), CONST64(0x0800000200000808), CONST64(0x0800000008000808), CONST64(0x0800000208000808), + CONST64(0x0800000000080808), CONST64(0x0800000200080808), CONST64(0x0800000008080808), CONST64(0x0800000208080808), + CONST64(0x0008000000000000), CONST64(0x0008000200000000), CONST64(0x0008000008000000), CONST64(0x0008000208000000), + CONST64(0x0008000000080000), CONST64(0x0008000200080000), CONST64(0x0008000008080000), CONST64(0x0008000208080000), + CONST64(0x0008000000000800), CONST64(0x0008000200000800), CONST64(0x0008000008000800), CONST64(0x0008000208000800), + CONST64(0x0008000000080800), CONST64(0x0008000200080800), CONST64(0x0008000008080800), CONST64(0x0008000208080800), + CONST64(0x0008000000000008), CONST64(0x0008000200000008), CONST64(0x0008000008000008), CONST64(0x0008000208000008), + CONST64(0x0008000000080008), CONST64(0x0008000200080008), CONST64(0x0008000008080008), CONST64(0x0008000208080008), + CONST64(0x0008000000000808), CONST64(0x0008000200000808), CONST64(0x0008000008000808), CONST64(0x0008000208000808), + CONST64(0x0008000000080808), CONST64(0x0008000200080808), CONST64(0x0008000008080808), CONST64(0x0008000208080808), + CONST64(0x0808000000000000), CONST64(0x0808000200000000), CONST64(0x0808000008000000), CONST64(0x0808000208000000), + CONST64(0x0808000000080000), CONST64(0x0808000200080000), CONST64(0x0808000008080000), CONST64(0x0808000208080000), + CONST64(0x0808000000000800), CONST64(0x0808000200000800), CONST64(0x0808000008000800), CONST64(0x0808000208000800), + CONST64(0x0808000000080800), CONST64(0x0808000200080800), CONST64(0x0808000008080800), CONST64(0x0808000208080800), + CONST64(0x0808000000000008), CONST64(0x0808000200000008), CONST64(0x0808000008000008), CONST64(0x0808000208000008), + CONST64(0x0808000000080008), CONST64(0x0808000200080008), CONST64(0x0808000008080008), CONST64(0x0808000208080008), + CONST64(0x0808000000000808), CONST64(0x0808000200000808), CONST64(0x0808000008000808), CONST64(0x0808000208000808), + CONST64(0x0808000000080808), CONST64(0x0808000200080808), CONST64(0x0808000008080808), CONST64(0x0808000208080808), + CONST64(0x0000080000000000), CONST64(0x0000080200000000), CONST64(0x0000080008000000), CONST64(0x0000080208000000), + CONST64(0x0000080000080000), CONST64(0x0000080200080000), CONST64(0x0000080008080000), CONST64(0x0000080208080000), + CONST64(0x0000080000000800), CONST64(0x0000080200000800), CONST64(0x0000080008000800), CONST64(0x0000080208000800), + CONST64(0x0000080000080800), CONST64(0x0000080200080800), CONST64(0x0000080008080800), CONST64(0x0000080208080800), + CONST64(0x0000080000000008), CONST64(0x0000080200000008), CONST64(0x0000080008000008), CONST64(0x0000080208000008), + CONST64(0x0000080000080008), CONST64(0x0000080200080008), CONST64(0x0000080008080008), CONST64(0x0000080208080008), + CONST64(0x0000080000000808), CONST64(0x0000080200000808), CONST64(0x0000080008000808), CONST64(0x0000080208000808), + CONST64(0x0000080000080808), CONST64(0x0000080200080808), CONST64(0x0000080008080808), CONST64(0x0000080208080808), + CONST64(0x0800080000000000), CONST64(0x0800080200000000), CONST64(0x0800080008000000), CONST64(0x0800080208000000), + CONST64(0x0800080000080000), CONST64(0x0800080200080000), CONST64(0x0800080008080000), CONST64(0x0800080208080000), + CONST64(0x0800080000000800), CONST64(0x0800080200000800), CONST64(0x0800080008000800), CONST64(0x0800080208000800), + CONST64(0x0800080000080800), CONST64(0x0800080200080800), CONST64(0x0800080008080800), CONST64(0x0800080208080800), + CONST64(0x0800080000000008), CONST64(0x0800080200000008), CONST64(0x0800080008000008), CONST64(0x0800080208000008), + CONST64(0x0800080000080008), CONST64(0x0800080200080008), CONST64(0x0800080008080008), CONST64(0x0800080208080008), + CONST64(0x0800080000000808), CONST64(0x0800080200000808), CONST64(0x0800080008000808), CONST64(0x0800080208000808), + CONST64(0x0800080000080808), CONST64(0x0800080200080808), CONST64(0x0800080008080808), CONST64(0x0800080208080808), + CONST64(0x0008080000000000), CONST64(0x0008080200000000), CONST64(0x0008080008000000), CONST64(0x0008080208000000), + CONST64(0x0008080000080000), CONST64(0x0008080200080000), CONST64(0x0008080008080000), CONST64(0x0008080208080000), + CONST64(0x0008080000000800), CONST64(0x0008080200000800), CONST64(0x0008080008000800), CONST64(0x0008080208000800), + CONST64(0x0008080000080800), CONST64(0x0008080200080800), CONST64(0x0008080008080800), CONST64(0x0008080208080800), + CONST64(0x0008080000000008), CONST64(0x0008080200000008), CONST64(0x0008080008000008), CONST64(0x0008080208000008), + CONST64(0x0008080000080008), CONST64(0x0008080200080008), CONST64(0x0008080008080008), CONST64(0x0008080208080008), + CONST64(0x0008080000000808), CONST64(0x0008080200000808), CONST64(0x0008080008000808), CONST64(0x0008080208000808), + CONST64(0x0008080000080808), CONST64(0x0008080200080808), CONST64(0x0008080008080808), CONST64(0x0008080208080808), + CONST64(0x0808080000000000), CONST64(0x0808080200000000), CONST64(0x0808080008000000), CONST64(0x0808080208000000), + CONST64(0x0808080000080000), CONST64(0x0808080200080000), CONST64(0x0808080008080000), CONST64(0x0808080208080000), + CONST64(0x0808080000000800), CONST64(0x0808080200000800), CONST64(0x0808080008000800), CONST64(0x0808080208000800), + CONST64(0x0808080000080800), CONST64(0x0808080200080800), CONST64(0x0808080008080800), CONST64(0x0808080208080800), + CONST64(0x0808080000000008), CONST64(0x0808080200000008), CONST64(0x0808080008000008), CONST64(0x0808080208000008), + CONST64(0x0808080000080008), CONST64(0x0808080200080008), CONST64(0x0808080008080008), CONST64(0x0808080208080008), + CONST64(0x0808080000000808), CONST64(0x0808080200000808), CONST64(0x0808080008000808), CONST64(0x0808080208000808), + CONST64(0x0808080000080808), CONST64(0x0808080200080808), CONST64(0x0808080008080808), CONST64(0x0808080208080808) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000020000000), CONST64(0x0000000820000000), + CONST64(0x0000000000200000), CONST64(0x0000000800200000), CONST64(0x0000000020200000), CONST64(0x0000000820200000), + CONST64(0x0000000000002000), CONST64(0x0000000800002000), CONST64(0x0000000020002000), CONST64(0x0000000820002000), + CONST64(0x0000000000202000), CONST64(0x0000000800202000), CONST64(0x0000000020202000), CONST64(0x0000000820202000), + CONST64(0x0000000000000020), CONST64(0x0000000800000020), CONST64(0x0000000020000020), CONST64(0x0000000820000020), + CONST64(0x0000000000200020), CONST64(0x0000000800200020), CONST64(0x0000000020200020), CONST64(0x0000000820200020), + CONST64(0x0000000000002020), CONST64(0x0000000800002020), CONST64(0x0000000020002020), CONST64(0x0000000820002020), + CONST64(0x0000000000202020), CONST64(0x0000000800202020), CONST64(0x0000000020202020), CONST64(0x0000000820202020), + CONST64(0x2000000000000000), CONST64(0x2000000800000000), CONST64(0x2000000020000000), CONST64(0x2000000820000000), + CONST64(0x2000000000200000), CONST64(0x2000000800200000), CONST64(0x2000000020200000), CONST64(0x2000000820200000), + CONST64(0x2000000000002000), CONST64(0x2000000800002000), CONST64(0x2000000020002000), CONST64(0x2000000820002000), + CONST64(0x2000000000202000), CONST64(0x2000000800202000), CONST64(0x2000000020202000), CONST64(0x2000000820202000), + CONST64(0x2000000000000020), CONST64(0x2000000800000020), CONST64(0x2000000020000020), CONST64(0x2000000820000020), + CONST64(0x2000000000200020), CONST64(0x2000000800200020), CONST64(0x2000000020200020), CONST64(0x2000000820200020), + CONST64(0x2000000000002020), CONST64(0x2000000800002020), CONST64(0x2000000020002020), CONST64(0x2000000820002020), + CONST64(0x2000000000202020), CONST64(0x2000000800202020), CONST64(0x2000000020202020), CONST64(0x2000000820202020), + CONST64(0x0020000000000000), CONST64(0x0020000800000000), CONST64(0x0020000020000000), CONST64(0x0020000820000000), + CONST64(0x0020000000200000), CONST64(0x0020000800200000), CONST64(0x0020000020200000), CONST64(0x0020000820200000), + CONST64(0x0020000000002000), CONST64(0x0020000800002000), CONST64(0x0020000020002000), CONST64(0x0020000820002000), + CONST64(0x0020000000202000), CONST64(0x0020000800202000), CONST64(0x0020000020202000), CONST64(0x0020000820202000), + CONST64(0x0020000000000020), CONST64(0x0020000800000020), CONST64(0x0020000020000020), CONST64(0x0020000820000020), + CONST64(0x0020000000200020), CONST64(0x0020000800200020), CONST64(0x0020000020200020), CONST64(0x0020000820200020), + CONST64(0x0020000000002020), CONST64(0x0020000800002020), CONST64(0x0020000020002020), CONST64(0x0020000820002020), + CONST64(0x0020000000202020), CONST64(0x0020000800202020), CONST64(0x0020000020202020), CONST64(0x0020000820202020), + CONST64(0x2020000000000000), CONST64(0x2020000800000000), CONST64(0x2020000020000000), CONST64(0x2020000820000000), + CONST64(0x2020000000200000), CONST64(0x2020000800200000), CONST64(0x2020000020200000), CONST64(0x2020000820200000), + CONST64(0x2020000000002000), CONST64(0x2020000800002000), CONST64(0x2020000020002000), CONST64(0x2020000820002000), + CONST64(0x2020000000202000), CONST64(0x2020000800202000), CONST64(0x2020000020202000), CONST64(0x2020000820202000), + CONST64(0x2020000000000020), CONST64(0x2020000800000020), CONST64(0x2020000020000020), CONST64(0x2020000820000020), + CONST64(0x2020000000200020), CONST64(0x2020000800200020), CONST64(0x2020000020200020), CONST64(0x2020000820200020), + CONST64(0x2020000000002020), CONST64(0x2020000800002020), CONST64(0x2020000020002020), CONST64(0x2020000820002020), + CONST64(0x2020000000202020), CONST64(0x2020000800202020), CONST64(0x2020000020202020), CONST64(0x2020000820202020), + CONST64(0x0000200000000000), CONST64(0x0000200800000000), CONST64(0x0000200020000000), CONST64(0x0000200820000000), + CONST64(0x0000200000200000), CONST64(0x0000200800200000), CONST64(0x0000200020200000), CONST64(0x0000200820200000), + CONST64(0x0000200000002000), CONST64(0x0000200800002000), CONST64(0x0000200020002000), CONST64(0x0000200820002000), + CONST64(0x0000200000202000), CONST64(0x0000200800202000), CONST64(0x0000200020202000), CONST64(0x0000200820202000), + CONST64(0x0000200000000020), CONST64(0x0000200800000020), CONST64(0x0000200020000020), CONST64(0x0000200820000020), + CONST64(0x0000200000200020), CONST64(0x0000200800200020), CONST64(0x0000200020200020), CONST64(0x0000200820200020), + CONST64(0x0000200000002020), CONST64(0x0000200800002020), CONST64(0x0000200020002020), CONST64(0x0000200820002020), + CONST64(0x0000200000202020), CONST64(0x0000200800202020), CONST64(0x0000200020202020), CONST64(0x0000200820202020), + CONST64(0x2000200000000000), CONST64(0x2000200800000000), CONST64(0x2000200020000000), CONST64(0x2000200820000000), + CONST64(0x2000200000200000), CONST64(0x2000200800200000), CONST64(0x2000200020200000), CONST64(0x2000200820200000), + CONST64(0x2000200000002000), CONST64(0x2000200800002000), CONST64(0x2000200020002000), CONST64(0x2000200820002000), + CONST64(0x2000200000202000), CONST64(0x2000200800202000), CONST64(0x2000200020202000), CONST64(0x2000200820202000), + CONST64(0x2000200000000020), CONST64(0x2000200800000020), CONST64(0x2000200020000020), CONST64(0x2000200820000020), + CONST64(0x2000200000200020), CONST64(0x2000200800200020), CONST64(0x2000200020200020), CONST64(0x2000200820200020), + CONST64(0x2000200000002020), CONST64(0x2000200800002020), CONST64(0x2000200020002020), CONST64(0x2000200820002020), + CONST64(0x2000200000202020), CONST64(0x2000200800202020), CONST64(0x2000200020202020), CONST64(0x2000200820202020), + CONST64(0x0020200000000000), CONST64(0x0020200800000000), CONST64(0x0020200020000000), CONST64(0x0020200820000000), + CONST64(0x0020200000200000), CONST64(0x0020200800200000), CONST64(0x0020200020200000), CONST64(0x0020200820200000), + CONST64(0x0020200000002000), CONST64(0x0020200800002000), CONST64(0x0020200020002000), CONST64(0x0020200820002000), + CONST64(0x0020200000202000), CONST64(0x0020200800202000), CONST64(0x0020200020202000), CONST64(0x0020200820202000), + CONST64(0x0020200000000020), CONST64(0x0020200800000020), CONST64(0x0020200020000020), CONST64(0x0020200820000020), + CONST64(0x0020200000200020), CONST64(0x0020200800200020), CONST64(0x0020200020200020), CONST64(0x0020200820200020), + CONST64(0x0020200000002020), CONST64(0x0020200800002020), CONST64(0x0020200020002020), CONST64(0x0020200820002020), + CONST64(0x0020200000202020), CONST64(0x0020200800202020), CONST64(0x0020200020202020), CONST64(0x0020200820202020), + CONST64(0x2020200000000000), CONST64(0x2020200800000000), CONST64(0x2020200020000000), CONST64(0x2020200820000000), + CONST64(0x2020200000200000), CONST64(0x2020200800200000), CONST64(0x2020200020200000), CONST64(0x2020200820200000), + CONST64(0x2020200000002000), CONST64(0x2020200800002000), CONST64(0x2020200020002000), CONST64(0x2020200820002000), + CONST64(0x2020200000202000), CONST64(0x2020200800202000), CONST64(0x2020200020202000), CONST64(0x2020200820202000), + CONST64(0x2020200000000020), CONST64(0x2020200800000020), CONST64(0x2020200020000020), CONST64(0x2020200820000020), + CONST64(0x2020200000200020), CONST64(0x2020200800200020), CONST64(0x2020200020200020), CONST64(0x2020200820200020), + CONST64(0x2020200000002020), CONST64(0x2020200800002020), CONST64(0x2020200020002020), CONST64(0x2020200820002020), + CONST64(0x2020200000202020), CONST64(0x2020200800202020), CONST64(0x2020200020202020), CONST64(0x2020200820202020) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000080000000), CONST64(0x0000002080000000), + CONST64(0x0000000000800000), CONST64(0x0000002000800000), CONST64(0x0000000080800000), CONST64(0x0000002080800000), + CONST64(0x0000000000008000), CONST64(0x0000002000008000), CONST64(0x0000000080008000), CONST64(0x0000002080008000), + CONST64(0x0000000000808000), CONST64(0x0000002000808000), CONST64(0x0000000080808000), CONST64(0x0000002080808000), + CONST64(0x0000000000000080), CONST64(0x0000002000000080), CONST64(0x0000000080000080), CONST64(0x0000002080000080), + CONST64(0x0000000000800080), CONST64(0x0000002000800080), CONST64(0x0000000080800080), CONST64(0x0000002080800080), + CONST64(0x0000000000008080), CONST64(0x0000002000008080), CONST64(0x0000000080008080), CONST64(0x0000002080008080), + CONST64(0x0000000000808080), CONST64(0x0000002000808080), CONST64(0x0000000080808080), CONST64(0x0000002080808080), + CONST64(0x8000000000000000), CONST64(0x8000002000000000), CONST64(0x8000000080000000), CONST64(0x8000002080000000), + CONST64(0x8000000000800000), CONST64(0x8000002000800000), CONST64(0x8000000080800000), CONST64(0x8000002080800000), + CONST64(0x8000000000008000), CONST64(0x8000002000008000), CONST64(0x8000000080008000), CONST64(0x8000002080008000), + CONST64(0x8000000000808000), CONST64(0x8000002000808000), CONST64(0x8000000080808000), CONST64(0x8000002080808000), + CONST64(0x8000000000000080), CONST64(0x8000002000000080), CONST64(0x8000000080000080), CONST64(0x8000002080000080), + CONST64(0x8000000000800080), CONST64(0x8000002000800080), CONST64(0x8000000080800080), CONST64(0x8000002080800080), + CONST64(0x8000000000008080), CONST64(0x8000002000008080), CONST64(0x8000000080008080), CONST64(0x8000002080008080), + CONST64(0x8000000000808080), CONST64(0x8000002000808080), CONST64(0x8000000080808080), CONST64(0x8000002080808080), + CONST64(0x0080000000000000), CONST64(0x0080002000000000), CONST64(0x0080000080000000), CONST64(0x0080002080000000), + CONST64(0x0080000000800000), CONST64(0x0080002000800000), CONST64(0x0080000080800000), CONST64(0x0080002080800000), + CONST64(0x0080000000008000), CONST64(0x0080002000008000), CONST64(0x0080000080008000), CONST64(0x0080002080008000), + CONST64(0x0080000000808000), CONST64(0x0080002000808000), CONST64(0x0080000080808000), CONST64(0x0080002080808000), + CONST64(0x0080000000000080), CONST64(0x0080002000000080), CONST64(0x0080000080000080), CONST64(0x0080002080000080), + CONST64(0x0080000000800080), CONST64(0x0080002000800080), CONST64(0x0080000080800080), CONST64(0x0080002080800080), + CONST64(0x0080000000008080), CONST64(0x0080002000008080), CONST64(0x0080000080008080), CONST64(0x0080002080008080), + CONST64(0x0080000000808080), CONST64(0x0080002000808080), CONST64(0x0080000080808080), CONST64(0x0080002080808080), + CONST64(0x8080000000000000), CONST64(0x8080002000000000), CONST64(0x8080000080000000), CONST64(0x8080002080000000), + CONST64(0x8080000000800000), CONST64(0x8080002000800000), CONST64(0x8080000080800000), CONST64(0x8080002080800000), + CONST64(0x8080000000008000), CONST64(0x8080002000008000), CONST64(0x8080000080008000), CONST64(0x8080002080008000), + CONST64(0x8080000000808000), CONST64(0x8080002000808000), CONST64(0x8080000080808000), CONST64(0x8080002080808000), + CONST64(0x8080000000000080), CONST64(0x8080002000000080), CONST64(0x8080000080000080), CONST64(0x8080002080000080), + CONST64(0x8080000000800080), CONST64(0x8080002000800080), CONST64(0x8080000080800080), CONST64(0x8080002080800080), + CONST64(0x8080000000008080), CONST64(0x8080002000008080), CONST64(0x8080000080008080), CONST64(0x8080002080008080), + CONST64(0x8080000000808080), CONST64(0x8080002000808080), CONST64(0x8080000080808080), CONST64(0x8080002080808080), + CONST64(0x0000800000000000), CONST64(0x0000802000000000), CONST64(0x0000800080000000), CONST64(0x0000802080000000), + CONST64(0x0000800000800000), CONST64(0x0000802000800000), CONST64(0x0000800080800000), CONST64(0x0000802080800000), + CONST64(0x0000800000008000), CONST64(0x0000802000008000), CONST64(0x0000800080008000), CONST64(0x0000802080008000), + CONST64(0x0000800000808000), CONST64(0x0000802000808000), CONST64(0x0000800080808000), CONST64(0x0000802080808000), + CONST64(0x0000800000000080), CONST64(0x0000802000000080), CONST64(0x0000800080000080), CONST64(0x0000802080000080), + CONST64(0x0000800000800080), CONST64(0x0000802000800080), CONST64(0x0000800080800080), CONST64(0x0000802080800080), + CONST64(0x0000800000008080), CONST64(0x0000802000008080), CONST64(0x0000800080008080), CONST64(0x0000802080008080), + CONST64(0x0000800000808080), CONST64(0x0000802000808080), CONST64(0x0000800080808080), CONST64(0x0000802080808080), + CONST64(0x8000800000000000), CONST64(0x8000802000000000), CONST64(0x8000800080000000), CONST64(0x8000802080000000), + CONST64(0x8000800000800000), CONST64(0x8000802000800000), CONST64(0x8000800080800000), CONST64(0x8000802080800000), + CONST64(0x8000800000008000), CONST64(0x8000802000008000), CONST64(0x8000800080008000), CONST64(0x8000802080008000), + CONST64(0x8000800000808000), CONST64(0x8000802000808000), CONST64(0x8000800080808000), CONST64(0x8000802080808000), + CONST64(0x8000800000000080), CONST64(0x8000802000000080), CONST64(0x8000800080000080), CONST64(0x8000802080000080), + CONST64(0x8000800000800080), CONST64(0x8000802000800080), CONST64(0x8000800080800080), CONST64(0x8000802080800080), + CONST64(0x8000800000008080), CONST64(0x8000802000008080), CONST64(0x8000800080008080), CONST64(0x8000802080008080), + CONST64(0x8000800000808080), CONST64(0x8000802000808080), CONST64(0x8000800080808080), CONST64(0x8000802080808080), + CONST64(0x0080800000000000), CONST64(0x0080802000000000), CONST64(0x0080800080000000), CONST64(0x0080802080000000), + CONST64(0x0080800000800000), CONST64(0x0080802000800000), CONST64(0x0080800080800000), CONST64(0x0080802080800000), + CONST64(0x0080800000008000), CONST64(0x0080802000008000), CONST64(0x0080800080008000), CONST64(0x0080802080008000), + CONST64(0x0080800000808000), CONST64(0x0080802000808000), CONST64(0x0080800080808000), CONST64(0x0080802080808000), + CONST64(0x0080800000000080), CONST64(0x0080802000000080), CONST64(0x0080800080000080), CONST64(0x0080802080000080), + CONST64(0x0080800000800080), CONST64(0x0080802000800080), CONST64(0x0080800080800080), CONST64(0x0080802080800080), + CONST64(0x0080800000008080), CONST64(0x0080802000008080), CONST64(0x0080800080008080), CONST64(0x0080802080008080), + CONST64(0x0080800000808080), CONST64(0x0080802000808080), CONST64(0x0080800080808080), CONST64(0x0080802080808080), + CONST64(0x8080800000000000), CONST64(0x8080802000000000), CONST64(0x8080800080000000), CONST64(0x8080802080000000), + CONST64(0x8080800000800000), CONST64(0x8080802000800000), CONST64(0x8080800080800000), CONST64(0x8080802080800000), + CONST64(0x8080800000008000), CONST64(0x8080802000008000), CONST64(0x8080800080008000), CONST64(0x8080802080008000), + CONST64(0x8080800000808000), CONST64(0x8080802000808000), CONST64(0x8080800080808000), CONST64(0x8080802080808000), + CONST64(0x8080800000000080), CONST64(0x8080802000000080), CONST64(0x8080800080000080), CONST64(0x8080802080000080), + CONST64(0x8080800000800080), CONST64(0x8080802000800080), CONST64(0x8080800080800080), CONST64(0x8080802080800080), + CONST64(0x8080800000008080), CONST64(0x8080802000008080), CONST64(0x8080800080008080), CONST64(0x8080802080008080), + CONST64(0x8080800000808080), CONST64(0x8080802000808080), CONST64(0x8080800080808080), CONST64(0x8080802080808080) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000001000000), CONST64(0x0000004001000000), + CONST64(0x0000000000010000), CONST64(0x0000004000010000), CONST64(0x0000000001010000), CONST64(0x0000004001010000), + CONST64(0x0000000000000100), CONST64(0x0000004000000100), CONST64(0x0000000001000100), CONST64(0x0000004001000100), + CONST64(0x0000000000010100), CONST64(0x0000004000010100), CONST64(0x0000000001010100), CONST64(0x0000004001010100), + CONST64(0x0000000000000001), CONST64(0x0000004000000001), CONST64(0x0000000001000001), CONST64(0x0000004001000001), + CONST64(0x0000000000010001), CONST64(0x0000004000010001), CONST64(0x0000000001010001), CONST64(0x0000004001010001), + CONST64(0x0000000000000101), CONST64(0x0000004000000101), CONST64(0x0000000001000101), CONST64(0x0000004001000101), + CONST64(0x0000000000010101), CONST64(0x0000004000010101), CONST64(0x0000000001010101), CONST64(0x0000004001010101), + CONST64(0x0100000000000000), CONST64(0x0100004000000000), CONST64(0x0100000001000000), CONST64(0x0100004001000000), + CONST64(0x0100000000010000), CONST64(0x0100004000010000), CONST64(0x0100000001010000), CONST64(0x0100004001010000), + CONST64(0x0100000000000100), CONST64(0x0100004000000100), CONST64(0x0100000001000100), CONST64(0x0100004001000100), + CONST64(0x0100000000010100), CONST64(0x0100004000010100), CONST64(0x0100000001010100), CONST64(0x0100004001010100), + CONST64(0x0100000000000001), CONST64(0x0100004000000001), CONST64(0x0100000001000001), CONST64(0x0100004001000001), + CONST64(0x0100000000010001), CONST64(0x0100004000010001), CONST64(0x0100000001010001), CONST64(0x0100004001010001), + CONST64(0x0100000000000101), CONST64(0x0100004000000101), CONST64(0x0100000001000101), CONST64(0x0100004001000101), + CONST64(0x0100000000010101), CONST64(0x0100004000010101), CONST64(0x0100000001010101), CONST64(0x0100004001010101), + CONST64(0x0001000000000000), CONST64(0x0001004000000000), CONST64(0x0001000001000000), CONST64(0x0001004001000000), + CONST64(0x0001000000010000), CONST64(0x0001004000010000), CONST64(0x0001000001010000), CONST64(0x0001004001010000), + CONST64(0x0001000000000100), CONST64(0x0001004000000100), CONST64(0x0001000001000100), CONST64(0x0001004001000100), + CONST64(0x0001000000010100), CONST64(0x0001004000010100), CONST64(0x0001000001010100), CONST64(0x0001004001010100), + CONST64(0x0001000000000001), CONST64(0x0001004000000001), CONST64(0x0001000001000001), CONST64(0x0001004001000001), + CONST64(0x0001000000010001), CONST64(0x0001004000010001), CONST64(0x0001000001010001), CONST64(0x0001004001010001), + CONST64(0x0001000000000101), CONST64(0x0001004000000101), CONST64(0x0001000001000101), CONST64(0x0001004001000101), + CONST64(0x0001000000010101), CONST64(0x0001004000010101), CONST64(0x0001000001010101), CONST64(0x0001004001010101), + CONST64(0x0101000000000000), CONST64(0x0101004000000000), CONST64(0x0101000001000000), CONST64(0x0101004001000000), + CONST64(0x0101000000010000), CONST64(0x0101004000010000), CONST64(0x0101000001010000), CONST64(0x0101004001010000), + CONST64(0x0101000000000100), CONST64(0x0101004000000100), CONST64(0x0101000001000100), CONST64(0x0101004001000100), + CONST64(0x0101000000010100), CONST64(0x0101004000010100), CONST64(0x0101000001010100), CONST64(0x0101004001010100), + CONST64(0x0101000000000001), CONST64(0x0101004000000001), CONST64(0x0101000001000001), CONST64(0x0101004001000001), + CONST64(0x0101000000010001), CONST64(0x0101004000010001), CONST64(0x0101000001010001), CONST64(0x0101004001010001), + CONST64(0x0101000000000101), CONST64(0x0101004000000101), CONST64(0x0101000001000101), CONST64(0x0101004001000101), + CONST64(0x0101000000010101), CONST64(0x0101004000010101), CONST64(0x0101000001010101), CONST64(0x0101004001010101), + CONST64(0x0000010000000000), CONST64(0x0000014000000000), CONST64(0x0000010001000000), CONST64(0x0000014001000000), + CONST64(0x0000010000010000), CONST64(0x0000014000010000), CONST64(0x0000010001010000), CONST64(0x0000014001010000), + CONST64(0x0000010000000100), CONST64(0x0000014000000100), CONST64(0x0000010001000100), CONST64(0x0000014001000100), + CONST64(0x0000010000010100), CONST64(0x0000014000010100), CONST64(0x0000010001010100), CONST64(0x0000014001010100), + CONST64(0x0000010000000001), CONST64(0x0000014000000001), CONST64(0x0000010001000001), CONST64(0x0000014001000001), + CONST64(0x0000010000010001), CONST64(0x0000014000010001), CONST64(0x0000010001010001), CONST64(0x0000014001010001), + CONST64(0x0000010000000101), CONST64(0x0000014000000101), CONST64(0x0000010001000101), CONST64(0x0000014001000101), + CONST64(0x0000010000010101), CONST64(0x0000014000010101), CONST64(0x0000010001010101), CONST64(0x0000014001010101), + CONST64(0x0100010000000000), CONST64(0x0100014000000000), CONST64(0x0100010001000000), CONST64(0x0100014001000000), + CONST64(0x0100010000010000), CONST64(0x0100014000010000), CONST64(0x0100010001010000), CONST64(0x0100014001010000), + CONST64(0x0100010000000100), CONST64(0x0100014000000100), CONST64(0x0100010001000100), CONST64(0x0100014001000100), + CONST64(0x0100010000010100), CONST64(0x0100014000010100), CONST64(0x0100010001010100), CONST64(0x0100014001010100), + CONST64(0x0100010000000001), CONST64(0x0100014000000001), CONST64(0x0100010001000001), CONST64(0x0100014001000001), + CONST64(0x0100010000010001), CONST64(0x0100014000010001), CONST64(0x0100010001010001), CONST64(0x0100014001010001), + CONST64(0x0100010000000101), CONST64(0x0100014000000101), CONST64(0x0100010001000101), CONST64(0x0100014001000101), + CONST64(0x0100010000010101), CONST64(0x0100014000010101), CONST64(0x0100010001010101), CONST64(0x0100014001010101), + CONST64(0x0001010000000000), CONST64(0x0001014000000000), CONST64(0x0001010001000000), CONST64(0x0001014001000000), + CONST64(0x0001010000010000), CONST64(0x0001014000010000), CONST64(0x0001010001010000), CONST64(0x0001014001010000), + CONST64(0x0001010000000100), CONST64(0x0001014000000100), CONST64(0x0001010001000100), CONST64(0x0001014001000100), + CONST64(0x0001010000010100), CONST64(0x0001014000010100), CONST64(0x0001010001010100), CONST64(0x0001014001010100), + CONST64(0x0001010000000001), CONST64(0x0001014000000001), CONST64(0x0001010001000001), CONST64(0x0001014001000001), + CONST64(0x0001010000010001), CONST64(0x0001014000010001), CONST64(0x0001010001010001), CONST64(0x0001014001010001), + CONST64(0x0001010000000101), CONST64(0x0001014000000101), CONST64(0x0001010001000101), CONST64(0x0001014001000101), + CONST64(0x0001010000010101), CONST64(0x0001014000010101), CONST64(0x0001010001010101), CONST64(0x0001014001010101), + CONST64(0x0101010000000000), CONST64(0x0101014000000000), CONST64(0x0101010001000000), CONST64(0x0101014001000000), + CONST64(0x0101010000010000), CONST64(0x0101014000010000), CONST64(0x0101010001010000), CONST64(0x0101014001010000), + CONST64(0x0101010000000100), CONST64(0x0101014000000100), CONST64(0x0101010001000100), CONST64(0x0101014001000100), + CONST64(0x0101010000010100), CONST64(0x0101014000010100), CONST64(0x0101010001010100), CONST64(0x0101014001010100), + CONST64(0x0101010000000001), CONST64(0x0101014000000001), CONST64(0x0101010001000001), CONST64(0x0101014001000001), + CONST64(0x0101010000010001), CONST64(0x0101014000010001), CONST64(0x0101010001010001), CONST64(0x0101014001010001), + CONST64(0x0101010000000101), CONST64(0x0101014000000101), CONST64(0x0101010001000101), CONST64(0x0101014001000101), + CONST64(0x0101010000010101), CONST64(0x0101014000010101), CONST64(0x0101010001010101), CONST64(0x0101014001010101) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000100000000), CONST64(0x0000000004000000), CONST64(0x0000000104000000), + CONST64(0x0000000000040000), CONST64(0x0000000100040000), CONST64(0x0000000004040000), CONST64(0x0000000104040000), + CONST64(0x0000000000000400), CONST64(0x0000000100000400), CONST64(0x0000000004000400), CONST64(0x0000000104000400), + CONST64(0x0000000000040400), CONST64(0x0000000100040400), CONST64(0x0000000004040400), CONST64(0x0000000104040400), + CONST64(0x0000000000000004), CONST64(0x0000000100000004), CONST64(0x0000000004000004), CONST64(0x0000000104000004), + CONST64(0x0000000000040004), CONST64(0x0000000100040004), CONST64(0x0000000004040004), CONST64(0x0000000104040004), + CONST64(0x0000000000000404), CONST64(0x0000000100000404), CONST64(0x0000000004000404), CONST64(0x0000000104000404), + CONST64(0x0000000000040404), CONST64(0x0000000100040404), CONST64(0x0000000004040404), CONST64(0x0000000104040404), + CONST64(0x0400000000000000), CONST64(0x0400000100000000), CONST64(0x0400000004000000), CONST64(0x0400000104000000), + CONST64(0x0400000000040000), CONST64(0x0400000100040000), CONST64(0x0400000004040000), CONST64(0x0400000104040000), + CONST64(0x0400000000000400), CONST64(0x0400000100000400), CONST64(0x0400000004000400), CONST64(0x0400000104000400), + CONST64(0x0400000000040400), CONST64(0x0400000100040400), CONST64(0x0400000004040400), CONST64(0x0400000104040400), + CONST64(0x0400000000000004), CONST64(0x0400000100000004), CONST64(0x0400000004000004), CONST64(0x0400000104000004), + CONST64(0x0400000000040004), CONST64(0x0400000100040004), CONST64(0x0400000004040004), CONST64(0x0400000104040004), + CONST64(0x0400000000000404), CONST64(0x0400000100000404), CONST64(0x0400000004000404), CONST64(0x0400000104000404), + CONST64(0x0400000000040404), CONST64(0x0400000100040404), CONST64(0x0400000004040404), CONST64(0x0400000104040404), + CONST64(0x0004000000000000), CONST64(0x0004000100000000), CONST64(0x0004000004000000), CONST64(0x0004000104000000), + CONST64(0x0004000000040000), CONST64(0x0004000100040000), CONST64(0x0004000004040000), CONST64(0x0004000104040000), + CONST64(0x0004000000000400), CONST64(0x0004000100000400), CONST64(0x0004000004000400), CONST64(0x0004000104000400), + CONST64(0x0004000000040400), CONST64(0x0004000100040400), CONST64(0x0004000004040400), CONST64(0x0004000104040400), + CONST64(0x0004000000000004), CONST64(0x0004000100000004), CONST64(0x0004000004000004), CONST64(0x0004000104000004), + CONST64(0x0004000000040004), CONST64(0x0004000100040004), CONST64(0x0004000004040004), CONST64(0x0004000104040004), + CONST64(0x0004000000000404), CONST64(0x0004000100000404), CONST64(0x0004000004000404), CONST64(0x0004000104000404), + CONST64(0x0004000000040404), CONST64(0x0004000100040404), CONST64(0x0004000004040404), CONST64(0x0004000104040404), + CONST64(0x0404000000000000), CONST64(0x0404000100000000), CONST64(0x0404000004000000), CONST64(0x0404000104000000), + CONST64(0x0404000000040000), CONST64(0x0404000100040000), CONST64(0x0404000004040000), CONST64(0x0404000104040000), + CONST64(0x0404000000000400), CONST64(0x0404000100000400), CONST64(0x0404000004000400), CONST64(0x0404000104000400), + CONST64(0x0404000000040400), CONST64(0x0404000100040400), CONST64(0x0404000004040400), CONST64(0x0404000104040400), + CONST64(0x0404000000000004), CONST64(0x0404000100000004), CONST64(0x0404000004000004), CONST64(0x0404000104000004), + CONST64(0x0404000000040004), CONST64(0x0404000100040004), CONST64(0x0404000004040004), CONST64(0x0404000104040004), + CONST64(0x0404000000000404), CONST64(0x0404000100000404), CONST64(0x0404000004000404), CONST64(0x0404000104000404), + CONST64(0x0404000000040404), CONST64(0x0404000100040404), CONST64(0x0404000004040404), CONST64(0x0404000104040404), + CONST64(0x0000040000000000), CONST64(0x0000040100000000), CONST64(0x0000040004000000), CONST64(0x0000040104000000), + CONST64(0x0000040000040000), CONST64(0x0000040100040000), CONST64(0x0000040004040000), CONST64(0x0000040104040000), + CONST64(0x0000040000000400), CONST64(0x0000040100000400), CONST64(0x0000040004000400), CONST64(0x0000040104000400), + CONST64(0x0000040000040400), CONST64(0x0000040100040400), CONST64(0x0000040004040400), CONST64(0x0000040104040400), + CONST64(0x0000040000000004), CONST64(0x0000040100000004), CONST64(0x0000040004000004), CONST64(0x0000040104000004), + CONST64(0x0000040000040004), CONST64(0x0000040100040004), CONST64(0x0000040004040004), CONST64(0x0000040104040004), + CONST64(0x0000040000000404), CONST64(0x0000040100000404), CONST64(0x0000040004000404), CONST64(0x0000040104000404), + CONST64(0x0000040000040404), CONST64(0x0000040100040404), CONST64(0x0000040004040404), CONST64(0x0000040104040404), + CONST64(0x0400040000000000), CONST64(0x0400040100000000), CONST64(0x0400040004000000), CONST64(0x0400040104000000), + CONST64(0x0400040000040000), CONST64(0x0400040100040000), CONST64(0x0400040004040000), CONST64(0x0400040104040000), + CONST64(0x0400040000000400), CONST64(0x0400040100000400), CONST64(0x0400040004000400), CONST64(0x0400040104000400), + CONST64(0x0400040000040400), CONST64(0x0400040100040400), CONST64(0x0400040004040400), CONST64(0x0400040104040400), + CONST64(0x0400040000000004), CONST64(0x0400040100000004), CONST64(0x0400040004000004), CONST64(0x0400040104000004), + CONST64(0x0400040000040004), CONST64(0x0400040100040004), CONST64(0x0400040004040004), CONST64(0x0400040104040004), + CONST64(0x0400040000000404), CONST64(0x0400040100000404), CONST64(0x0400040004000404), CONST64(0x0400040104000404), + CONST64(0x0400040000040404), CONST64(0x0400040100040404), CONST64(0x0400040004040404), CONST64(0x0400040104040404), + CONST64(0x0004040000000000), CONST64(0x0004040100000000), CONST64(0x0004040004000000), CONST64(0x0004040104000000), + CONST64(0x0004040000040000), CONST64(0x0004040100040000), CONST64(0x0004040004040000), CONST64(0x0004040104040000), + CONST64(0x0004040000000400), CONST64(0x0004040100000400), CONST64(0x0004040004000400), CONST64(0x0004040104000400), + CONST64(0x0004040000040400), CONST64(0x0004040100040400), CONST64(0x0004040004040400), CONST64(0x0004040104040400), + CONST64(0x0004040000000004), CONST64(0x0004040100000004), CONST64(0x0004040004000004), CONST64(0x0004040104000004), + CONST64(0x0004040000040004), CONST64(0x0004040100040004), CONST64(0x0004040004040004), CONST64(0x0004040104040004), + CONST64(0x0004040000000404), CONST64(0x0004040100000404), CONST64(0x0004040004000404), CONST64(0x0004040104000404), + CONST64(0x0004040000040404), CONST64(0x0004040100040404), CONST64(0x0004040004040404), CONST64(0x0004040104040404), + CONST64(0x0404040000000000), CONST64(0x0404040100000000), CONST64(0x0404040004000000), CONST64(0x0404040104000000), + CONST64(0x0404040000040000), CONST64(0x0404040100040000), CONST64(0x0404040004040000), CONST64(0x0404040104040000), + CONST64(0x0404040000000400), CONST64(0x0404040100000400), CONST64(0x0404040004000400), CONST64(0x0404040104000400), + CONST64(0x0404040000040400), CONST64(0x0404040100040400), CONST64(0x0404040004040400), CONST64(0x0404040104040400), + CONST64(0x0404040000000004), CONST64(0x0404040100000004), CONST64(0x0404040004000004), CONST64(0x0404040104000004), + CONST64(0x0404040000040004), CONST64(0x0404040100040004), CONST64(0x0404040004040004), CONST64(0x0404040104040004), + CONST64(0x0404040000000404), CONST64(0x0404040100000404), CONST64(0x0404040004000404), CONST64(0x0404040104000404), + CONST64(0x0404040000040404), CONST64(0x0404040100040404), CONST64(0x0404040004040404), CONST64(0x0404040104040404) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000010000000), CONST64(0x0000000410000000), + CONST64(0x0000000000100000), CONST64(0x0000000400100000), CONST64(0x0000000010100000), CONST64(0x0000000410100000), + CONST64(0x0000000000001000), CONST64(0x0000000400001000), CONST64(0x0000000010001000), CONST64(0x0000000410001000), + CONST64(0x0000000000101000), CONST64(0x0000000400101000), CONST64(0x0000000010101000), CONST64(0x0000000410101000), + CONST64(0x0000000000000010), CONST64(0x0000000400000010), CONST64(0x0000000010000010), CONST64(0x0000000410000010), + CONST64(0x0000000000100010), CONST64(0x0000000400100010), CONST64(0x0000000010100010), CONST64(0x0000000410100010), + CONST64(0x0000000000001010), CONST64(0x0000000400001010), CONST64(0x0000000010001010), CONST64(0x0000000410001010), + CONST64(0x0000000000101010), CONST64(0x0000000400101010), CONST64(0x0000000010101010), CONST64(0x0000000410101010), + CONST64(0x1000000000000000), CONST64(0x1000000400000000), CONST64(0x1000000010000000), CONST64(0x1000000410000000), + CONST64(0x1000000000100000), CONST64(0x1000000400100000), CONST64(0x1000000010100000), CONST64(0x1000000410100000), + CONST64(0x1000000000001000), CONST64(0x1000000400001000), CONST64(0x1000000010001000), CONST64(0x1000000410001000), + CONST64(0x1000000000101000), CONST64(0x1000000400101000), CONST64(0x1000000010101000), CONST64(0x1000000410101000), + CONST64(0x1000000000000010), CONST64(0x1000000400000010), CONST64(0x1000000010000010), CONST64(0x1000000410000010), + CONST64(0x1000000000100010), CONST64(0x1000000400100010), CONST64(0x1000000010100010), CONST64(0x1000000410100010), + CONST64(0x1000000000001010), CONST64(0x1000000400001010), CONST64(0x1000000010001010), CONST64(0x1000000410001010), + CONST64(0x1000000000101010), CONST64(0x1000000400101010), CONST64(0x1000000010101010), CONST64(0x1000000410101010), + CONST64(0x0010000000000000), CONST64(0x0010000400000000), CONST64(0x0010000010000000), CONST64(0x0010000410000000), + CONST64(0x0010000000100000), CONST64(0x0010000400100000), CONST64(0x0010000010100000), CONST64(0x0010000410100000), + CONST64(0x0010000000001000), CONST64(0x0010000400001000), CONST64(0x0010000010001000), CONST64(0x0010000410001000), + CONST64(0x0010000000101000), CONST64(0x0010000400101000), CONST64(0x0010000010101000), CONST64(0x0010000410101000), + CONST64(0x0010000000000010), CONST64(0x0010000400000010), CONST64(0x0010000010000010), CONST64(0x0010000410000010), + CONST64(0x0010000000100010), CONST64(0x0010000400100010), CONST64(0x0010000010100010), CONST64(0x0010000410100010), + CONST64(0x0010000000001010), CONST64(0x0010000400001010), CONST64(0x0010000010001010), CONST64(0x0010000410001010), + CONST64(0x0010000000101010), CONST64(0x0010000400101010), CONST64(0x0010000010101010), CONST64(0x0010000410101010), + CONST64(0x1010000000000000), CONST64(0x1010000400000000), CONST64(0x1010000010000000), CONST64(0x1010000410000000), + CONST64(0x1010000000100000), CONST64(0x1010000400100000), CONST64(0x1010000010100000), CONST64(0x1010000410100000), + CONST64(0x1010000000001000), CONST64(0x1010000400001000), CONST64(0x1010000010001000), CONST64(0x1010000410001000), + CONST64(0x1010000000101000), CONST64(0x1010000400101000), CONST64(0x1010000010101000), CONST64(0x1010000410101000), + CONST64(0x1010000000000010), CONST64(0x1010000400000010), CONST64(0x1010000010000010), CONST64(0x1010000410000010), + CONST64(0x1010000000100010), CONST64(0x1010000400100010), CONST64(0x1010000010100010), CONST64(0x1010000410100010), + CONST64(0x1010000000001010), CONST64(0x1010000400001010), CONST64(0x1010000010001010), CONST64(0x1010000410001010), + CONST64(0x1010000000101010), CONST64(0x1010000400101010), CONST64(0x1010000010101010), CONST64(0x1010000410101010), + CONST64(0x0000100000000000), CONST64(0x0000100400000000), CONST64(0x0000100010000000), CONST64(0x0000100410000000), + CONST64(0x0000100000100000), CONST64(0x0000100400100000), CONST64(0x0000100010100000), CONST64(0x0000100410100000), + CONST64(0x0000100000001000), CONST64(0x0000100400001000), CONST64(0x0000100010001000), CONST64(0x0000100410001000), + CONST64(0x0000100000101000), CONST64(0x0000100400101000), CONST64(0x0000100010101000), CONST64(0x0000100410101000), + CONST64(0x0000100000000010), CONST64(0x0000100400000010), CONST64(0x0000100010000010), CONST64(0x0000100410000010), + CONST64(0x0000100000100010), CONST64(0x0000100400100010), CONST64(0x0000100010100010), CONST64(0x0000100410100010), + CONST64(0x0000100000001010), CONST64(0x0000100400001010), CONST64(0x0000100010001010), CONST64(0x0000100410001010), + CONST64(0x0000100000101010), CONST64(0x0000100400101010), CONST64(0x0000100010101010), CONST64(0x0000100410101010), + CONST64(0x1000100000000000), CONST64(0x1000100400000000), CONST64(0x1000100010000000), CONST64(0x1000100410000000), + CONST64(0x1000100000100000), CONST64(0x1000100400100000), CONST64(0x1000100010100000), CONST64(0x1000100410100000), + CONST64(0x1000100000001000), CONST64(0x1000100400001000), CONST64(0x1000100010001000), CONST64(0x1000100410001000), + CONST64(0x1000100000101000), CONST64(0x1000100400101000), CONST64(0x1000100010101000), CONST64(0x1000100410101000), + CONST64(0x1000100000000010), CONST64(0x1000100400000010), CONST64(0x1000100010000010), CONST64(0x1000100410000010), + CONST64(0x1000100000100010), CONST64(0x1000100400100010), CONST64(0x1000100010100010), CONST64(0x1000100410100010), + CONST64(0x1000100000001010), CONST64(0x1000100400001010), CONST64(0x1000100010001010), CONST64(0x1000100410001010), + CONST64(0x1000100000101010), CONST64(0x1000100400101010), CONST64(0x1000100010101010), CONST64(0x1000100410101010), + CONST64(0x0010100000000000), CONST64(0x0010100400000000), CONST64(0x0010100010000000), CONST64(0x0010100410000000), + CONST64(0x0010100000100000), CONST64(0x0010100400100000), CONST64(0x0010100010100000), CONST64(0x0010100410100000), + CONST64(0x0010100000001000), CONST64(0x0010100400001000), CONST64(0x0010100010001000), CONST64(0x0010100410001000), + CONST64(0x0010100000101000), CONST64(0x0010100400101000), CONST64(0x0010100010101000), CONST64(0x0010100410101000), + CONST64(0x0010100000000010), CONST64(0x0010100400000010), CONST64(0x0010100010000010), CONST64(0x0010100410000010), + CONST64(0x0010100000100010), CONST64(0x0010100400100010), CONST64(0x0010100010100010), CONST64(0x0010100410100010), + CONST64(0x0010100000001010), CONST64(0x0010100400001010), CONST64(0x0010100010001010), CONST64(0x0010100410001010), + CONST64(0x0010100000101010), CONST64(0x0010100400101010), CONST64(0x0010100010101010), CONST64(0x0010100410101010), + CONST64(0x1010100000000000), CONST64(0x1010100400000000), CONST64(0x1010100010000000), CONST64(0x1010100410000000), + CONST64(0x1010100000100000), CONST64(0x1010100400100000), CONST64(0x1010100010100000), CONST64(0x1010100410100000), + CONST64(0x1010100000001000), CONST64(0x1010100400001000), CONST64(0x1010100010001000), CONST64(0x1010100410001000), + CONST64(0x1010100000101000), CONST64(0x1010100400101000), CONST64(0x1010100010101000), CONST64(0x1010100410101000), + CONST64(0x1010100000000010), CONST64(0x1010100400000010), CONST64(0x1010100010000010), CONST64(0x1010100410000010), + CONST64(0x1010100000100010), CONST64(0x1010100400100010), CONST64(0x1010100010100010), CONST64(0x1010100410100010), + CONST64(0x1010100000001010), CONST64(0x1010100400001010), CONST64(0x1010100010001010), CONST64(0x1010100410001010), + CONST64(0x1010100000101010), CONST64(0x1010100400101010), CONST64(0x1010100010101010), CONST64(0x1010100410101010) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000040000000), CONST64(0x0000001040000000), + CONST64(0x0000000000400000), CONST64(0x0000001000400000), CONST64(0x0000000040400000), CONST64(0x0000001040400000), + CONST64(0x0000000000004000), CONST64(0x0000001000004000), CONST64(0x0000000040004000), CONST64(0x0000001040004000), + CONST64(0x0000000000404000), CONST64(0x0000001000404000), CONST64(0x0000000040404000), CONST64(0x0000001040404000), + CONST64(0x0000000000000040), CONST64(0x0000001000000040), CONST64(0x0000000040000040), CONST64(0x0000001040000040), + CONST64(0x0000000000400040), CONST64(0x0000001000400040), CONST64(0x0000000040400040), CONST64(0x0000001040400040), + CONST64(0x0000000000004040), CONST64(0x0000001000004040), CONST64(0x0000000040004040), CONST64(0x0000001040004040), + CONST64(0x0000000000404040), CONST64(0x0000001000404040), CONST64(0x0000000040404040), CONST64(0x0000001040404040), + CONST64(0x4000000000000000), CONST64(0x4000001000000000), CONST64(0x4000000040000000), CONST64(0x4000001040000000), + CONST64(0x4000000000400000), CONST64(0x4000001000400000), CONST64(0x4000000040400000), CONST64(0x4000001040400000), + CONST64(0x4000000000004000), CONST64(0x4000001000004000), CONST64(0x4000000040004000), CONST64(0x4000001040004000), + CONST64(0x4000000000404000), CONST64(0x4000001000404000), CONST64(0x4000000040404000), CONST64(0x4000001040404000), + CONST64(0x4000000000000040), CONST64(0x4000001000000040), CONST64(0x4000000040000040), CONST64(0x4000001040000040), + CONST64(0x4000000000400040), CONST64(0x4000001000400040), CONST64(0x4000000040400040), CONST64(0x4000001040400040), + CONST64(0x4000000000004040), CONST64(0x4000001000004040), CONST64(0x4000000040004040), CONST64(0x4000001040004040), + CONST64(0x4000000000404040), CONST64(0x4000001000404040), CONST64(0x4000000040404040), CONST64(0x4000001040404040), + CONST64(0x0040000000000000), CONST64(0x0040001000000000), CONST64(0x0040000040000000), CONST64(0x0040001040000000), + CONST64(0x0040000000400000), CONST64(0x0040001000400000), CONST64(0x0040000040400000), CONST64(0x0040001040400000), + CONST64(0x0040000000004000), CONST64(0x0040001000004000), CONST64(0x0040000040004000), CONST64(0x0040001040004000), + CONST64(0x0040000000404000), CONST64(0x0040001000404000), CONST64(0x0040000040404000), CONST64(0x0040001040404000), + CONST64(0x0040000000000040), CONST64(0x0040001000000040), CONST64(0x0040000040000040), CONST64(0x0040001040000040), + CONST64(0x0040000000400040), CONST64(0x0040001000400040), CONST64(0x0040000040400040), CONST64(0x0040001040400040), + CONST64(0x0040000000004040), CONST64(0x0040001000004040), CONST64(0x0040000040004040), CONST64(0x0040001040004040), + CONST64(0x0040000000404040), CONST64(0x0040001000404040), CONST64(0x0040000040404040), CONST64(0x0040001040404040), + CONST64(0x4040000000000000), CONST64(0x4040001000000000), CONST64(0x4040000040000000), CONST64(0x4040001040000000), + CONST64(0x4040000000400000), CONST64(0x4040001000400000), CONST64(0x4040000040400000), CONST64(0x4040001040400000), + CONST64(0x4040000000004000), CONST64(0x4040001000004000), CONST64(0x4040000040004000), CONST64(0x4040001040004000), + CONST64(0x4040000000404000), CONST64(0x4040001000404000), CONST64(0x4040000040404000), CONST64(0x4040001040404000), + CONST64(0x4040000000000040), CONST64(0x4040001000000040), CONST64(0x4040000040000040), CONST64(0x4040001040000040), + CONST64(0x4040000000400040), CONST64(0x4040001000400040), CONST64(0x4040000040400040), CONST64(0x4040001040400040), + CONST64(0x4040000000004040), CONST64(0x4040001000004040), CONST64(0x4040000040004040), CONST64(0x4040001040004040), + CONST64(0x4040000000404040), CONST64(0x4040001000404040), CONST64(0x4040000040404040), CONST64(0x4040001040404040), + CONST64(0x0000400000000000), CONST64(0x0000401000000000), CONST64(0x0000400040000000), CONST64(0x0000401040000000), + CONST64(0x0000400000400000), CONST64(0x0000401000400000), CONST64(0x0000400040400000), CONST64(0x0000401040400000), + CONST64(0x0000400000004000), CONST64(0x0000401000004000), CONST64(0x0000400040004000), CONST64(0x0000401040004000), + CONST64(0x0000400000404000), CONST64(0x0000401000404000), CONST64(0x0000400040404000), CONST64(0x0000401040404000), + CONST64(0x0000400000000040), CONST64(0x0000401000000040), CONST64(0x0000400040000040), CONST64(0x0000401040000040), + CONST64(0x0000400000400040), CONST64(0x0000401000400040), CONST64(0x0000400040400040), CONST64(0x0000401040400040), + CONST64(0x0000400000004040), CONST64(0x0000401000004040), CONST64(0x0000400040004040), CONST64(0x0000401040004040), + CONST64(0x0000400000404040), CONST64(0x0000401000404040), CONST64(0x0000400040404040), CONST64(0x0000401040404040), + CONST64(0x4000400000000000), CONST64(0x4000401000000000), CONST64(0x4000400040000000), CONST64(0x4000401040000000), + CONST64(0x4000400000400000), CONST64(0x4000401000400000), CONST64(0x4000400040400000), CONST64(0x4000401040400000), + CONST64(0x4000400000004000), CONST64(0x4000401000004000), CONST64(0x4000400040004000), CONST64(0x4000401040004000), + CONST64(0x4000400000404000), CONST64(0x4000401000404000), CONST64(0x4000400040404000), CONST64(0x4000401040404000), + CONST64(0x4000400000000040), CONST64(0x4000401000000040), CONST64(0x4000400040000040), CONST64(0x4000401040000040), + CONST64(0x4000400000400040), CONST64(0x4000401000400040), CONST64(0x4000400040400040), CONST64(0x4000401040400040), + CONST64(0x4000400000004040), CONST64(0x4000401000004040), CONST64(0x4000400040004040), CONST64(0x4000401040004040), + CONST64(0x4000400000404040), CONST64(0x4000401000404040), CONST64(0x4000400040404040), CONST64(0x4000401040404040), + CONST64(0x0040400000000000), CONST64(0x0040401000000000), CONST64(0x0040400040000000), CONST64(0x0040401040000000), + CONST64(0x0040400000400000), CONST64(0x0040401000400000), CONST64(0x0040400040400000), CONST64(0x0040401040400000), + CONST64(0x0040400000004000), CONST64(0x0040401000004000), CONST64(0x0040400040004000), CONST64(0x0040401040004000), + CONST64(0x0040400000404000), CONST64(0x0040401000404000), CONST64(0x0040400040404000), CONST64(0x0040401040404000), + CONST64(0x0040400000000040), CONST64(0x0040401000000040), CONST64(0x0040400040000040), CONST64(0x0040401040000040), + CONST64(0x0040400000400040), CONST64(0x0040401000400040), CONST64(0x0040400040400040), CONST64(0x0040401040400040), + CONST64(0x0040400000004040), CONST64(0x0040401000004040), CONST64(0x0040400040004040), CONST64(0x0040401040004040), + CONST64(0x0040400000404040), CONST64(0x0040401000404040), CONST64(0x0040400040404040), CONST64(0x0040401040404040), + CONST64(0x4040400000000000), CONST64(0x4040401000000000), CONST64(0x4040400040000000), CONST64(0x4040401040000000), + CONST64(0x4040400000400000), CONST64(0x4040401000400000), CONST64(0x4040400040400000), CONST64(0x4040401040400000), + CONST64(0x4040400000004000), CONST64(0x4040401000004000), CONST64(0x4040400040004000), CONST64(0x4040401040004000), + CONST64(0x4040400000404000), CONST64(0x4040401000404000), CONST64(0x4040400040404000), CONST64(0x4040401040404000), + CONST64(0x4040400000000040), CONST64(0x4040401000000040), CONST64(0x4040400040000040), CONST64(0x4040401040000040), + CONST64(0x4040400000400040), CONST64(0x4040401000400040), CONST64(0x4040400040400040), CONST64(0x4040401040400040), + CONST64(0x4040400000004040), CONST64(0x4040401000004040), CONST64(0x4040400040004040), CONST64(0x4040401040004040), + CONST64(0x4040400000404040), CONST64(0x4040401000404040), CONST64(0x4040400040404040), CONST64(0x4040401040404040) + }}; + +#endif + + +static void cookey(const ulong32 *raw1, ulong32 *keyout); #ifdef CLEAN_STACK -void _deskey(const unsigned char *key, short edf, unsigned long *keyout) +void _deskey(const unsigned char *key, short edf, ulong32 *keyout) #else -void deskey(const unsigned char *key, short edf, unsigned long *keyout) +void deskey(const unsigned char *key, short edf, ulong32 *keyout) #endif { - unsigned long i, j, l, m, n, kn[32]; + ulong32 i, j, l, m, n, kn[32]; unsigned char pc1m[56], pcr[56]; for (j=0; j < 56; j++) { - l = (unsigned long)pc1[j]; + l = (ulong32)pc1[j]; m = l & 7; pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); } @@ -256,7 +1306,7 @@ void deskey(const unsigned char *key, short edf, unsigned long *keyout) n = m + 1; kn[m] = kn[n] = 0L; for (j=0; j < 28; j++) { - l = j + (unsigned long)totrot[i]; + l = j + (ulong32)totrot[i]; if (l < 28) { pcr[j] = pc1m[l]; } else { @@ -264,7 +1314,7 @@ void deskey(const unsigned char *key, short edf, unsigned long *keyout) } } for (/*j = 28*/; j < 56; j++) { - l = j + (unsigned long)totrot[i]; + l = j + (ulong32)totrot[i]; if (l < 56) { pcr[j] = pc1m[l]; } else { @@ -285,22 +1335,22 @@ void deskey(const unsigned char *key, short edf, unsigned long *keyout) } #ifdef CLEAN_STACK -void deskey(const unsigned char *key, short edf, unsigned long *keyout) +void deskey(const unsigned char *key, short edf, ulong32 *keyout) { _deskey(key, edf, keyout); - burn_stack(sizeof(int)*5 + sizeof(unsigned long)*32 + sizeof(unsigned char)*112); + burn_stack(sizeof(int)*5 + sizeof(ulong32)*32 + sizeof(unsigned char)*112); } #endif #ifdef CLEAN_STACK -static void _cookey(const unsigned long *raw1, unsigned long *keyout) +static void _cookey(const ulong32 *raw1, ulong32 *keyout) #else -static void cookey(const unsigned long *raw1, unsigned long *keyout) +static void cookey(const ulong32 *raw1, ulong32 *keyout) #endif { - unsigned long *cook; - const unsigned long *raw0; - unsigned long dough[32]; + ulong32 *cook; + const ulong32 *raw0; + ulong32 dough[32]; int i; cook = dough; @@ -321,25 +1371,26 @@ static void cookey(const unsigned long *raw1, unsigned long *keyout) } #ifdef CLEAN_STACK -static void cookey(const unsigned long *raw1, unsigned long *keyout) +static void cookey(const ulong32 *raw1, ulong32 *keyout) { _cookey(raw1, keyout); - burn_stack(sizeof(unsigned long *) * 2 + sizeof(unsigned long)*32 + sizeof(int)); + burn_stack(sizeof(ulong32 *) * 2 + sizeof(ulong32)*32 + sizeof(int)); } #endif #ifndef CLEAN_STACK -static void desfunc(unsigned long *block, const unsigned long *keys) +static void desfunc(ulong32 *block, const ulong32 *keys) #else -static void _desfunc(unsigned long *block, const unsigned long *keys) +static void _desfunc(ulong32 *block, const ulong32 *keys) #endif { - unsigned long work, right, leftt; + ulong32 work, right, leftt; int round; leftt = block[0]; right = block[1]; +#ifdef SMALL_CODE work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; right ^= work; leftt ^= (work << 4); @@ -362,6 +1413,21 @@ static void _desfunc(unsigned long *block, const unsigned long *keys) leftt ^= work; right ^= work; leftt = ROL(leftt, 1); +#else + { + ulong64 tmp; + tmp = des_ip[0][byte(leftt, 0)] ^ + des_ip[1][byte(leftt, 1)] ^ + des_ip[2][byte(leftt, 2)] ^ + des_ip[3][byte(leftt, 3)] ^ + des_ip[4][byte(right, 0)] ^ + des_ip[5][byte(right, 1)] ^ + des_ip[6][byte(right, 2)] ^ + des_ip[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + } +#endif for (round = 0; round < 8; round++) { work = ROR(right, 4) ^ *keys++; @@ -386,11 +1452,13 @@ static void _desfunc(unsigned long *block, const unsigned long *keys) ^ SP4[(work >> 16) & 0x3fL] ^ SP2[(work >> 24) & 0x3fL]; } - right = (right << 31) | (right >> 1); + +#ifdef SMALL_CODE + right = ROR(right, 1); work = (leftt ^ right) & 0xaaaaaaaaL; leftt ^= work; right ^= work; - leftt = (leftt << 31) | (leftt >> 1); + leftt = ROR(leftt, 1); work = ((leftt >> 8) ^ right) & 0x00ff00ffL; right ^= work; leftt ^= (work << 8); @@ -404,16 +1472,31 @@ static void _desfunc(unsigned long *block, const unsigned long *keys) work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; leftt ^= work; right ^= (work << 4); +#else + { + ulong64 tmp; + tmp = des_fp[0][byte(leftt, 0)] ^ + des_fp[1][byte(leftt, 1)] ^ + des_fp[2][byte(leftt, 2)] ^ + des_fp[3][byte(leftt, 3)] ^ + des_fp[4][byte(right, 0)] ^ + des_fp[5][byte(right, 1)] ^ + des_fp[6][byte(right, 2)] ^ + des_fp[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + } +#endif block[0] = right; block[1] = leftt; } #ifdef CLEAN_STACK -static void desfunc(unsigned long *block, const unsigned long *keys) +static void desfunc(ulong32 *block, const ulong32 *keys) { _desfunc(block, keys); - burn_stack(sizeof(unsigned long) * 4 + sizeof(int)); + burn_stack(sizeof(ulong32) * 4 + sizeof(int)); } #endif @@ -462,7 +1545,7 @@ int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_k void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { - unsigned long work[2]; + ulong32 work[2]; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); _ARGCHK(key != NULL); @@ -475,7 +1558,7 @@ void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key * void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { - unsigned long work[2]; + ulong32 work[2]; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); _ARGCHK(key != NULL); @@ -488,7 +1571,7 @@ void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key * void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { - unsigned long work[2]; + ulong32 work[2]; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); @@ -504,7 +1587,7 @@ void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { - unsigned long work[2]; + ulong32 work[2]; _ARGCHK(pt != NULL); _ARGCHK(ct != NULL); _ARGCHK(key != NULL); diff --git a/dh.c b/dh.c index 7540292..d23632d 100644 --- a/dh.c +++ b/dh.c @@ -155,8 +155,8 @@ int dh_test(void) #if 0 printf("dh_test():testing size %d-bits\n", sets[x].size * 8); #endif - if (mp_read_radix(&g,(unsigned char *)sets[x].base, 64) != MP_OKAY) { goto error; } - if (mp_read_radix(&p,(unsigned char *)sets[x].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&g,(char *)sets[x].base, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&p,(char *)sets[x].prime, 64) != MP_OKAY) { goto error; } /* ensure p is prime */ if ((res = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } @@ -464,7 +464,7 @@ int dh_shared_secret(dh_key *private_key, dh_key *public_key, return CRYPT_MEM; } - if (mp_read_radix(&p, (unsigned char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, (char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } if (mp_exptmod(&public_key->y, &private_key->x, &p, &tmp) != MP_OKAY) { goto error; } /* enough space for output? */ diff --git a/ecc.c b/ecc.c index 13f55e8..5bc6398 100644 --- a/ecc.c +++ b/ecc.c @@ -528,8 +528,8 @@ int ecc_test(void) #if 0 printf("Testing %d\n", sets[i].size); #endif - if (mp_read_radix(&modulus, (unsigned char *)sets[i].prime, 64) != MP_OKAY) { goto error; } - if (mp_read_radix(&order, (unsigned char *)sets[i].order, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&modulus, (char *)sets[i].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&order, (char *)sets[i].order, 64) != MP_OKAY) { goto error; } /* is prime actually prime? */ if (is_prime(&modulus, &primality) != CRYPT_OK) { goto error; } @@ -545,8 +545,8 @@ int ecc_test(void) goto done1; } - if (mp_read_radix(&G->x, (unsigned char *)sets[i].Gx, 64) != MP_OKAY) { goto error; } - if (mp_read_radix(&G->y, (unsigned char *)sets[i].Gy, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&G->x, (char *)sets[i].Gx, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&G->y, (char *)sets[i].Gy, 64) != MP_OKAY) { goto error; } /* then we should have G == (order + 1)G */ if (mp_add_d(&order, 1, &order) != MP_OKAY) { goto error; } @@ -624,9 +624,9 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) } /* read in the specs for this key */ - if (mp_read_radix(&prime, (unsigned char *)sets[key->idx].prime, 64) != MP_OKAY) { goto error; } - if (mp_read_radix(&base->x, (unsigned char *)sets[key->idx].Gx, 64) != MP_OKAY) { goto error; } - if (mp_read_radix(&base->y, (unsigned char *)sets[key->idx].Gy, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&prime, (char *)sets[key->idx].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&base->x, (char *)sets[key->idx].Gx, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&base->y, (char *)sets[key->idx].Gy, 64) != MP_OKAY) { goto error; } if (mp_read_unsigned_bin(&key->k, (unsigned char *)buf, keysize) != MP_OKAY) { goto error; } /* make the public key */ @@ -671,12 +671,12 @@ static int compress_y_point(ecc_point *pt, int idx, int *result) } /* get x^3 - 3x + b */ - if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 64) != MP_OKAY) { goto error; } /* p = B */ + if (mp_read_radix(&p, (char *)sets[idx].B, 64) != MP_OKAY) { goto error; } /* p = B */ if (mp_expt_d(&pt->x, 3, &tmp) != MP_OKAY) { goto error; } /* tmp = pX^3 */ if (mp_mul_d(&pt->x, 3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ if (mp_sub(&tmp, &tmp2, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ if (mp_add(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp + p */ - if (mp_read_radix(&p, (unsigned char *)sets[idx].prime, 64) != MP_OKAY) { goto error; } /* p = prime */ + if (mp_read_radix(&p, (char *)sets[idx].prime, 64) != MP_OKAY) { goto error; } /* p = prime */ if (mp_mod(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ /* now find square root */ @@ -713,12 +713,12 @@ static int expand_y_point(ecc_point *pt, int idx, int result) } /* get x^3 - 3x + b */ - if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 64) != MP_OKAY) { goto error; } /* p = B */ + if (mp_read_radix(&p, (char *)sets[idx].B, 64) != MP_OKAY) { goto error; } /* p = B */ if (mp_expt_d(&pt->x, 3, &tmp) != MP_OKAY) { goto error; } /* tmp = pX^3 */ if (mp_mul_d(&pt->x, 3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ if (mp_sub(&tmp, &tmp2, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ if (mp_add(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp + p */ - if (mp_read_radix(&p, (unsigned char *)sets[idx].prime, 64) != MP_OKAY) { goto error; } /* p = prime */ + if (mp_read_radix(&p, (char *)sets[idx].prime, 64) != MP_OKAY) { goto error; } /* p = prime */ if (mp_mod(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ /* now find square root */ @@ -935,7 +935,7 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, return CRYPT_MEM; } - if (mp_read_radix(&prime, (unsigned char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&prime, (char *)sets[private_key->idx].prime, 64) != MP_OKAY) { goto error; } if ((res = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime)) != CRYPT_OK) { goto done1; } x = (unsigned long)mp_unsigned_bin_size(&result->x); diff --git a/ecc_sys.c b/ecc_sys.c index e15e473..1dd19e1 100644 --- a/ecc_sys.c +++ b/ecc_sys.c @@ -238,7 +238,7 @@ int ecc_sign_hash(const unsigned char *in, unsigned long inlen, ecc_free(&pubkey); return CRYPT_MEM; } - if (mp_read_radix(&p, (unsigned char *)sets[key->idx].order, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, (char *)sets[key->idx].order, 64) != MP_OKAY) { goto error; } if (mp_read_unsigned_bin(&b, (unsigned char *)in, (int)inlen) != MP_OKAY) { goto error; } /* find b = (m - x)/k */ @@ -389,7 +389,7 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, if (mp_read_unsigned_bin(&m, (unsigned char *)hash, (int)inlen) != MP_OKAY) { goto error; } /* load prime */ - if (mp_read_radix(&p, (unsigned char *)sets[key->idx].prime, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, (char *)sets[key->idx].prime, 64) != MP_OKAY) { goto error; } /* calculate barrett stuff */ mp_set(&mu, 1); @@ -406,8 +406,8 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, 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; } - if (mp_read_radix(&mG->y, (unsigned char *)sets[key->idx].Gy, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&mG->x, (char *)sets[key->idx].Gx, 64) != MP_OKAY) { goto error; } + if (mp_read_radix(&mG->y, (char *)sets[key->idx].Gy, 64) != MP_OKAY) { goto error; } if (ecc_mulmod(&m, mG, mG, &p) != CRYPT_OK) { goto error; } /* compare mG to bA + Y */ diff --git a/makefile b/makefile index cfec020..a5b2ead 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.87 +VERSION=0.88 #ch1-01-1 # Compiler and Linker Names @@ -28,9 +28,8 @@ CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Wshadow -Werror # optimize for SPEED #CFLAGS += -O3 -funroll-loops -#add -fomit-frame-pointer. v3.2 is buggy for certain platforms so this is used for files it is known to work for -#default is off but you may enable this to get further performance [make sure you run the test suite!] -#EXT_CFLAGS = -fomit-frame-pointer +#add -fomit-frame-pointer. v3.2 is buggy for certain platforms! +#CFLAGS += -fomit-frame-pointer # optimize for SIZE CFLAGS += -Os @@ -48,6 +47,8 @@ HASH=hashsum CRYPT=encrypt SMALL=small PROF=x86_prof +TV=tv_gen + #LIBPATH-The directory for libtomcrypt to be installed to. #INCPATH-The directory to install the header files for libtomcrypt. @@ -58,17 +59,22 @@ INCPATH=/usr/include DATAPATH=/usr/share/doc/libtomcrypt/pdf #List of objects to compile. + +#Leave MPI built-in or force developer to link against libtommath? +MPIOBJECT=mpi.o + 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 des.o \ safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o \ -mpi.o prime.o twofish.o packet.o hmac.o strings.o +prime.o twofish.o packet.o hmac.o strings.o $(MPIOBJECT) TESTOBJECTS=demos/test.o HASHOBJECTS=demos/hashsum.o CRYPTOBJECTS=demos/encrypt.o SMALLOBJECTS=demos/small.o PROFS=demos/x86_prof.o +TVS=demos/tv_gen.o #Files left over from making the crypt.pdf. LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind @@ -91,45 +97,8 @@ dh.o: dh.c dh_sys.c aes.o: aes.c aes_tab.c sha512.o: sha512.c sha384.c -#These are objects that are known to build with -fomit-frame-pointer successfully [RISK!] -aes.o: aes.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c aes.c - -blowfish.o: blowfish.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c blowfish.c - -cast5.o: cast5.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c cast5.c - -des.o: des.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c des.c - -twofish.o: twofish.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c twofish.c - -md2.o: md2.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c md2.c - -md4.o: md4.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c md4.c - -md5.o: md5.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c md5.c - -sha1.o: sha1.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c sha1.c - -sha256.o: sha256.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c sha256.c - -sha512.o: sha512.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c sha512.c - -tiger.o: tiger.c - $(CC) $(CFLAGS) $(EXT_CFLAGS) -c tiger.c - #This rule makes the libtomcrypt library. -library: $(OBJECTS) +library: $(OBJECTS) $(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS) ranlib $(LIBNAME) @@ -150,7 +119,10 @@ small: library $(SMALLOBJECTS) $(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN) x86_prof: library $(PROFS) - $(CC) demos/x86_prof.o $(LIBNAME) -o $(PROF) + $(CC) $(PROFS) $(LIBNAME) -o $(PROF) + +tv_gen: library $(TVS) + $(CC) $(TVS) $(LIBNAME) -o $(TV) #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 @@ -167,8 +139,8 @@ install: library docs #documentation. clean: rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) - rm -f $(TEST) $(HASH) $(COMPRESSED) - rm -f *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat + rm -f $(TEST) $(HASH) $(COMPRESSED) $(PROFS) $(PROF) $(TVS) $(TV) + rm -f *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat hash_tv.txt cipher_tv.txt #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 @@ -181,6 +153,12 @@ docs: crypt.tex pdflatex crypt > /dev/null rm -f $(LEFTOVERS) +#beta +beta: clean + cd .. ; rm -rf crypt* libtomcrypt-$(VERSION)-beta ; mkdir libtomcrypt-$(VERSION)-beta ; \ + cp -R ./libtomcrypt/* ./libtomcrypt-$(VERSION)-beta/ ; tar -c libtomcrypt-$(VERSION)-beta/* > crypt-$(VERSION)-beta.tar ; \ + bzip2 -9vv crypt-$(VERSION)-beta.tar ; zip -9 -r crypt-$(VERSION)-beta.zip libtomcrypt-$(VERSION)-beta/* + #zipup the project (take that!) zipup: clean docs cd .. ; rm -rf crypt* libtomcrypt-$(VERSION) ; mkdir libtomcrypt-$(VERSION) ; \ diff --git a/makefile.msvc b/makefile.msvc index 3af1440..c5ab49c 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -12,7 +12,7 @@ OBJECTS=keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj \ bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj \ md5.obj md4.obj md2.obj sha256.obj sha512.obj xtea.obj aes.obj des.obj \ safer_tab.obj safer.obj safer+.obj rc4.obj rc2.obj rc6.obj rc5.obj cast5.obj noekeon.obj \ -blowfish.obj crypt.obj mpi.obj prime.obj twofish.obj packet.obj hmac.obj strings.obj +blowfish.obj crypt.obj mpi.obj prime.obj twofish.obj packet.obj hmac.obj strings.obj library: $(OBJECTS) lib /out:tomcrypt.lib $(OBJECTS) @@ -24,4 +24,7 @@ test: library test.obj cl test.obj tomcrypt.lib advapi32.lib x86_prof: demos/x86_prof.c library - cl $(CFLAGS) demos/x86_prof.c tomcrypt.lib advapi32.lib \ No newline at end of file + cl $(CFLAGS) demos/x86_prof.c tomcrypt.lib advapi32.lib + +tv_gen: demos/tv_gen.c library + cl $(CFLAGS) demos/tv_gen.c tomcrypt.lib advapi32.lib diff --git a/md5.c b/md5.c index 71481ae..1a4dc95 100644 --- a/md5.c +++ b/md5.c @@ -20,16 +20,16 @@ const struct _hash_descriptor md5_desc = #define I(x,y,z) (y^(x|(~z))) #define FF(a,b,c,d,M,s,t) \ - a = (a + F(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b; #define GG(a,b,c,d,M,s,t) \ - a = (a + G(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b; #define HH(a,b,c,d,M,s,t) \ - a = (a + H(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b; #define II(a,b,c,d,M,s,t) \ - a = (a + I(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b; #ifdef CLEAN_STACK static void _md5_compress(hash_state *md) diff --git a/mpi.c b/mpi.c index d427eaa..b92e915 100644 --- a/mpi.c +++ b/mpi.c @@ -14,6 +14,7 @@ * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org */ #include "mycrypt.h" +#include /* computes the modular inverse via binary extended euclidean algorithm, * that is c = 1/a mod b @@ -67,8 +68,8 @@ top: if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto __ERR; } - /* 4.2 if A or B is odd then */ - if (mp_iseven (&B) == 0) { + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto __ERR; } @@ -85,8 +86,8 @@ top: if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto __ERR; } - /* 5.2 if C,D are even then */ - if (mp_iseven (&D) == 0) { + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { /* D = (D-x)/2 */ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto __ERR; @@ -216,7 +217,7 @@ fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) * that W[ix-1] have the carry cleared (see after the inner loop) */ register mp_digit mu; - mu = (((mp_digit) (W[ix] & MP_MASK)) * rho) & MP_MASK; + mu = MULT(W[ix] & MP_MASK, rho) & MP_MASK; /* a = a + mu * m * b**i * @@ -245,7 +246,7 @@ fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) /* inner loop */ for (iy = 0; iy < n->used; iy++) { - *_W++ += ((mp_word) mu) * ((mp_word) * tmpn++); + *_W++ += MULT(mu, *tmpn++); } } @@ -383,7 +384,7 @@ fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) pb = MIN (b->used, digs - ix); for (iy = 0; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += MULT(tmpx, *tmpy++); } } @@ -500,7 +501,7 @@ fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) /* compute column products for digits above the minimum */ for (; iy < pb; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += MULT(tmpx, *tmpy++); } } } @@ -596,7 +597,7 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) * 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]); + W2[ix + ix] = MULT(a->dp[ix], a->dp[ix]); { register mp_digit tmpx, *tmpy; @@ -614,7 +615,7 @@ fast_s_mp_sqr (mp_int * a, mp_int * b) /* inner products */ for (iy = ix + 1; iy < pa; iy++) { - *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); + *_W++ += MULT(tmpx, *tmpy++); } } } @@ -1116,6 +1117,50 @@ mp_cmp_mag (mp_int * a, mp_int * b) /* End: bn_mp_cmp_mag.c */ +/* Start: bn_mp_cnt_lsb.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a) +{ + int x; + mp_digit q; + + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + while ((q & 1) == 0) { + q >>= 1; + x += 1; + } + + return x; +} + + +/* End: bn_mp_cnt_lsb.c */ + /* Start: bn_mp_copy.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -1234,14 +1279,18 @@ mp_count_bits (mp_int * a) */ #include -/* integer signed division. c*b + d == a [e.g. a/b, c=quotient, d=remainder] +/* 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.. + * 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. + * 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) @@ -1249,7 +1298,6 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) mp_int q, x, y, t1, t2; int res, n, t, i, norm, neg; - /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; @@ -1293,7 +1341,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; x.sign = y.sign = MP_ZPOS; - /* normalize both x and y, ensure that y >= b/2, [b == 2^DIGIT_BIT] */ + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ norm = mp_count_bits(&y) % DIGIT_BIT; if (norm < (int)(DIGIT_BIT-1)) { norm = (DIGIT_BIT-1) - norm; @@ -1311,8 +1359,8 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) 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} */ + /* 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; } @@ -1331,7 +1379,8 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) if (i > x.used) continue; - /* step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ if (x.dp[i] == y.dp[t]) { q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); } else { @@ -1344,7 +1393,11 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) 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; */ + /* 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; @@ -1365,7 +1418,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) t2.used = 3; } while (mp_cmp_mag(&t1, &t2) == MP_GT); - /* step 3.3 x = x - q{i-t-1} * y * b^{i-t-1} */ + /* 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; } @@ -1378,7 +1431,7 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) goto __Y; } - /* step 3.4 if x < 0 then { x = x + y*b^{i-t-1}; q{i-t-1} -= 1; } */ + /* 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; @@ -1394,7 +1447,10 @@ mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) } } - /* now q is the quotient and x is the remainder [which we have to normalize] */ + /* 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; @@ -1549,11 +1605,14 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) /* shift any bit count < DIGIT_BIT */ D = (mp_digit) (b % DIGIT_BIT); if (D != 0) { - register mp_digit *tmpc, mask; + register mp_digit *tmpc, mask, shift; /* mask */ mask = (((mp_digit)1) << D) - 1; + /* shift for lsb */ + shift = DIGIT_BIT - D; + /* alias */ tmpc = c->dp + (c->used - 1); @@ -1564,7 +1623,7 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) rr = *tmpc & mask; /* shift the current word and mix in the carry bits from the previous word */ - *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); + *tmpc = (*tmpc >> D) | (r << shift); --tmpc; /* set the carry to the carry bits of the current word found above */ @@ -1582,70 +1641,70 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) /* End: bn_mp_div_2d.c */ /* Start: bn_mp_div_3.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* divide by three (based on routine from MPI and the GMP manual) */ -int -mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) -{ - mp_int q; - mp_word w, t; - mp_digit b; - int res, ix; - - /* b = 2**DIGIT_BIT / 3 */ - b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); - - if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { - return res; - } - - q.used = a->used; - q.sign = a->sign; - w = 0; - for (ix = a->used - 1; ix >= 0; ix--) { - w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); - - if (w >= 3) { - t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); - w -= (t << ((mp_word)1)) + t; - while (w >= 3) { - t += 1; - w -= 3; - } - } else { - t = 0; - } - q.dp[ix] = (mp_digit)t; - } - - if (d != NULL) { - *d = (mp_digit)w; - } - - if (c != NULL) { - mp_clamp(&q); - mp_exch(&q, c); - } - mp_clear(&q); - - return res; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); + w -= (t << ((mp_word)1)) + t; + while (w >= 3) { + t += 1; + w -= 3; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + /* End: bn_mp_div_3.c */ @@ -1671,7 +1730,8 @@ int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) { mp_int q; - mp_word w, t; + mp_word w; + mp_digit t; int res, ix; if (b == 0) { @@ -1693,7 +1753,7 @@ mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); if (w >= b) { - t = w / b; + t = (mp_digit)(w / b); w = w % b; } else { t = 0; @@ -1718,40 +1778,40 @@ mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) /* End: bn_mp_div_d.c */ /* Start: bn_mp_dr_is_modulus.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines if a number is a valid DR modulus */ -int mp_dr_is_modulus(mp_int *a) -{ - int ix; - - /* must be at least two digits */ - if (a->used < 2) { - return 0; - } - - for (ix = 1; ix < a->used; ix++) { - if (a->dp[ix] != MP_MASK) { - return 0; - } - } - return 1; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + /* End: bn_mp_dr_is_modulus.c */ @@ -1817,7 +1877,7 @@ top: /* compute (x mod B**m) + mp * [x/B**m] inline and inplace */ for (i = 0; i < m; i++) { - r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + r = MULT(*tmpx2++, k) + *tmpx1 + mu; *tmpx1++ = (mp_digit)(r & MP_MASK); mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); } @@ -1846,32 +1906,32 @@ top: /* End: bn_mp_dr_reduce.c */ /* Start: bn_mp_dr_setup.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines the setup value */ -void mp_dr_setup(mp_int *a, mp_digit *d) -{ - /* the casts are required if DIGIT_BIT is one less than - * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] - */ - *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - - ((mp_word)a->dp[0])); -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + /* End: bn_mp_dr_setup.c */ @@ -2066,10 +2126,17 @@ mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) * * Uses Montgomery or Diminished Radix reduction [whichever appropriate] */ + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) { - mp_int M[256], res; + mp_int M[TAB_SIZE], res; mp_digit buf, mp; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; @@ -2103,13 +2170,19 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) } #endif + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } - /* init G array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init (&M[x])) != MP_OKAY) { - for (y = 0; y < x; y++) { + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { mp_clear (&M[y]); } + mp_clear(&M[1]); return err; } } @@ -2302,7 +2375,8 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) err = MP_OKAY; __RES:mp_clear (&res); __M: - for (x = 0; x < (1 << winsize); x++) { + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { mp_clear (&M[x]); } return err; @@ -2310,6 +2384,122 @@ __M: /* End: bn_mp_exptmod_fast.c */ +/* Start: bn_mp_fread.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (mp_s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + + +/* End: bn_mp_fread.c */ + +/* Start: bn_mp_fwrite.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + len = mp_radix_size(a, radix); + if (len == 0) { + return MP_VAL; + } + + buf = malloc(len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + free(buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + free(buf); + return MP_VAL; + } + } + + free(buf); + return MP_OKAY; +} + + +/* End: bn_mp_fwrite.c */ + /* Start: bn_mp_gcd.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -2327,13 +2517,12 @@ __M: */ #include -/* Greatest Common Divisor using the binary method [Algorithm B, page 338, vol2 of TAOCP] - */ +/* Greatest Common Divisor using the binary method */ int mp_gcd (mp_int * a, mp_int * b, mp_int * c) { - mp_int u, v, t; - int k, res, neg; + mp_int u, v; + int k, u_lsb, v_lsb, res; /* either zero than gcd is the largest */ if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { @@ -2347,9 +2536,6 @@ mp_gcd (mp_int * a, mp_int * b, mp_int * c) return MP_OKAY; } - /* if both are negative they share (-1) as a common divisor */ - neg = (a->sign == b->sign) ? a->sign : MP_ZPOS; - if ((res = mp_init_copy (&u, a)) != MP_OKAY) { return res; } @@ -2361,71 +2547,55 @@ mp_gcd (mp_int * a, mp_int * b, mp_int * c) /* must be positive for the remainder of the algorithm */ u.sign = v.sign = MP_ZPOS; - if ((res = mp_init (&t)) != MP_OKAY) { + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MIN(u_lsb, v_lsb); + + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto __V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto __V; + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto __V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + while (mp_iszero(&v) == 0) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto __V; + } + + /* Divide out all factors of two */ + if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { goto __V; } - - /* B1. Find power of two */ - k = 0; - while (mp_iseven(&u) == 1 && mp_iseven(&v) == 1) { - ++k; - if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { - goto __T; - } - if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { - goto __T; - } - } - - /* B2. Initialize */ - if (mp_isodd(&u) == 1) { - /* t = -v */ - if ((res = mp_copy (&v, &t)) != MP_OKAY) { - goto __T; - } - t.sign = MP_NEG; - } else { - /* t = u */ - if ((res = mp_copy (&u, &t)) != MP_OKAY) { - goto __T; - } - } - - do { - /* B3 (and B4). Halve t, if even */ - while (t.used != 0 && mp_iseven(&t) == 1) { - if ((res = mp_div_2 (&t, &t)) != MP_OKAY) { - goto __T; - } - } - - /* B5. if t>0 then u=t otherwise v=-t */ - if (t.used != 0 && t.sign != MP_NEG) { - if ((res = mp_copy (&t, &u)) != MP_OKAY) { - goto __T; - } - } else { - if ((res = mp_copy (&t, &v)) != MP_OKAY) { - goto __T; - } - v.sign = (v.sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; - } - - /* B6. t = u - v, if t != 0 loop otherwise terminate */ - if ((res = mp_sub (&u, &v, &t)) != MP_OKAY) { - goto __T; - } - } while (mp_iszero(&t) == 0); - - /* multiply by 2^k which we divided out at the beginning */ - if ((res = mp_mul_2d (&u, k, &u)) != MP_OKAY) { - goto __T; - } - - mp_exch (&u, c); - c->sign = neg; + c->sign = MP_ZPOS; res = MP_OKAY; -__T:mp_clear (&t); __V:mp_clear (&u); __U:mp_clear (&v); return res; @@ -2570,7 +2740,7 @@ mp_init_size (mp_int * a, int size) { /* pad size so there are always extra digits */ - size += (MP_PREC * 2) - (size & (MP_PREC - 1)); + size += (MP_PREC * 2) - (size & (MP_PREC - 1)); /* alloc mem */ a->dp = OPT_CAST calloc (sizeof (mp_digit), size); @@ -2603,6 +2773,7 @@ mp_init_size (mp_int * a, int size) */ #include +/* hac 14.61, pp608 */ int mp_invmod (mp_int * a, mp_int * b, mp_int * c) { @@ -2610,17 +2781,18 @@ mp_invmod (mp_int * a, mp_int * b, mp_int * c) int res; /* b cannot be negative */ - if (b->sign == MP_NEG) { + if (b->sign == MP_NEG || mp_iszero(b) == 1) { return MP_VAL; } /* if the modulus is odd we can use a faster routine instead */ - if (mp_iseven (b) == 0) { + if (mp_isodd (b) == 1) { return fast_mp_invmod (a, b, c); } /* init temps */ - if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { return res; } @@ -2632,10 +2804,6 @@ mp_invmod (mp_int * a, mp_int * b, mp_int * c) goto __ERR; } - if ((res = mp_abs (&x, &x)) != MP_OKAY) { - goto __ERR; - } - /* 2. [modified] if x,y are both even then return an error! */ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { res = MP_VAL; @@ -2652,7 +2820,6 @@ mp_invmod (mp_int * a, mp_int * b, mp_int * c) mp_set (&A, 1); mp_set (&D, 1); - top: /* 4. while u is even do */ while (mp_iseven (&u) == 1) { @@ -2661,13 +2828,13 @@ top: goto __ERR; } /* 4.2 if A or B is odd then */ - if (mp_iseven (&A) == 0 || mp_iseven (&B) == 0) { + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { - goto __ERR; + goto __ERR; } if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { - goto __ERR; + goto __ERR; } } /* A = A/2, B = B/2 */ @@ -2679,21 +2846,20 @@ top: } } - /* 5. while v is even do */ while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto __ERR; } - /* 5.2 if C,D are even then */ - if (mp_iseven (&C) == 0 || mp_iseven (&D) == 0) { + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { - goto __ERR; + goto __ERR; } if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { - goto __ERR; + goto __ERR; } } /* C = C/2, D = D/2 */ @@ -2746,10 +2912,23 @@ top: goto __ERR; } - /* a is now the inverse */ + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* C is now the inverse */ mp_exch (&C, c); res = MP_OKAY; - __ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); return res; } @@ -2777,10 +2956,10 @@ __ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); * HAC pp. 73 Algorithm 2.149 */ int -mp_jacobi (mp_int * a, mp_int * n, int *c) +mp_jacobi (mp_int * a, mp_int * p, int *c) { - mp_int a1, n1, e; - int s, r, res; + mp_int a1, p1; + int k, s, r, res; mp_digit residue; /* step 1. if a == 0, return 0 */ @@ -2796,39 +2975,30 @@ mp_jacobi (mp_int * a, mp_int * n, int *c) } /* default */ - s = 0; + k = s = 0; - /* step 3. write a = a1 * 2^e */ + /* step 3. write a = a1 * 2**k */ if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { return res; } - if ((res = mp_init (&n1)) != MP_OKAY) { + if ((res = mp_init (&p1)) != 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; - } - + k = k + 1; if ((res = mp_div_2 (&a1, &a1)) != MP_OKAY) { - goto __E; + goto __P1; } } /* step 4. if e is even set s=1 */ - if (mp_iseven (&e) == 1) { + if ((k & 1) == 0) { 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; - } + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; if (residue == 1 || residue == 7) { s = 1; @@ -2837,17 +3007,9 @@ mp_jacobi (mp_int * a, mp_int * n, int *c) } } - /* 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; - } + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; } /* if a1 == 1 we're done */ @@ -2855,19 +3017,18 @@ mp_jacobi (mp_int * a, mp_int * n, int *c) *c = s; } else { /* n1 = n mod a1 */ - if ((res = mp_mod (n, &a1, &n1)) != MP_OKAY) { - goto __E; + if ((res = mp_mod (p, &a1, &p1)) != MP_OKAY) { + goto __P1; } - if ((res = mp_jacobi (&n1, &a1, &r)) != MP_OKAY) { - goto __E; + if ((res = mp_jacobi (&p1, &a1, &r)) != MP_OKAY) { + goto __P1; } *c = s * r; } /* done */ res = MP_OKAY; -__E:mp_clear (&e); -__N1:mp_clear (&n1); +__P1:mp_clear (&p1); __A1:mp_clear (&a1); return res; } @@ -3505,7 +3666,7 @@ mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) for (ix = 0; ix < n->used; ix++) { /* mu = ai * m' mod b */ - mu = (x->dp[ix] * rho) & MP_MASK; + mu = MULT(x->dp[ix], rho) & MP_MASK; /* a = a + mu * m * b**i */ { @@ -3522,7 +3683,7 @@ mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) /* Multiply and add in place */ for (iy = 0; iy < n->used; iy++) { - r = ((mp_word) mu) * ((mp_word) * tmpn++) + + r = MULT(mu, *tmpn++) + ((mp_word) u) + ((mp_word) * tmpx); u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK)); @@ -3758,12 +3919,6 @@ mp_mul_2 (mp_int * a, mp_int * b) */ #include -/* NOTE: This routine requires updating. For instance the c->used = c->alloc bit - is wrong. We should just shift c->used digits then set the carry as c->dp[c->used] = carry - - To be fixed for LTM 0.18 - */ - /* shift left by a certain bit count */ int mp_mul_2d (mp_int * a, int b, mp_int * c) @@ -3778,8 +3933,8 @@ mp_mul_2d (mp_int * a, int b, mp_int * c) } } - if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) { - if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) { + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { return res; } } @@ -3790,17 +3945,19 @@ mp_mul_2d (mp_int * a, int b, mp_int * c) return res; } } - c->used = c->alloc; /* shift any bit count < DIGIT_BIT */ d = (mp_digit) (b % DIGIT_BIT); if (d != 0) { - register mp_digit *tmpc, mask, r, rr; + register mp_digit *tmpc, shift, mask, r, rr; register int x; /* bitmask for carries */ mask = (((mp_digit)1) << d) - 1; + /* shift for msbs */ + shift = DIGIT_BIT - d; + /* alias */ tmpc = c->dp; @@ -3808,7 +3965,7 @@ mp_mul_2d (mp_int * a, int b, mp_int * c) r = 0; for (x = 0; x < c->used; x++) { /* get the higher bits of the current word */ - rr = (*tmpc >> (DIGIT_BIT - d)) & mask; + rr = (*tmpc >> shift) & mask; /* shift the current word and OR in the carry */ *tmpc = ((*tmpc << d) | r) & MP_MASK; @@ -3817,6 +3974,11 @@ mp_mul_2d (mp_int * a, int b, mp_int * c) /* set the carry to the carry bits of the current word */ r = rr; } + + /* set final carry */ + if (r != 0) { + c->dp[c->used++] = r; + } } mp_clamp (c); return MP_OKAY; @@ -3860,6 +4022,7 @@ mp_mul_d (mp_int * a, mp_digit b, mp_int * c) /* set the new temporary used count */ c->used = pa + 1; + c->sign = a->sign; { register mp_digit u, *tmpa, *tmpc; @@ -3876,7 +4039,7 @@ mp_mul_d (mp_int * a, mp_digit b, mp_int * c) u = 0; for (ix = 0; ix < pa; ix++) { /* compute product and carry sum for this term */ - r = ((mp_word) u) + ((mp_word) * tmpa++) * ((mp_word) b); + r = ((mp_word) u) + MULT(*tmpa++, b); /* mask off higher bits to get a single digit */ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); @@ -4026,11 +4189,13 @@ void mp_clear_multi(mp_int *mp, ...) /* find the n'th root of an integer * - * Result found such that (c)^b <= a and (c+1)^b > a + * 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]. + * 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, etc]. */ int mp_n_root (mp_int * a, mp_digit b, mp_int * c) @@ -4068,33 +4233,39 @@ mp_n_root (mp_int * a, mp_digit b, mp_int * c) 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) */ + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { goto __T3; } /* numerator */ - if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { /* t2 = t1^b */ + /* t2 = t1**b */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { goto __T3; } - if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { /* t2 = t1^b - a */ + /* t2 = t1**b - a */ + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { goto __T3; } - if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { /* t3 = t1^(b-1) * b */ + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { goto __T3; } - if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { /* t3 = (t1^b - a)/(b * t1^(b-1)) */ + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { goto __T3; } if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { goto __T3; } - } - while (mp_cmp (&t1, &t2) != MP_EQ); + } while (mp_cmp (&t1, &t2) != MP_EQ); /* result can be off by a few so check */ for (;;) { @@ -4229,9 +4400,9 @@ mp_or (mp_int * a, mp_int * b, mp_int * c) /* performs one Fermat test. * - * If "a" were prime then b^a == b (mod a) since the order of + * If "a" were prime then b**a == b (mod a) since the order of * the multiplicative sub-group would be phi(a) = a-1. That means - * it would be the same as b^(a mod (a-1)) == b^1 == b (mod a). + * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a). * * Sets result to 1 if the congruence holds, or zero otherwise. */ @@ -4249,7 +4420,7 @@ mp_prime_fermat (mp_int * a, mp_int * b, int *result) return err; } - /* compute t = b^a mod a */ + /* compute t = b**a mod a */ if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { goto __T; } @@ -4283,7 +4454,8 @@ __T:mp_clear (&t); */ #include -/* determines if an integers is divisible by one of the first 256 primes or not +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not * * sets result to 0 if not, 1 if yes */ @@ -4297,12 +4469,6 @@ mp_prime_is_divisible (mp_int * a, int *result) *result = 0; for (ix = 0; ix < PRIME_SIZE; ix++) { - /* is it equal to the prime? */ - if (mp_cmp_d (a, __prime_tab[ix]) == MP_EQ) { - *result = 1; - return MP_OKAY; - } - /* what is a mod __prime_tab[ix] */ if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { return err; @@ -4441,19 +4607,17 @@ mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) goto __N1; } - /* set 2^s * r = n1 */ + /* set 2**s * r = n1 */ if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { goto __N1; } - s = 0; - while (mp_iseven (&r) == 1) { - ++s; - if ((err = mp_div_2 (&r, &r)) != MP_OKAY) { - goto __R; - } + + s = mp_cnt_lsb(&r); + if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) { + goto __R; } - /* compute y = b^r mod a */ + /* compute y = b**r mod a */ if ((err = mp_init (&y)) != MP_OKAY) { goto __R; } @@ -4467,12 +4631,12 @@ mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) /* while j <= s-1 and y != n1 */ while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { - goto __Y; + goto __Y; } /* if y == 1 then composite */ if (mp_cmp_d (&y, 1) == MP_EQ) { - goto __Y; + goto __Y; } ++j; @@ -4552,6 +4716,86 @@ int mp_prime_next_prime(mp_int *a, int t) /* End: bn_mp_prime_next_prime.c */ +/* Start: bn_mp_radix_size.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* returns size of ASCII reprensentation */ +int +mp_radix_size (mp_int * a, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + + /* special case for binary */ + if (radix == 2) { + return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + } + + if (radix < 2 || radix > 64) { + return 0; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return 0; + } + + digs = 0; + if (t.sign == MP_NEG) { + ++digs; + t.sign = MP_ZPOS; + } + + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return 0; + } + ++digs; + } + mp_clear (&t); + return digs + 1; +} + + +/* End: bn_mp_radix_size.c */ + +/* Start: bn_mp_radix_smap.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* chars used in radix conversions */ +const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* End: bn_mp_radix_smap.c */ + /* Start: bn_mp_rand.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -4605,6 +4849,87 @@ mp_rand (mp_int * a, int digits) /* End: bn_mp_rand.c */ +/* Start: bn_mp_read_radix.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* 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; + + /* make sure the radix is ok */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + /* set the integer to the default of zero */ + mp_zero (a); + + /* process each digit of the string */ + while (*str) { + /* if the radix < 36 the conversion is case insensitive + * this allows numbers like 1AB and 1ab to represent the same value + * [e.g. in hex] + */ + ch = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == mp_s_rmap[y]) { + break; + } + } + + /* if the char was found in the map + * and is less than the given radix add it + * to the number, otherwise exit the loop. + */ + 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; + } + + /* set the sign only if a != 0 */ + if (mp_iszero(a) != 1) { + a->sign = neg; + } + return MP_OKAY; +} + +/* End: bn_mp_read_radix.c */ + /* Start: bn_mp_read_signed_bin.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -4769,183 +5094,183 @@ CLEANUP: /* End: bn_mp_reduce.c */ /* Start: bn_mp_reduce_2k.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* reduces a modulo n where n is of the form 2**p - k */ -int -mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k) -{ - mp_int q; - int p, res; - - if ((res = mp_init(&q)) != MP_OKAY) { - return res; - } - - p = mp_count_bits(n); -top: - /* q = a/2**p, a = a mod 2**p */ - if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { - goto ERR; - } - - if (k != 1) { - /* q = q * k */ - if ((res = mp_mul_d(&q, k, &q)) != MP_OKAY) { - goto ERR; - } - } - - /* a = a + q */ - if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { - goto ERR; - } - - if (mp_cmp_mag(a, n) != MP_LT) { - s_mp_sub(a, n, a); - goto top; - } - -ERR: - mp_clear(&q); - return res; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduces a modulo n where n is of the form 2**p - k */ +int +mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (k != 1) { + /* q = q * k */ + if ((res = mp_mul_d(&q, k, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + /* End: bn_mp_reduce_2k.c */ /* Start: bn_mp_reduce_2k_setup.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines the setup value */ -int -mp_reduce_2k_setup(mp_int *a, mp_digit *d) -{ - int res, p; - mp_int tmp; - - if ((res = mp_init(&tmp)) != MP_OKAY) { - return res; - } - - p = mp_count_bits(a); - if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { - mp_clear(&tmp); - return res; - } - - *d = tmp.dp[0]; - mp_clear(&tmp); - return MP_OKAY; -} +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +int +mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} /* End: bn_mp_reduce_2k_setup.c */ /* Start: bn_mp_reduce_is_2k.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* determines if mp_reduce_2k can be used */ -int -mp_reduce_is_2k(mp_int *a) -{ - int ix, iy; - - if (a->used == 0) { - return 0; - } else if (a->used == 1) { - return 1; - } else if (a->used > 1) { - iy = mp_count_bits(a); - for (ix = DIGIT_BIT; ix < iy; ix++) { - if ((a->dp[ix/DIGIT_BIT] & - ((mp_digit)1 << (mp_digit)(ix % DIGIT_BIT))) == 0) { - return 0; - } - } - } - return 1; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if mp_reduce_2k can be used */ +int +mp_reduce_is_2k(mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return 0; + } else if (a->used == 1) { + return 1; + } else if (a->used > 1) { + iy = mp_count_bits(a); + for (ix = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[ix/DIGIT_BIT] & + ((mp_digit)1 << (mp_digit)(ix % DIGIT_BIT))) == 0) { + return 0; + } + } + } + return 1; +} + /* End: bn_mp_reduce_is_2k.c */ /* Start: bn_mp_reduce_setup.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* pre-calculate the value required for Barrett reduction - * For a given modulus "b" it calulates the value required in "a" - */ -int -mp_reduce_setup (mp_int * a, mp_int * b) -{ - int res; - - if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { - return res; - } - return mp_div (a, b, a, NULL); -} +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} /* End: bn_mp_reduce_setup.c */ @@ -5449,506 +5774,580 @@ mp_to_unsigned_bin (mp_int * a, unsigned char *b) /* End: bn_mp_to_unsigned_bin.c */ /* Start: bn_mp_toom_mul.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* multiplication using the Toom-Cook 3-way algorithm */ -int -mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) -{ - mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; - int res, B; - - /* init temps */ - if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, - &a0, &a1, &a2, &b0, &b1, - &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { - return res; - } - - /* B */ - B = MIN(a->used, b->used) / 3; - - /* a = a2 * B**2 + a1 * B + a0 */ - if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_copy(a, &a1)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&a1, B); - mp_mod_2d(&a1, DIGIT_BIT * B, &a1); - - if ((res = mp_copy(a, &a2)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&a2, B*2); - - /* b = b2 * B**2 + b1 * B + b0 */ - if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_copy(b, &b1)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&b1, B); - mp_mod_2d(&b1, DIGIT_BIT * B, &b1); - - if ((res = mp_copy(b, &b2)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&b2, B*2); - - /* w0 = a0*b0 */ - if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { - goto ERR; - } - - /* w4 = a2 * b2 */ - if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { - goto ERR; - } - - /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ - if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { - goto ERR; - } - - /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ - if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { - goto ERR; - } - - - /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ - if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { - goto ERR; - } - - /* now solve the matrix - - 0 0 0 0 1 - 1 2 4 8 16 - 1 1 1 1 1 - 16 8 4 2 1 - 1 0 0 0 0 - - using 12 subtractions, 4 shifts, - 2 small divisions and 1 small multiplication - */ - - /* r1 - r4 */ - if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r0 */ - if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1/2 */ - if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3/2 */ - if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { - goto ERR; - } - /* r2 - r0 - r4 */ - if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { - goto ERR; - } - /* r1 - r2 */ - if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r2 */ - if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1 - 8r0 */ - if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - 8r4 */ - if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { - goto ERR; - } - /* 3r2 - r1 - r3 */ - if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { - goto ERR; - } - /* r1 - r2 */ - if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r2 */ - if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1/3 */ - if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { - goto ERR; - } - /* r3/3 */ - if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { - goto ERR; - } - - /* at this point shift W[n] by B*n */ - if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { - goto ERR; - } - -ERR: - mp_clear_multi(&w0, &w1, &w2, &w3, &w4, - &a0, &a1, &a2, &b0, &b1, - &b2, &tmp1, &tmp2, NULL); - return res; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplication using the Toom-Cook 3-way algorithm */ +int +mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B**2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, + 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL); + return res; +} + /* End: bn_mp_toom_mul.c */ /* Start: bn_mp_toom_sqr.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* squaring using Toom-Cook 3-way algorithm */ -int -mp_toom_sqr(mp_int *a, mp_int *b) -{ - mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; - int res, B; - - /* init temps */ - if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { - return res; - } - - /* B */ - B = a->used / 3; - - /* a = a2 * B^2 + a1 * B + a0 */ - if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_copy(a, &a1)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&a1, B); - mp_mod_2d(&a1, DIGIT_BIT * B, &a1); - - if ((res = mp_copy(a, &a2)) != MP_OKAY) { - goto ERR; - } - mp_rshd(&a2, B*2); - - /* w0 = a0*a0 */ - if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { - goto ERR; - } - - /* w4 = a2 * a2 */ - if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { - goto ERR; - } - - /* w1 = (a2 + 2(a1 + 2a0))**2 */ - if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { - goto ERR; - } - - /* w3 = (a0 + 2(a1 + 2a2))**2 */ - if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { - goto ERR; - } - - - /* w2 = (a2 + a1 + a0)**2 */ - if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { - goto ERR; - } - - /* now solve the matrix - - 0 0 0 0 1 - 1 2 4 8 16 - 1 1 1 1 1 - 16 8 4 2 1 - 1 0 0 0 0 - - using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. - */ - - /* r1 - r4 */ - if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r0 */ - if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1/2 */ - if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3/2 */ - if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { - goto ERR; - } - /* r2 - r0 - r4 */ - if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { - goto ERR; - } - /* r1 - r2 */ - if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r2 */ - if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1 - 8r0 */ - if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - 8r4 */ - if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { - goto ERR; - } - /* 3r2 - r1 - r3 */ - if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { - goto ERR; - } - /* r1 - r2 */ - if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { - goto ERR; - } - /* r3 - r2 */ - if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { - goto ERR; - } - /* r1/3 */ - if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { - goto ERR; - } - /* r3/3 */ - if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { - goto ERR; - } - - /* at this point shift W[n] by B*n */ - if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { - goto ERR; - } - - if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { - goto ERR; - } - if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { - goto ERR; - } - -ERR: - mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); - return res; -} - +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* squaring using Toom-Cook 3-way algorithm */ +int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B^2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + /* End: bn_mp_toom_sqr.c */ +/* Start: bn_mp_toradix.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int +mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == 1) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = mp_s_rmap[d]; + ++digs; + } + + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number] + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str++ = '\0'; + + + mp_clear (&t); + return MP_OKAY; +} + + +/* End: bn_mp_toradix.c */ + /* Start: bn_mp_unsigned_bin_size.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -6053,6 +6452,216 @@ mp_zero (mp_int * a) /* End: bn_mp_zero.c */ +/* Start: bn_mult.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ + #include + +/* this file provides a nxn=>2n multiplier based on the + * fact that xy = ((x-y)^2 - (x+y)^2)/4 + * so by having a square table for 0..2^(n+1) + * we can compute (x+y)^2 via table lookup, etc.. + */ + +#ifdef SLOW_MULT + +/* table of x^2 for -510..510 */ +#if defined(MP_8BIT) || defined(MP_16BIT) +static const unsigned long sqr[] = { +65025, 64770, 64516, 64262, 64009, 63756, 63504, 63252, 63001, 62750, 62500, 62250, +62001, 61752, 61504, 61256, 61009, 60762, 60516, 60270, 60025, 59780, 59536, 59292, +59049, 58806, 58564, 58322, 58081, 57840, 57600, 57360, 57121, 56882, 56644, 56406, +56169, 55932, 55696, 55460, 55225, 54990, 54756, 54522, 54289, 54056, 53824, 53592, +53361, 53130, 52900, 52670, 52441, 52212, 51984, 51756, 51529, 51302, 51076, 50850, +50625, 50400, 50176, 49952, 49729, 49506, 49284, 49062, 48841, 48620, 48400, 48180, +47961, 47742, 47524, 47306, 47089, 46872, 46656, 46440, 46225, 46010, 45796, 45582, +45369, 45156, 44944, 44732, 44521, 44310, 44100, 43890, 43681, 43472, 43264, 43056, +42849, 42642, 42436, 42230, 42025, 41820, 41616, 41412, 41209, 41006, 40804, 40602, +40401, 40200, 40000, 39800, 39601, 39402, 39204, 39006, 38809, 38612, 38416, 38220, +38025, 37830, 37636, 37442, 37249, 37056, 36864, 36672, 36481, 36290, 36100, 35910, +35721, 35532, 35344, 35156, 34969, 34782, 34596, 34410, 34225, 34040, 33856, 33672, +33489, 33306, 33124, 32942, 32761, 32580, 32400, 32220, 32041, 31862, 31684, 31506, +31329, 31152, 30976, 30800, 30625, 30450, 30276, 30102, 29929, 29756, 29584, 29412, +29241, 29070, 28900, 28730, 28561, 28392, 28224, 28056, 27889, 27722, 27556, 27390, +27225, 27060, 26896, 26732, 26569, 26406, 26244, 26082, 25921, 25760, 25600, 25440, +25281, 25122, 24964, 24806, 24649, 24492, 24336, 24180, 24025, 23870, 23716, 23562, +23409, 23256, 23104, 22952, 22801, 22650, 22500, 22350, 22201, 22052, 21904, 21756, +21609, 21462, 21316, 21170, 21025, 20880, 20736, 20592, 20449, 20306, 20164, 20022, +19881, 19740, 19600, 19460, 19321, 19182, 19044, 18906, 18769, 18632, 18496, 18360, +18225, 18090, 17956, 17822, 17689, 17556, 17424, 17292, 17161, 17030, 16900, 16770, +16641, 16512, 16384, 16256, 16129, 16002, 15876, 15750, 15625, 15500, 15376, 15252, +15129, 15006, 14884, 14762, 14641, 14520, 14400, 14280, 14161, 14042, 13924, 13806, +13689, 13572, 13456, 13340, 13225, 13110, 12996, 12882, 12769, 12656, 12544, 12432, +12321, 12210, 12100, 11990, 11881, 11772, 11664, 11556, 11449, 11342, 11236, 11130, +11025, 10920, 10816, 10712, 10609, 10506, 10404, 10302, 10201, 10100, 10000, 9900, + 9801, 9702, 9604, 9506, 9409, 9312, 9216, 9120, 9025, 8930, 8836, 8742, + 8649, 8556, 8464, 8372, 8281, 8190, 8100, 8010, 7921, 7832, 7744, 7656, + 7569, 7482, 7396, 7310, 7225, 7140, 7056, 6972, 6889, 6806, 6724, 6642, + 6561, 6480, 6400, 6320, 6241, 6162, 6084, 6006, 5929, 5852, 5776, 5700, + 5625, 5550, 5476, 5402, 5329, 5256, 5184, 5112, 5041, 4970, 4900, 4830, + 4761, 4692, 4624, 4556, 4489, 4422, 4356, 4290, 4225, 4160, 4096, 4032, + 3969, 3906, 3844, 3782, 3721, 3660, 3600, 3540, 3481, 3422, 3364, 3306, + 3249, 3192, 3136, 3080, 3025, 2970, 2916, 2862, 2809, 2756, 2704, 2652, + 2601, 2550, 2500, 2450, 2401, 2352, 2304, 2256, 2209, 2162, 2116, 2070, + 2025, 1980, 1936, 1892, 1849, 1806, 1764, 1722, 1681, 1640, 1600, 1560, + 1521, 1482, 1444, 1406, 1369, 1332, 1296, 1260, 1225, 1190, 1156, 1122, + 1089, 1056, 1024, 992, 961, 930, 900, 870, 841, 812, 784, 756, + 729, 702, 676, 650, 625, 600, 576, 552, 529, 506, 484, 462, + 441, 420, 400, 380, 361, 342, 324, 306, 289, 272, 256, 240, + 225, 210, 196, 182, 169, 156, 144, 132, 121, 110, 100, 90, + 81, 72, 64, 56, 49, 42, 36, 30, 25, 20, 16, 12, + 9, 6, 4, 2, 1, 0, 0, 0, 1, 2, 4, 6, + 9, 12, 16, 20, 25, 30, 36, 42, 49, 56, 64, 72, + 81, 90, 100, 110, 121, 132, 144, 156, 169, 182, 196, 210, + 225, 240, 256, 272, 289, 306, 324, 342, 361, 380, 400, 420, + 441, 462, 484, 506, 529, 552, 576, 600, 625, 650, 676, 702, + 729, 756, 784, 812, 841, 870, 900, 930, 961, 992, 1024, 1056, + 1089, 1122, 1156, 1190, 1225, 1260, 1296, 1332, 1369, 1406, 1444, 1482, + 1521, 1560, 1600, 1640, 1681, 1722, 1764, 1806, 1849, 1892, 1936, 1980, + 2025, 2070, 2116, 2162, 2209, 2256, 2304, 2352, 2401, 2450, 2500, 2550, + 2601, 2652, 2704, 2756, 2809, 2862, 2916, 2970, 3025, 3080, 3136, 3192, + 3249, 3306, 3364, 3422, 3481, 3540, 3600, 3660, 3721, 3782, 3844, 3906, + 3969, 4032, 4096, 4160, 4225, 4290, 4356, 4422, 4489, 4556, 4624, 4692, + 4761, 4830, 4900, 4970, 5041, 5112, 5184, 5256, 5329, 5402, 5476, 5550, + 5625, 5700, 5776, 5852, 5929, 6006, 6084, 6162, 6241, 6320, 6400, 6480, + 6561, 6642, 6724, 6806, 6889, 6972, 7056, 7140, 7225, 7310, 7396, 7482, + 7569, 7656, 7744, 7832, 7921, 8010, 8100, 8190, 8281, 8372, 8464, 8556, + 8649, 8742, 8836, 8930, 9025, 9120, 9216, 9312, 9409, 9506, 9604, 9702, + 9801, 9900, 10000, 10100, 10201, 10302, 10404, 10506, 10609, 10712, 10816, 10920, +11025, 11130, 11236, 11342, 11449, 11556, 11664, 11772, 11881, 11990, 12100, 12210, +12321, 12432, 12544, 12656, 12769, 12882, 12996, 13110, 13225, 13340, 13456, 13572, +13689, 13806, 13924, 14042, 14161, 14280, 14400, 14520, 14641, 14762, 14884, 15006, +15129, 15252, 15376, 15500, 15625, 15750, 15876, 16002, 16129, 16256, 16384, 16512, +16641, 16770, 16900, 17030, 17161, 17292, 17424, 17556, 17689, 17822, 17956, 18090, +18225, 18360, 18496, 18632, 18769, 18906, 19044, 19182, 19321, 19460, 19600, 19740, +19881, 20022, 20164, 20306, 20449, 20592, 20736, 20880, 21025, 21170, 21316, 21462, +21609, 21756, 21904, 22052, 22201, 22350, 22500, 22650, 22801, 22952, 23104, 23256, +23409, 23562, 23716, 23870, 24025, 24180, 24336, 24492, 24649, 24806, 24964, 25122, +25281, 25440, 25600, 25760, 25921, 26082, 26244, 26406, 26569, 26732, 26896, 27060, +27225, 27390, 27556, 27722, 27889, 28056, 28224, 28392, 28561, 28730, 28900, 29070, +29241, 29412, 29584, 29756, 29929, 30102, 30276, 30450, 30625, 30800, 30976, 31152, +31329, 31506, 31684, 31862, 32041, 32220, 32400, 32580, 32761, 32942, 33124, 33306, +33489, 33672, 33856, 34040, 34225, 34410, 34596, 34782, 34969, 35156, 35344, 35532, +35721, 35910, 36100, 36290, 36481, 36672, 36864, 37056, 37249, 37442, 37636, 37830, +38025, 38220, 38416, 38612, 38809, 39006, 39204, 39402, 39601, 39800, 40000, 40200, +40401, 40602, 40804, 41006, 41209, 41412, 41616, 41820, 42025, 42230, 42436, 42642, +42849, 43056, 43264, 43472, 43681, 43890, 44100, 44310, 44521, 44732, 44944, 45156, +45369, 45582, 45796, 46010, 46225, 46440, 46656, 46872, 47089, 47306, 47524, 47742, +47961, 48180, 48400, 48620, 48841, 49062, 49284, 49506, 49729, 49952, 50176, 50400, +50625, 50850, 51076, 51302, 51529, 51756, 51984, 52212, 52441, 52670, 52900, 53130, +53361, 53592, 53824, 54056, 54289, 54522, 54756, 54990, 55225, 55460, 55696, 55932, +56169, 56406, 56644, 56882, 57121, 57360, 57600, 57840, 58081, 58322, 58564, 58806, +59049, 59292, 59536, 59780, 60025, 60270, 60516, 60762, 61009, 61256, 61504, 61752, +62001, 62250, 62500, 62750, 63001, 63252, 63504, 63756, 64009, 64262, 64516, 64770, +65025}; +#endif + +#if defined(MP_8BIT) +/* + 4 add/sub + 2 table lookups + - + 6 operations + + versus + + 8 shifts + 8 ands + 8 jump/zero + 8 adds + -- + 32 operations +*/ +mp_word s_mp_mult(mp_digit a, mp_digit b) +{ + int A, B; + /* since mp_digit < 9-bits a+b may truncate... */ + A = a; B = b; + A += 510; + return (mp_word)(sqr[A+B] - sqr[A-B]); +} +#elif defined(MP_16BIT) +/* + 17 add/sub + 4 shifts + 8 table lookups + 2 ands + -- + 31 operations + + A double/multiply would require + + 16 shifts + 16 ands + 16 jump/zero + 16 adds + -- + 64 operations + */ +mp_word s_mp_mult(mp_digit a, mp_digit b) +{ + mp_digit a1, a2, b1, b2; + a1 = a&255; a2 = a>>8; + b1 = (b&255)+510; b2 = (b>>8)+510; + return (mp_word)( + (sqr[b1+a1] - sqr[b1-a1]) + + ((sqr[b1+a2] + sqr[b2+a1] - (sqr[b1-a2] + sqr[b2-a1]))<<8) + + ((sqr[b2+a2] - sqr[b2-a2])<<16)); +} +#elif defined(MP_28BIT) +/* use a 2-ary sliding window + + 29 shifts + 14 additions + 13 ands + 18 table lookups + -- + 74 operations + + versus 4*28 == 112 via the other method +*/ +mp_word s_mp_mult(mp_digit a, mp_digit b) +{ + mp_digit wnd[4]; + mp_word res; + + /* make window */ + wnd[0] = 0; + wnd[1] = a; + wnd[2] = a<<1; + wnd[3] = (a<<1) + a; + + /* go over the 28 bits of b */ +#define RND(i) res = (res << 2) + ((mp_word)wnd[(b>>(2*i))&3]); + res = wnd[b>>26]; + RND(12); RND(11); RND(10); RND( 9); + RND( 8); RND( 7); RND( 6); RND( 5); + RND( 4); RND( 3); RND( 2); RND( 1); RND(0); + return res; +} +#else +mp_word s_mp_mult(mp_digit a, mp_digit b) +{ + return ((mp_word)a)*((mp_word)b); +} +#endif + +#endif /* SLOW_MULT */ + +/* End: bn_mult.c */ + /* Start: bn_prime_tab.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -6112,232 +6721,6 @@ const mp_digit __prime_tab[] = { /* End: bn_prime_tab.c */ -/* Start: bn_radix.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -/* chars used in radix conversions */ -static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; - -/* read a string [ASCII] in a given radix */ -int -mp_read_radix (mp_int * a, char *str, int radix) -{ - int y, res, neg; - char ch; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - if (*str == '-') { - ++str; - neg = MP_NEG; - } else { - neg = MP_ZPOS; - } - - mp_zero (a); - while (*str) { - ch = (char) ((radix < 36) ? toupper (*str) : *str); - for (y = 0; y < 64; y++) { - if (ch == s_rmap[y]) { - break; - } - } - - if (y < radix) { - if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { - return res; - } - if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { - return res; - } - } else { - break; - } - ++str; - } - a->sign = neg; - return MP_OKAY; -} - -/* stores a bignum as a ASCII string in a given radix (2..64) */ -int -mp_toradix (mp_int * a, char *str, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - char *_s = str; - - if (radix < 2 || radix > 64) { - return MP_VAL; - } - - /* quick out if its zero */ - if (mp_iszero(a) == 1) { - *str++ = '0'; - *str = '\0'; - return MP_OKAY; - } - - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return res; - } - - if (t.sign == MP_NEG) { - ++_s; - *str++ = '-'; - t.sign = MP_ZPOS; - } - - digs = 0; - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return res; - } - *str++ = s_rmap[d]; - ++digs; - } - bn_reverse ((unsigned char *)_s, digs); - *str++ = '\0'; - mp_clear (&t); - return MP_OKAY; -} - -/* returns size of ASCII reprensentation */ -int -mp_radix_size (mp_int * a, int radix) -{ - int res, digs; - mp_int t; - mp_digit d; - - /* special case for binary */ - if (radix == 2) { - return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; - } - - if (radix < 2 || radix > 64) { - return 0; - } - - if ((res = mp_init_copy (&t, a)) != MP_OKAY) { - return 0; - } - - digs = 0; - if (t.sign == MP_NEG) { - ++digs; - t.sign = MP_ZPOS; - } - - while (mp_iszero (&t) == 0) { - if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { - mp_clear (&t); - return 0; - } - ++digs; - } - mp_clear (&t); - return digs + 1; -} - -/* read a bigint from a file stream in ASCII */ -int mp_fread(mp_int *a, int radix, FILE *stream) -{ - int err, ch, neg, y; - - /* clear a */ - mp_zero(a); - - /* if first digit is - then set negative */ - ch = fgetc(stream); - if (ch == '-') { - neg = MP_NEG; - ch = fgetc(stream); - } else { - neg = MP_ZPOS; - } - - for (;;) { - /* find y in the radix map */ - for (y = 0; y < radix; y++) { - if (s_rmap[y] == ch) { - break; - } - } - if (y == radix) { - break; - } - - /* shift up and add */ - if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { - return err; - } - if ((err = mp_add_d(a, y, a)) != MP_OKAY) { - return err; - } - - ch = fgetc(stream); - } - if (mp_cmp_d(a, 0) != MP_EQ) { - a->sign = neg; - } - - return MP_OKAY; -} - -int mp_fwrite(mp_int *a, int radix, FILE *stream) -{ - char *buf; - int err, len, x; - - len = mp_radix_size(a, radix); - if (len == 0) { - return MP_VAL; - } - - buf = malloc(len); - if (buf == NULL) { - return MP_MEM; - } - - if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { - free(buf); - return err; - } - - for (x = 0; x < len; x++) { - if (fputc(buf[x], stream) == EOF) { - free(buf); - return MP_VAL; - } - } - - free(buf); - return MP_OKAY; -} - - -/* End: bn_radix.c */ - /* Start: bn_reverse.c */ /* LibTomMath, multiple-precision integer library -- Tom St Denis * @@ -6483,222 +6866,236 @@ s_mp_add (mp_int * a, mp_int * b, mp_int * c) /* End: bn_s_mp_add.c */ /* Start: bn_s_mp_exptmod.c */ -/* LibTomMath, multiple-precision integer library -- Tom St Denis - * - * LibTomMath is library that provides for multiple-precision - * integer arithmetic as well as number theoretic functionality. - * - * The library is designed directly after the MPI library by - * Michael Fromberger but has been written from scratch with - * additional optimizations in place. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org - */ -#include - -int -s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -{ - mp_int M[256], res, mu; - mp_digit buf; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; - - /* find window size */ - x = mp_count_bits (X); - if (x <= 7) { - winsize = 2; - } else if (x <= 36) { - winsize = 3; - } else if (x <= 140) { - winsize = 4; - } else if (x <= 450) { - winsize = 5; - } else if (x <= 1303) { - winsize = 6; - } else if (x <= 3529) { - winsize = 7; - } else { - winsize = 8; - } - -#ifdef MP_LOW_MEM - if (winsize > 5) { - winsize = 5; - } -#endif - - /* init M array */ - for (x = 0; x < (1 << winsize); x++) { - if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) { - for (y = 0; y < x; y++) { - mp_clear (&M[y]); - } - return err; - } - } - - /* create mu, used for Barrett reduction */ - if ((err = mp_init (&mu)) != MP_OKAY) { - goto __M; - } - if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { - goto __MU; - } - - /* create M table - * - * The M table contains powers of the base, - * e.g. M[x] = G**x mod P - * - * The first half of the table is not - * computed though accept for M[0] and M[1] - */ - if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { - goto __MU; - } - - /* compute the value at M[1<<(winsize-1)] by squaring - * M[1] (winsize-1) times - */ - if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - - for (x = 0; x < (winsize - 1); x++) { - if ((err = mp_sqr (&M[1 << (winsize - 1)], - &M[1 << (winsize - 1)])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* create upper table */ - for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { - if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { - goto __MU; - } - } - - /* setup result */ - if ((err = mp_init (&res)) != MP_OKAY) { - goto __MU; - } - mp_set (&res, 1); - - /* set initial mode and bit cnt */ - mode = 0; - bitcnt = 1; - buf = 0; - digidx = X->used - 1; - bitcpy = 0; - bitbuf = 0; - - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = X->dp[digidx--]; - bitcnt = (int) DIGIT_BIT; - } - - /* grab the next msb from the exponent */ - y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; - buf <<= (mp_digit)1; - - /* if the bit is zero and mode == 0 then we ignore it - * These represent the leading zero bits before the first 1 bit - * in the exponent. Technically this opt is not required but it - * does lower the # of trivial squaring/reductions used - */ - if (mode == 0 && y == 0) - continue; - - /* if the bit is zero and mode == 1 then we square */ - if (mode == 1 && y == 0) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - continue; - } - - /* else we add it to the window */ - bitbuf |= (y << (winsize - ++bitcpy)); - mode = 2; - - if (bitcpy == winsize) { - /* ok window is filled so square as required and multiply */ - /* square first */ - for (x = 0; x < winsize; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - - /* then multiply */ - if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __MU; - } - - /* empty window and reset */ - bitcpy = 0; - bitbuf = 0; - mode = 1; - } - } - - /* if bits remain then square/multiply */ - if (mode == 2 && bitcpy > 0) { - /* square then multiply if the bit is set */ - for (x = 0; x < bitcpy; x++) { - if ((err = mp_sqr (&res, &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << winsize)) != 0) { - /* then multiply */ - if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { - goto __RES; - } - if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { - goto __RES; - } - } - } - } - - mp_exch (&res, Y); - err = MP_OKAY; -__RES:mp_clear (&res); -__MU:mp_clear (&mu); -__M: - for (x = 0; x < (1 << winsize); x++) { - mp_clear (&M[x]); - } - return err; -} +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is library that provides for multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library is designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int +s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + 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 base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) + continue; + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __MU; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__MU:mp_clear (&mu); +__M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} /* End: bn_s_mp_exptmod.c */ @@ -6767,7 +7164,7 @@ s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) for (iy = 0; iy < pb; iy++) { /* compute the column as a mp_word */ r = ((mp_word) *tmpt) + - ((mp_word) tmpx) * ((mp_word) * tmpy++) + + MULT(tmpx, *tmpy++) + ((mp_word) u); /* the new column is the lower part of the result */ @@ -6849,7 +7246,7 @@ s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) 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); + r = ((mp_word) * tmpt) + MULT(tmpx, *tmpy++) + ((mp_word) u); /* get the lower part */ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); @@ -6903,7 +7300,7 @@ s_mp_sqr (mp_int * a, mp_int * b) /* first calculate the digit at 2*ix */ /* calculate double precision result */ r = ((mp_word) t.dp[2*ix]) + - ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); + MULT(a->dp[ix], a->dp[ix]); /* store lower part in result */ t.dp[2*ix] = (mp_digit) (r & ((mp_word) MP_MASK)); @@ -6919,7 +7316,7 @@ s_mp_sqr (mp_int * a, mp_int * b) for (iy = ix + 1; iy < pa; iy++) { /* first calculate the product */ - r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); + r = MULT(tmpx, a->dp[iy]); /* now calculate the double precision result, note we use * addition instead of *2 since it's easier to optimize diff --git a/mycrypt.h b/mycrypt.h index b673d96..d99cb17 100644 --- a/mycrypt.h +++ b/mycrypt.h @@ -16,8 +16,8 @@ extern "C" { #endif /* version */ -#define CRYPT 0x0086 -#define SCRYPT "0.86" +#define CRYPT 0x0088 +#define SCRYPT "0.88" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 128 diff --git a/mycrypt_cipher.h b/mycrypt_cipher.h index f7a3419..3071bde 100644 --- a/mycrypt_cipher.h +++ b/mycrypt_cipher.h @@ -5,21 +5,21 @@ */ #ifdef BLOWFISH struct blowfish_key { - unsigned long S[4][256]; - unsigned long K[18]; + ulong32 S[4][256]; + ulong32 K[18]; }; #endif #ifdef RC5 struct rc5_key { int rounds; - unsigned long K[50]; + ulong32 K[50]; }; #endif #ifdef RC6 struct rc6_key { - unsigned long K[44]; + ulong32 K[44]; }; #endif @@ -32,7 +32,7 @@ struct saferp_key { #ifdef RIJNDAEL struct rijndael_key { - unsigned long eK[64], dK[64]; + ulong32 eK[64], dK[64]; int Nr; }; #endif @@ -46,11 +46,11 @@ struct xtea_key { #ifdef TWOFISH #ifndef TWOFISH_SMALL struct twofish_key { - unsigned long S[4][256], K[40]; + ulong32 S[4][256], K[40]; }; #else struct twofish_key { - unsigned long K[40]; + ulong32 K[40]; unsigned char S[32], start; }; #endif @@ -75,23 +75,23 @@ struct rc2_key { unsigned xkey[64]; }; #ifdef DES struct des_key { - unsigned long ek[32], dk[32]; + ulong32 ek[32], dk[32]; }; struct des3_key { - unsigned long ek[3][32], dk[3][32]; + ulong32 ek[3][32], dk[3][32]; }; #endif #ifdef CAST5 struct cast5_key { - unsigned long K[32], keylen; + ulong32 K[32], keylen; }; #endif #ifdef NOEKEON struct noekeon_key { - unsigned long K[4], dK[4]; + ulong32 K[4], dK[4]; }; #endif diff --git a/mycrypt_custom.h b/mycrypt_custom.h index 2429329..b91bde3 100644 --- a/mycrypt_custom.h +++ b/mycrypt_custom.h @@ -15,9 +15,8 @@ #define XFREE free #define XCLOCK clock #define XCLOCKS_PER_SEC CLOCKS_PER_SEC -#define TWOFISH_TABLES -//#define SMALL_CODE #define LTC_TEST +#define SMALL_CODE #define BLOWFISH #define RC2 #define RC5 @@ -25,6 +24,7 @@ #define SAFERP #define SAFER #define RIJNDAEL +#define SERPENT #define XTEA #define TWOFISH #define DES diff --git a/mycrypt_macros.h b/mycrypt_macros.h index 43c90c7..ba8a9e8 100644 --- a/mycrypt_macros.h +++ b/mycrypt_macros.h @@ -7,6 +7,11 @@ typedef unsigned long long ulong64; #endif +/* this is the "32-bit at least" data type + * Re-define it to suit your platform but it must be at least 32-bits + */ +typedef unsigned long ulong32; + extern char *crypt_error; /* ---- HELPER MACROS ---- */ diff --git a/noekeon.c b/noekeon.c index 8d6f0c8..ac1cafb 100644 --- a/noekeon.c +++ b/noekeon.c @@ -15,7 +15,7 @@ const struct _cipher_descriptor noekeon_desc = &noekeon_keysize }; -static const unsigned long RC[] = { +static const ulong32 RC[] = { 0x00000080UL, 0x0000001bUL, 0x00000036UL, 0x0000006cUL, 0x000000d8UL, 0x000000abUL, 0x0000004dUL, 0x0000009aUL, 0x0000002fUL, 0x0000005eUL, 0x000000bcUL, 0x00000063UL, @@ -54,7 +54,7 @@ static const unsigned long RC[] = { int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) { - unsigned long temp; + ulong32 temp; _ARGCHK(key != NULL); _ARGCHK(skey != NULL); @@ -88,7 +88,7 @@ static void _noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, sym void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) #endif { - unsigned long a,b,c,d,temp; + ulong32 a,b,c,d,temp; int r; _ARGCHK(key != NULL); @@ -105,11 +105,9 @@ void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k GAMMA(a,b,c,d); \ PI2(a,b,c,d); - for (r = 0; r < 16; r += 4) { + for (r = 0; r < 16; r += 2) { ROUND(0); ROUND(1); - ROUND(2); - ROUND(3); } #undef ROUND @@ -125,7 +123,7 @@ void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { _noekeon_ecb_encrypt(pt, ct, key); - burn_stack(sizeof(unsigned long) * 5 + sizeof(int)); + burn_stack(sizeof(ulong32) * 5 + sizeof(int)); } #endif @@ -135,7 +133,7 @@ static void _noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, sym void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) #endif { - unsigned long a,b,c,d, temp; + ulong32 a,b,c,d, temp; int r; _ARGCHK(key != NULL); @@ -170,7 +168,7 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { _noekeon_ecb_decrypt(ct, pt, key); - burn_stack(sizeof(unsigned long) * 5 + sizeof(int)); + burn_stack(sizeof(ulong32) * 5 + sizeof(int)); } #endif diff --git a/rc5.c b/rc5.c index 51ebba5..0572f18 100644 --- a/rc5.c +++ b/rc5.c @@ -14,16 +14,27 @@ const struct _cipher_descriptor rc5_desc = &rc5_keysize }; +static const ulong32 stab[50] = { +0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL, +0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL, +0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL, +0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL, +0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL, +0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL, 0xe96a3d2fUL, 0x87a1b6e8UL, 0x25d930a1UL, 0xc410aa5aUL, +0x62482413UL, 0x007f9dccUL +}; + #ifdef CLEAN_STACK static int _rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) #else int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) #endif { - unsigned long L[64], S[50], A, B, i, j, v, s, t, l; + ulong32 L[64], *S, A, B, i, j, v, s, t, l; _ARGCHK(skey != NULL); _ARGCHK(key != NULL); + /* test parameters */ if (num_rounds == 0) { @@ -38,10 +49,13 @@ int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke if (keylen < 8 || keylen > 128) { return CRYPT_INVALID_KEYSIZE; } + + skey->rc5.rounds = num_rounds; + S = skey->rc5.K; /* copy the key into the L array */ - for (A = i = j = 0; i < (unsigned long)keylen; ) { - A = (A << 8) | ((unsigned long)(key[i++] & 255)); + for (A = i = j = 0; i < (ulong32)keylen; ) { + A = (A << 8) | ((ulong32)(key[i++] & 255)); if ((i & 3) == 0) { L[j++] = BSWAP(A); A = 0; @@ -49,14 +63,13 @@ int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke } if ((keylen & 3) != 0) { - A <<= (unsigned long)((8 * (4 - (keylen&3)))); + A <<= (ulong32)((8 * (4 - (keylen&3)))); L[j++] = BSWAP(A); } /* setup the S array */ - t = (unsigned long)(2 * (num_rounds + 1)); - S[0] = 0xB7E15163UL; - for (i = 1; i < t; i++) S[i] = S[i - 1] + 0x9E3779B9UL; + t = (ulong32)(2 * (num_rounds + 1)); + memcpy(S, stab, t * sizeof(stab[0])); /* mix buffer */ s = 3 * MAX(t, j); @@ -64,15 +77,9 @@ int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke for (A = B = i = j = v = 0; v < s; v++) { A = S[i] = ROL(S[i] + A + B, 3); B = L[j] = ROL(L[j] + A + B, (A+B)); - i = (i + 1) % t; - j = (j + 1) % l; + if (++i == t) { i = 0; } + if (++j == l) { j = 0; } } - - /* copy to key */ - for (i = 0; i < t; i++) { - skey->rc5.K[i] = S[i]; - } - skey->rc5.rounds = num_rounds; return CRYPT_OK; } @@ -81,7 +88,7 @@ int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke { int x; x = _rc5_setup(key, keylen, num_rounds, skey); - burn_stack(sizeof(unsigned long) * 122 + sizeof(int)); + burn_stack(sizeof(ulong32) * 122 + sizeof(int)); return x; } #endif @@ -92,7 +99,7 @@ static void _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetr void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) #endif { - unsigned long A, B, *K; + ulong32 A, B, *K; int r; _ARGCHK(key != NULL); _ARGCHK(pt != NULL); @@ -127,7 +134,7 @@ void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key * void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { _rc5_ecb_encrypt(pt, ct, key); - burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); + burn_stack(sizeof(ulong32) * 2 + sizeof(int)); } #endif @@ -137,7 +144,7 @@ static void _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetr void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) #endif { - unsigned long A, B, *K; + ulong32 A, B, *K; int r; _ARGCHK(key != NULL); _ARGCHK(pt != NULL); @@ -173,7 +180,7 @@ void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key * void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { _rc5_ecb_decrypt(ct, pt, key); - burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); + burn_stack(sizeof(ulong32) * 2 + sizeof(int)); } #endif diff --git a/rc6.c b/rc6.c index 720bdf3..c39a439 100644 --- a/rc6.c +++ b/rc6.c @@ -14,13 +14,21 @@ const struct _cipher_descriptor rc6_desc = &rc6_keysize }; +static const ulong32 stab[44] = { +0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL, +0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL, +0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL, +0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL, +0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL, +0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL }; + #ifdef CLEAN_STACK static int _rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) #else int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) #endif { - unsigned long L[64], S[50], A, B, i, j, v, s, t, l; + ulong32 L[64], S[50], A, B, i, j, v, s, l; _ARGCHK(key != NULL); _ARGCHK(skey != NULL); @@ -36,8 +44,8 @@ int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke } /* copy the key into the L array */ - for (A = i = j = 0; i < (unsigned long)keylen; ) { - A = (A << 8) | ((unsigned long)(key[i++] & 255)); + for (A = i = j = 0; i < (ulong32)keylen; ) { + A = (A << 8) | ((ulong32)(key[i++] & 255)); if (!(i & 3)) { L[j++] = BSWAP(A); A = 0; @@ -51,23 +59,20 @@ int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke } /* setup the S array */ - t = 44; /* fixed at 20 rounds */ - S[0] = 0xB7E15163UL; - for (i = 1; i < t; i++) - S[i] = S[i - 1] + 0x9E3779B9UL; + memcpy(S, stab, 44 * sizeof(stab[0])); /* mix buffer */ - s = 3 * MAX(t, j); + s = 3 * MAX(44, j); l = j; for (A = B = i = j = v = 0; v < s; v++) { A = S[i] = ROL(S[i] + A + B, 3); B = L[j] = ROL(L[j] + A + B, (A+B)); - i = (i + 1) % t; - j = (j + 1) % l; + if (++i == 44) { i = 0; } + if (++j == l) { j = 0; } } /* copy to key */ - for (i = 0; i < t; i++) { + for (i = 0; i < 44; i++) { skey->rc6.K[i] = S[i]; } return CRYPT_OK; @@ -78,7 +83,7 @@ int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_ke { int x; x = _rc6_setup(key, keylen, num_rounds, skey); - burn_stack(sizeof(unsigned long) * 122); + burn_stack(sizeof(ulong32) * 122); return x; } #endif @@ -89,7 +94,7 @@ static void _rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetr void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) #endif { - unsigned long a,b,c,d,t,u, *K; + ulong32 a,b,c,d,t,u, *K; int r; _ARGCHK(key != NULL); @@ -125,7 +130,7 @@ void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key * void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { _rc6_ecb_encrypt(pt, ct, key); - burn_stack(sizeof(unsigned long) * 6 + sizeof(int)); + burn_stack(sizeof(ulong32) * 6 + sizeof(int)); } #endif @@ -135,7 +140,7 @@ static void _rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetr void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) #endif { - unsigned long a,b,c,d,t,u, *K; + ulong32 a,b,c,d,t,u, *K; int r; _ARGCHK(key != NULL); @@ -172,7 +177,7 @@ void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key * void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { _rc6_ecb_decrypt(ct, pt, key); - burn_stack(sizeof(unsigned long) * 6 + sizeof(int)); + burn_stack(sizeof(ulong32) * 6 + sizeof(int)); } #endif diff --git a/safer+.c b/safer+.c index d8b1af3..c70a3a2 100644 --- a/safer+.c +++ b/safer+.c @@ -190,7 +190,7 @@ static const unsigned char safer_bias[33][16] = { int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) { - unsigned x, y; + unsigned x, y, z; unsigned char t[33]; static const int rounds[3] = { 8, 12, 16 }; @@ -231,8 +231,10 @@ int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric } /* select and add */ + z = x; for (y = 0; y < 16; y++) { - skey->saferp.K[x][y] = (t[(x+y)%17] + safer_bias[x-1][y]) & 255; + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 17) { z = 0; } } } skey->saferp.rounds = 8; @@ -256,8 +258,10 @@ int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric } /* select and add */ + z = x; for (y = 0; y < 16; y++) { - skey->saferp.K[x][y] = (t[(x+y)%25] + safer_bias[x-1][y]) & 255; + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 25) { z = 0; } } } skey->saferp.rounds = 12; @@ -281,8 +285,10 @@ int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric } /* select and add */ + z = x; for (y = 0; y < 16; y++) { - skey->saferp.K[x][y] = (t[(x+y)%33] + safer_bias[x-1][y]) & 255; + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 33) { z = 0; } } } skey->saferp.rounds = 16; diff --git a/safer.c b/safer.c index 87c7db9..2eb5f2a 100644 --- a/safer.c +++ b/safer.c @@ -91,7 +91,7 @@ static void Safer_Expand_Userkey(const unsigned char *userkey_1, int strengthened, safer_key_t key) #endif -{ unsigned int i, j; +{ unsigned int i, j, k; unsigned char ka[SAFER_BLOCK_LEN + 1]; unsigned char kb[SAFER_BLOCK_LEN + 1]; @@ -100,6 +100,7 @@ static void Safer_Expand_Userkey(const unsigned char *userkey_1, *key++ = (unsigned char)nof_rounds; ka[SAFER_BLOCK_LEN] = (unsigned char)0; kb[SAFER_BLOCK_LEN] = (unsigned char)0; + k = 0; for (j = 0; j < SAFER_BLOCK_LEN; j++) { ka[j] = ROL8(userkey_1[j], 5); ka[SAFER_BLOCK_LEN] ^= ka[j]; @@ -111,18 +112,28 @@ static void Safer_Expand_Userkey(const unsigned char *userkey_1, ka[j] = ROL8(ka[j], 6); kb[j] = ROL8(kb[j], 6); } + if (strengthened) { + k = 2 * i - 1; + while (k >= (SAFER_BLOCK_LEN + 1)) { k -= SAFER_BLOCK_LEN + 1; } + } for (j = 0; j < SAFER_BLOCK_LEN; j++) { if (strengthened) { - *key++ = (ka[(j + 2 * i - 1) % (SAFER_BLOCK_LEN + 1)] + *key++ = (ka[k] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF; + if (++k == (SAFER_BLOCK_LEN + 1)) { k = 0; } } else { *key++ = (ka[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF; } } + if (strengthened) { + k = 2 * i; + while (k >= (SAFER_BLOCK_LEN + 1)) { k -= SAFER_BLOCK_LEN + 1; } + } for (j = 0; j < SAFER_BLOCK_LEN; j++) { if (strengthened) { - *key++ = (kb[(j + 2 * i) % (SAFER_BLOCK_LEN + 1)] + *key++ = (kb[k] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 0xFF; + if (++k == (SAFER_BLOCK_LEN + 1)) { k = 0; } } else { *key++ = (kb[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 0xFF; } diff --git a/sha1.c b/sha1.c index 58975ca..2489f34 100644 --- a/sha1.c +++ b/sha1.c @@ -25,7 +25,7 @@ static void _sha1_compress(hash_state *md) static void sha1_compress(hash_state *md) #endif { - unsigned long a,b,c,d,e,W[80],i,j; + unsigned long a,b,c,d,e,W[80],i; _ARGCHK(md != NULL); @@ -43,52 +43,57 @@ static void sha1_compress(hash_state *md) /* expand it */ for (i = 16; i < 80; i++) { - j = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; - W[i] = ROL(j, 1); + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); } /* compress */ /* round one */ - for (i = 0; i < 20; i++) { - j = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); - e = d; - d = c; - c = ROL(b, 30); - b = a; - a = j; + #define FF0(a,b,c,d,e,i) e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30); + #define FF1(a,b,c,d,e,i) e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30); + #define FF2(a,b,c,d,e,i) e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30); + #define FF3(a,b,c,d,e,i) e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30); + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); + FF0(e,a,b,c,d,i++); + FF0(d,e,a,b,c,i++); + FF0(c,d,e,a,b,i++); + FF0(b,c,d,e,a,i++); } /* round two */ - for (i = 20; i < 40; i++) { - j = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); - e = d; - d = c; - c = ROL(b, 30); - b = a; - a = j; + for (i = 20; i < 40; ) { + FF1(a,b,c,d,e,i++); + FF1(e,a,b,c,d,i++); + FF1(d,e,a,b,c,i++); + FF1(c,d,e,a,b,i++); + FF1(b,c,d,e,a,i++); } /* round three */ - for (i = 40; i < 60; i++) { - j = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); - e = d; - d = c; - c = ROL(b, 30); - b = a; - a = j; + for (i = 40; i < 60; ) { + FF2(a,b,c,d,e,i++); + FF2(e,a,b,c,d,i++); + FF2(d,e,a,b,c,i++); + FF2(c,d,e,a,b,i++); + FF2(b,c,d,e,a,i++); } /* round four */ - for (i = 60; i < 80; i++) { - j = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); - e = d; - d = c; - c = ROL(b, 30); - b = a; - a = j; + for (i = 60; i < 80; ) { + FF3(a,b,c,d,e,i++); + FF3(e,a,b,c,d,i++); + FF3(d,e,a,b,c,i++); + FF3(c,d,e,a,b,i++); + FF3(b,c,d,e,a,i++); } + #undef FF0 + #undef FF1 + #undef FF2 + #undef FF3 + /* store */ md->sha1.state[0] = md->sha1.state[0] + a; md->sha1.state[1] = md->sha1.state[1] + b; diff --git a/sha256.c b/sha256.c index f14e72f..2402b0c 100644 --- a/sha256.c +++ b/sha256.c @@ -54,8 +54,9 @@ static void sha256_compress(hash_state * md) _ARGCHK(md != NULL); /* copy state into S */ - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { S[i] = md->sha256.state[i]; + } /* copy the state into 512-bits into W[0..15] */ for (i = 0; i < 16; i++) { @@ -68,6 +69,7 @@ static void sha256_compress(hash_state * md) } /* Compress */ +#ifdef SMALL_CODE for (i = 0; i < 64; i++) { t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); @@ -80,6 +82,81 @@ static void sha256_compress(hash_state * md) S[1] = S[0]; S[0] = t0 + t1; } +#else +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + +#endif /* feedback */ for (i = 0; i < 8; i++) { diff --git a/sha512.c b/sha512.c index c52e393..b63efdb 100644 --- a/sha512.c +++ b/sha512.c @@ -95,6 +95,7 @@ static void sha512_compress(hash_state * md) } /* Compress */ +#ifdef SMALL_CODE for (i = 0; i < 80; i++) { t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); @@ -107,6 +108,25 @@ static void sha512_compress(hash_state * md) S[1] = S[0]; S[0] = t0 + t1; } +#else +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } +#endif + /* feedback */ for (i = 0; i < 8; i++) { diff --git a/tommath.h b/tommath.h index 8e43f6c..7c3158f 100644 --- a/tommath.h +++ b/tommath.h @@ -85,6 +85,7 @@ extern "C" { #define DIGIT_BIT 31 #else #define DIGIT_BIT 28 + #define MP_28BIT #endif #endif @@ -120,11 +121,21 @@ extern int KARATSUBA_MUL_CUTOFF, TOOM_SQR_CUTOFF; /* various build options */ -#define MP_PREC 64 /* default digits of precision (must be power of two) */ +#define MP_PREC 64 /* default digits of precision (must be power of two) */ /* define this to use lower memory usage routines (exptmods mostly) */ /* #define MP_LOW_MEM */ +/* have no cpu based mult? */ +/* #define SLOW_MULT */ + +#ifdef SLOW_MULT + #define MULT(x, y) s_mp_mult((x), (y)) + mp_word s_mp_mult(mp_digit, mp_digit); +#else + #define MULT(x, y) (((mp_word)(x)) * ((mp_word)(y))) +#endif + /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ #define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) @@ -166,7 +177,7 @@ int mp_init_size(mp_int *a, int size); /* ---> 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_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 */ @@ -213,6 +224,9 @@ int mp_mod_2d(mp_int *a, int b, mp_int *c); /* computes a = 2**b */ int mp_2expt(mp_int *a, int b); +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a); + /* makes a pseudo-random int of a given size */ int mp_rand(mp_int *a, int digits); @@ -451,6 +465,8 @@ int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); void bn_reverse(unsigned char *s, int len); +extern const char *mp_s_rmap; + #ifdef __cplusplus } #endif diff --git a/twofish.c b/twofish.c index eb2ea93..2e1e937 100644 --- a/twofish.c +++ b/twofish.c @@ -101,7 +101,7 @@ static const unsigned char SBOX[2][256] = { 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91} }; -static const unsigned long mds_tab[4][256] = { +static const ulong32 mds_tab[4][256] = { { 0x00000000UL, 0xefef5b01UL, 0xb7b7b602UL, 0x5858ed03UL, 0x07070504UL, 0xe8e85e05UL, 0xb0b0b306UL, 0x5f5fe807UL, 0x0e0e0a08UL, 0xe1e15109UL, 0xb9b9bc0aUL, 0x5656e70bUL, 0x09090f0cUL, 0xe6e6540dUL, 0xbebeb90eUL, 0x5151e20fUL, @@ -239,7 +239,7 @@ static const unsigned long mds_tab[4][256] = { 0xc6baf8c6UL, 0x9d55f99dUL, 0x700dfa70UL, 0x2be2fb2bUL, 0xc3bdfcc3UL, 0x9852fd98UL, 0x750afe75UL, 0x2ee5ff2eUL }}; -#define sbox(i, x) ((unsigned long)SBOX[i][(x)&255]) +#define sbox(i, x) ((ulong32)SBOX[i][(x)&255]) #else @@ -261,9 +261,9 @@ static const unsigned char qbox[2][4][16] = { /* computes S_i[x] */ #ifdef CLEAN_STACK -static unsigned long _sbox(int i, unsigned long x) +static ulong32 _sbox(int i, ulong32 x) #else -static unsigned long sbox(int i, unsigned long x) +static ulong32 sbox(int i, ulong32 x) #endif { unsigned char a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,y; @@ -296,13 +296,13 @@ static unsigned long sbox(int i, unsigned long x) y = (b4 << 4) + a4; /* return result */ - return (unsigned long)y; + return (ulong32)y; } #ifdef CLEAN_STACK -static unsigned long sbox(int i, unsigned long x) +static ulong32 sbox(int i, ulong32 x) { - unsigned long y; + ulong32 y; y = _sbox(i, x); burn_stack(sizeof(unsigned char) * 11); return y; @@ -312,22 +312,22 @@ static unsigned long sbox(int i, unsigned long x) #endif /* TWOFISH_TABLES */ /* computes ab mod p */ -static unsigned long gf_mult(unsigned long a, unsigned long b, unsigned long p) +static ulong32 gf_mult(ulong32 a, ulong32 b, ulong32 p) { - unsigned long result = 0, B[2], P[2]; + ulong32 result = 0, B[2], P[2]; P[1] = p; B[1] = b; P[0] = B[0] = 0; /* unrolled branchless GF multiplier */ - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; - result ^= B[a&1]; a >>= 1; B[1] <<= 1; B[1] ^= P[B[1]>>8]; + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); result ^= B[a&1]; return result; @@ -335,9 +335,9 @@ static unsigned long gf_mult(unsigned long a, unsigned long b, unsigned long p) /* computes [y0 y1 y2 y3] = MDS . [x0] */ #ifndef TWOFISH_TABLES -static unsigned long mds_column_mult(unsigned char in, int col) +static ulong32 mds_column_mult(unsigned char in, int col) { - unsigned long x01, x5B, xEF; + ulong32 x01, x5B, xEF; x01 = in; x5B = gf_mult(in, 0x5B, MDS_POLY); @@ -379,7 +379,7 @@ static unsigned long mds_column_mult(unsigned char in, int col) static void mds_mult(const unsigned char *in, unsigned char *out) { int x; - unsigned long tmp; + ulong32 tmp; for (tmp = x = 0; x < 4; x++) { tmp ^= mds_column_mult(in[x], x); } @@ -407,20 +407,20 @@ static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M switch (k) { case 4: - y[0] = (unsigned char)(sbox(1, (unsigned long)y[0]) ^ M[4 * (6 + offset) + 0]); - y[1] = (unsigned char)(sbox(0, (unsigned long)y[1]) ^ M[4 * (6 + offset) + 1]); - y[2] = (unsigned char)(sbox(0, (unsigned long)y[2]) ^ M[4 * (6 + offset) + 2]); - y[3] = (unsigned char)(sbox(1, (unsigned long)y[3]) ^ M[4 * (6 + offset) + 3]); + y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (6 + offset) + 0]); + y[1] = (unsigned char)(sbox(0, (ulong32)y[1]) ^ M[4 * (6 + offset) + 1]); + y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (6 + offset) + 2]); + y[3] = (unsigned char)(sbox(1, (ulong32)y[3]) ^ M[4 * (6 + offset) + 3]); case 3: - y[0] = (unsigned char)(sbox(1, (unsigned long)y[0]) ^ M[4 * (4 + offset) + 0]); - y[1] = (unsigned char)(sbox(1, (unsigned long)y[1]) ^ M[4 * (4 + offset) + 1]); - y[2] = (unsigned char)(sbox(0, (unsigned long)y[2]) ^ M[4 * (4 + offset) + 2]); - y[3] = (unsigned char)(sbox(0, (unsigned long)y[3]) ^ M[4 * (4 + offset) + 3]); + y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (4 + offset) + 0]); + y[1] = (unsigned char)(sbox(1, (ulong32)y[1]) ^ M[4 * (4 + offset) + 1]); + y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (4 + offset) + 2]); + y[3] = (unsigned char)(sbox(0, (ulong32)y[3]) ^ M[4 * (4 + offset) + 3]); case 2: - y[0] = (unsigned char)(sbox(1, sbox(0, sbox(0, (unsigned long)y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0])); - y[1] = (unsigned char)(sbox(0, sbox(0, sbox(1, (unsigned long)y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1])); - y[2] = (unsigned char)(sbox(1, sbox(1, sbox(0, (unsigned long)y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2])); - y[3] = (unsigned char)(sbox(0, sbox(1, sbox(1, (unsigned long)y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3])); + y[0] = (unsigned char)(sbox(1, sbox(0, sbox(0, (ulong32)y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0])); + y[1] = (unsigned char)(sbox(0, sbox(0, sbox(1, (ulong32)y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1])); + y[2] = (unsigned char)(sbox(1, sbox(1, sbox(0, (ulong32)y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2])); + y[3] = (unsigned char)(sbox(0, sbox(1, sbox(1, (ulong32)y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3])); } mds_mult(y, out); } @@ -442,13 +442,13 @@ static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M #else #ifdef CLEAN_STACK -static unsigned long _g_func(unsigned long x, symmetric_key *key) +static ulong32 _g_func(ulong32 x, symmetric_key *key) #else -static unsigned long g_func(unsigned long x, symmetric_key *key) +static ulong32 g_func(ulong32 x, symmetric_key *key) #endif { unsigned char g, i, y, z; - unsigned long res; + ulong32 res; res = 0; for (y = 0; y < 4; y++) { @@ -475,11 +475,11 @@ static unsigned long g_func(unsigned long x, symmetric_key *key) #define g1_func(x, key) g_func(ROL(x, 8), key) #ifdef CLEAN_STACK -static unsigned long g_func(unsigned long x, symmetric_key *key) +static ulong32 g_func(ulong32 x, symmetric_key *key) { - unsigned long y; + ulong32 y; y = _g_func(x, key); - burn_stack(sizeof(unsigned char) * 4 + sizeof(unsigned long)); + burn_stack(sizeof(unsigned char) * 4 + sizeof(ulong32)); return y; } #endif /* CLEAN_STACK */ @@ -493,13 +493,13 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri #endif { #ifndef TWOFISH_SMALL - unsigned long g; + ulong32 g; int z, i; unsigned char S[4*4]; #endif int k, x, y, start; unsigned char tmp[4], tmp2[4], M[8*4]; - unsigned long A, B; + ulong32 A, B; _ARGCHK(key != NULL); _ARGCHK(skey != NULL); @@ -591,7 +591,7 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri { int x; x = _twofish_setup(key, keylen, num_rounds, skey); - burn_stack(sizeof(int) * 7 + sizeof(unsigned char) * 56 + sizeof(unsigned long) * 2); + burn_stack(sizeof(int) * 7 + sizeof(unsigned char) * 56 + sizeof(ulong32) * 2); return x; } #endif @@ -602,10 +602,10 @@ static void _twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, sym void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) #endif { - unsigned long a,b,c,d,ta,tb,tc,td,t1,t2, *k; + ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k; int r; #if !defined(TWOFISH_SMALL) && !defined(__GNUC__) - unsigned long *S1, *S2, *S3, *S4; + ulong32 *S1, *S2, *S3, *S4; #endif _ARGCHK(pt != NULL); @@ -656,7 +656,7 @@ void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) { _twofish_ecb_encrypt(pt, ct, key); - burn_stack(sizeof(unsigned long) * 10 + sizeof(int)); + burn_stack(sizeof(ulong32) * 10 + sizeof(int)); } #endif @@ -666,10 +666,10 @@ static void _twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, sym void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) #endif { - unsigned long a,b,c,d,ta,tb,tc,td,t1,t2, *k; + ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k; int r; #if !defined(TWOFISH_SMALL) && !defined(__GNUC__) - unsigned long *S1, *S2, *S3, *S4; + ulong32 *S1, *S2, *S3, *S4; #endif _ARGCHK(pt != NULL); @@ -723,7 +723,7 @@ void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) { _twofish_ecb_decrypt(ct, pt, key); - burn_stack(sizeof(unsigned long) * 10 + sizeof(int)); + burn_stack(sizeof(ulong32) * 10 + sizeof(int)); } #endif