Browse Source

added libtomcrypt-0.75

Tom St Denis 22 years ago
commit
a6a5fc648b
77 changed files with 28956 additions and 0 deletions
  1. 409 0
      aes.c
  2. 851 0
      aes_tab.c
  3. 55 0
      ampi.c
  4. 48 0
      authors
  5. 111 0
      base64.c
  6. 193 0
      bits.c
  7. 691 0
      blowfish.c
  8. 622 0
      cast5.c
  9. 101 0
      cbc.c
  10. 86 0
      cfb.c
  11. 622 0
      changes
  12. 507 0
      crypt.c
  13. BIN
      crypt.pdf
  14. 2412 0
      crypt.tex
  15. 77 0
      ctr.c
  16. 202 0
      demos/encrypt.c
  17. 77 0
      demos/hashsum.c
  18. 11 0
      demos/small.c
  19. 1586 0
      demos/test.c
  20. 7 0
      demos/timer.c
  21. 51 0
      demos/timer.h
  22. 728 0
      des.c
  23. 489 0
      dh.c
  24. 774 0
      dh_sys.c
  25. 49 0
      ecb.c
  26. 827 0
      ecc.c
  27. 862 0
      ecc_sys.c
  28. 295 0
      gf.c
  29. 93 0
      hash.c
  30. 478 0
      hmac.c
  31. 840 0
      keyring.c
  32. 262 0
      makefile
  33. 293 0
      makefile.ps2
  34. 254 0
      makefile.vc
  35. 203 0
      md2.c
  36. 290 0
      md4.c
  37. 268 0
      md5.c
  38. 19 0
      mem.c
  39. 87 0
      mpi-config.h
  40. 16 0
      mpi-types.h
  41. 4009 0
      mpi.c
  42. 225 0
      mpi.h
  43. 75 0
      mycrypt.h
  44. 41 0
      mycrypt_argchk.h
  45. 122 0
      mycrypt_cfg.h
  46. 349 0
      mycrypt_cipher.h
  47. 32 0
      mycrypt_gf.h
  48. 184 0
      mycrypt_hash.h
  49. 77 0
      mycrypt_kr.h
  50. 200 0
      mycrypt_macros.h
  51. 16 0
      mycrypt_misc.h
  52. 219 0
      mycrypt_pk.h
  53. 62 0
      mycrypt_prng.h
  54. 73 0
      notes/tech0001.txt
  55. 60 0
      ofb.c
  56. 43 0
      packet.c
  57. 1008 0
      prime.c
  58. 321 0
      rc2.c
  59. 97 0
      rc4.c
  60. 234 0
      rc5.c
  61. 253 0
      rc6.c
  62. 436 0
      rsa.c
  63. 584 0
      rsa_sys.c
  64. 506 0
      safer+.c
  65. 421 0
      safer.c
  66. 48 0
      safer_tab.c
  67. 719 0
      serpent.c
  68. 232 0
      sha1.c
  69. 229 0
      sha256.c
  70. 107 0
      sha384.c
  71. 272 0
      sha512.c
  72. 42 0
      sprng.c
  73. 47 0
      strings.c
  74. 775 0
      tiger.c
  75. 727 0
      twofish.c
  76. 121 0
      xtea.c
  77. 144 0
      yarrow.c

+ 409 - 0
aes.c

@@ -0,0 +1,409 @@
+/* This is an independent implementation of the encryption algorithm:   */
+/*                                                                      */
+/*         RIJNDAEL by Joan Daemen and Vincent Rijmen                   */
+/*                                                                      */
+/* which is a candidate algorithm in the Advanced Encryption Standard   */
+/* programme of the US National Institute of Standards and Technology.  */
+/*                                                                      */
+/* Copyright in this implementation is held by Dr B R Gladman but I     */
+/* hereby give permission for its free direct or derivative use subject */
+/* to acknowledgment of its origin and compliance with any conditions   */
+/* that the originators of the algorithm place on its exploitation.     */
+/*                                                                      */
+/* Dr Brian Gladman ([email protected]) 14th January 1999     */
+
+
+/* This code has been modified by Tom St Denis for libtomcrypt.a */
+
+#include "mycrypt.h"
+
+#ifdef RIJNDAEL
+
+const struct _cipher_descriptor rijndael_desc =
+{
+    "rijndael",
+    6,
+    16, 32, 16, 10,
+    &rijndael_setup,
+    &rijndael_ecb_encrypt,
+    &rijndael_ecb_decrypt,
+    &rijndael_test,
+    &rijndael_keysize
+};
+
+#include "aes_tab.c"
+
+#define byte(x, y) (((x)>>(8*(y)))&255)
+
+#define f_rn(bo, bi, n, k)                          \
+    bo[n] =  ft_tab[0][byte(bi[n],0)] ^             \
+             ft_tab[1][byte(bi[(n + 1) & 3],1)] ^   \
+             ft_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rn(bo, bi, n, k)                          \
+    bo[n] =  it_tab[0][byte(bi[n],0)] ^             \
+             it_tab[1][byte(bi[(n + 3) & 3],1)] ^   \
+             it_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#define ls_box(x)                \
+    ( fl_tab[0][byte(x, 0)] ^    \
+      fl_tab[1][byte(x, 1)] ^    \
+      fl_tab[2][byte(x, 2)] ^    \
+      fl_tab[3][byte(x, 3)] )
+
+#define f_rl(bo, bi, n, k)                          \
+    bo[n] =  fl_tab[0][byte(bi[n],0)] ^             \
+             fl_tab[1][byte(bi[(n + 1) & 3],1)] ^   \
+             fl_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
+
+#define i_rl(bo, bi, n, k)                          \
+    bo[n] =  il_tab[0][byte(bi[n],0)] ^             \
+             il_tab[1][byte(bi[(n + 3) & 3],1)] ^   \
+             il_tab[2][byte(bi[(n + 2) & 3],2)] ^   \
+             il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
+
+#define star_x(x) (((x) & 0x7f7f7f7fUL) << 1) ^ ((((x) & 0x80808080UL) >> 7) * 0x1bUL)
+
+#define imix_col(y,x)       \
+    u   = star_x(x);        \
+    v   = star_x(u);        \
+    w   = star_x(v);        \
+    t   = w ^ (x);          \
+   (y)  = u ^ v ^ w;        \
+   (y) ^= ROR(u ^ t,  8) ^  \
+          ROR(v ^ t, 16) ^  \
+          ROR(t,24)
+
+#ifdef CLEAN_STACK
+static int _rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+#else
+int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+#endif
+{
+    unsigned long  t, u, v, w, in_key[8];
+    int i, k_len;
+
+    /* check arguments */
+    _ARGCHK(key  != NULL);
+    _ARGCHK(skey != NULL);
+
+    if (numrounds == 0)
+       numrounds = 10 + (2 * ((keylen/8)-2));
+
+    if (keylen != 16 && keylen != 24 && keylen != 32) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    if (numrounds != (10 + (2 * ((keylen/8)-2)))) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    k_len = keylen / 4;
+    for (i = 0; i < k_len; i++) {
+        LOAD32L(in_key[i], key+(4*i));
+    }
+
+    skey->rijndael.k_len = k_len;
+    skey->rijndael.eK[0] = in_key[0]; skey->rijndael.eK[1] = in_key[1];
+    skey->rijndael.eK[2] = in_key[2]; skey->rijndael.eK[3] = in_key[3];
+
+    switch(k_len) {
+    case 4: t = skey->rijndael.eK[3];
+            for(i = 0; i < 10; ++i) {
+               t = ls_box(ROR(t,  8)) ^ rco_tab[i];
+               t ^= skey->rijndael.eK[4 * i];     skey->rijndael.eK[4 * i + 4] = t;
+               t ^= skey->rijndael.eK[4 * i + 1]; skey->rijndael.eK[4 * i + 5] = t;
+               t ^= skey->rijndael.eK[4 * i + 2]; skey->rijndael.eK[4 * i + 6] = t;
+               t ^= skey->rijndael.eK[4 * i + 3]; skey->rijndael.eK[4 * i + 7] = t;
+            }
+            break;
+    case 6: skey->rijndael.eK[4]     = in_key[4]; 
+            t = skey->rijndael.eK[5] = in_key[5];
+            for(i = 0; i < 8; ++i) {
+              t = ls_box(ROR(t,  8)) ^ rco_tab[i];
+              t ^= skey->rijndael.eK[6 * i];     skey->rijndael.eK[6 * i + 6] = t;
+              t ^= skey->rijndael.eK[6 * i + 1]; skey->rijndael.eK[6 * i + 7] = t;
+              t ^= skey->rijndael.eK[6 * i + 2]; skey->rijndael.eK[6 * i + 8] = t;
+              t ^= skey->rijndael.eK[6 * i + 3]; skey->rijndael.eK[6 * i + 9] = t;
+              t ^= skey->rijndael.eK[6 * i + 4]; skey->rijndael.eK[6 * i + 10] = t;
+              t ^= skey->rijndael.eK[6 * i + 5]; skey->rijndael.eK[6 * i + 11] = t;
+            }
+            break;
+    case 8: skey->rijndael.eK[4]     = in_key[4]; 
+            skey->rijndael.eK[5]     = in_key[5];
+            skey->rijndael.eK[6]     = in_key[6]; 
+            t = skey->rijndael.eK[7] = in_key[7];
+            for(i = 0; i < 7; ++i) {
+               t = ls_box(ROR(t,  8)) ^ rco_tab[i];
+               t ^= skey->rijndael.eK[8 * i];     skey->rijndael.eK[8 * i + 8] = t;
+               t ^= skey->rijndael.eK[8 * i + 1]; skey->rijndael.eK[8 * i + 9] = t;
+               t ^= skey->rijndael.eK[8 * i + 2]; skey->rijndael.eK[8 * i + 10] = t;
+               t ^= skey->rijndael.eK[8 * i + 3]; skey->rijndael.eK[8 * i + 11] = t;
+
+               t  = skey->rijndael.eK[8 * i + 4] ^ ls_box(t); skey->rijndael.eK[8 * i + 12] = t;
+               t ^= skey->rijndael.eK[8 * i + 5]; skey->rijndael.eK[8 * i + 13] = t;
+               t ^= skey->rijndael.eK[8 * i + 6]; skey->rijndael.eK[8 * i + 14] = t;
+               t ^= skey->rijndael.eK[8 * i + 7]; skey->rijndael.eK[8 * i + 15] = t;
+            }
+            break;
+    }
+
+    skey->rijndael.dK[0] = skey->rijndael.eK[0];
+    skey->rijndael.dK[1] = skey->rijndael.eK[1];
+    skey->rijndael.dK[2] = skey->rijndael.eK[2];
+    skey->rijndael.dK[3] = skey->rijndael.eK[3];
+    for(i = 4; i < 4 * k_len + 24; ++i) {
+        imix_col(skey->rijndael.dK[i], skey->rijndael.eK[i]);
+    }
+    return CRYPT_OK;
+};
+
+#ifdef CLEAN_STACK
+int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   int x;
+   x = _rijndael_setup(key, keylen, numrounds, skey);
+   burn_stack(sizeof(unsigned long) * 12 + sizeof(int) * 2);
+   return x;
+}
+#endif
+
+/* encrypt a block of text  */
+
+#define f_nround(bo, bi, k) \
+    f_rn(bo, bi, 0, k);     \
+    f_rn(bo, bi, 1, k);     \
+    f_rn(bo, bi, 2, k);     \
+    f_rn(bo, bi, 3, k);     \
+    k += 4
+
+#define f_lround(bo, bi, k) \
+    f_rl(bo, bi, 0, k);     \
+    f_rl(bo, bi, 1, k);     \
+    f_rl(bo, bi, 2, k);     \
+    f_rl(bo, bi, 3, k)
+    
+#ifdef RIJNDAEL_SMALL
+
+static void _fnround(unsigned long *bo, unsigned long *bi, unsigned long *k)
+{
+   f_nround(bo, bi, k);
+}
+
+static void _flround(unsigned long *bo, unsigned long *bi, unsigned long *k)
+{
+   f_lround(bo, bi, k);
+} 
+
+#undef   f_nround
+#define  f_nround(bo, bi, k) { _fnround(bo, bi, k); k += 4; }
+
+#undef   f_lround
+#define  f_lround(bo, bi, k) _flround(bo, bi, k)
+
+#endif
+
+void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{   
+    unsigned long  b0[4], b1[4], *kp;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(skey != NULL);
+
+    LOAD32L(b0[0], &pt[0]); LOAD32L(b0[1], &pt[4]);
+    LOAD32L(b0[2], &pt[8]); LOAD32L(b0[3], &pt[12]);
+    b0[0] ^= skey->rijndael.eK[0]; b0[1] ^= skey->rijndael.eK[1];
+    b0[2] ^= skey->rijndael.eK[2]; b0[3] ^= skey->rijndael.eK[3];
+    kp = skey->rijndael.eK + 4;
+
+    if(skey->rijndael.k_len > 6) {
+        f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    }
+
+    if(skey->rijndael.k_len > 4) {
+        f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    }
+
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_nround(b0, b1, kp);
+    f_nround(b1, b0, kp); f_lround(b0, b1, kp);
+
+    STORE32L(b0[0], &ct[0]); STORE32L(b0[1], &ct[4]);
+    STORE32L(b0[2], &ct[8]); STORE32L(b0[3], &ct[12]);
+#ifdef CLEAN_STACK
+    zeromem(b0, sizeof(b0));
+    zeromem(b1, sizeof(b1));
+#endif
+};
+
+/* decrypt a block of text  */
+#define i_nround(bo, bi, k) \
+    i_rn(bo, bi, 0, k);     \
+    i_rn(bo, bi, 1, k);     \
+    i_rn(bo, bi, 2, k);     \
+    i_rn(bo, bi, 3, k);     \
+    k -= 4
+
+#define i_lround(bo, bi, k) \
+    i_rl(bo, bi, 0, k);     \
+    i_rl(bo, bi, 1, k);     \
+    i_rl(bo, bi, 2, k);     \
+    i_rl(bo, bi, 3, k)
+    
+#ifdef RIJNDAEL_SMALL
+
+static void _inround(unsigned long *bo, unsigned long *bi, unsigned long *k)
+{
+   i_nround(bo, bi, k);
+}
+
+static void _ilround(unsigned long *bo, unsigned long *bi, unsigned long *k)
+{
+   i_lround(bo, bi, k);
+} 
+
+#undef   i_nround
+#define  i_nround(bo, bi, k) { _inround(bo, bi, k); k -= 4; }
+
+#undef   i_lround
+#define  i_lround(bo, bi, k) _ilround(bo, bi, k)
+
+#endif    
+
+void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{   
+    unsigned long b0[4], b1[4], *kp;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(skey != NULL);
+
+    LOAD32L(b0[0], &ct[0]); LOAD32L(b0[1], &ct[4]);
+    LOAD32L(b0[2], &ct[8]); LOAD32L(b0[3], &ct[12]);
+    b0[0] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 24]; 
+    b0[1] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 25];
+    b0[2] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 26]; 
+    b0[3] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 27];
+    kp = skey->rijndael.dK + 4 * (skey->rijndael.k_len + 5);
+
+    if(skey->rijndael.k_len > 6) {
+        i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    }
+
+    if(skey->rijndael.k_len > 4) {
+        i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    }
+
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_nround(b0, b1, kp);
+    i_nround(b1, b0, kp); i_lround(b0, b1, kp);
+
+    STORE32L(b0[0], &pt[0]); STORE32L(b0[1], &pt[4]);
+    STORE32L(b0[2], &pt[8]); STORE32L(b0[3], &pt[12]);
+#ifdef CLEAN_STACK
+    zeromem(b0, sizeof(b0));
+    zeromem(b1, sizeof(b1));
+#endif    
+};
+
+int rijndael_test(void)
+{
+ int errno;
+
+ static const unsigned char pt128[16] = {
+     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+     0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+ static const unsigned char key128[16] = {
+     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+ static const unsigned char ct128[16] = {
+     0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 
+     0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a };
+
+ static const unsigned char key192[24] = {
+     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ static const unsigned char ct192[16]  = {
+     0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 
+     0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 };
+
+ static const unsigned char key256[32] = {
+     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+ static const unsigned char ct256[16] = {
+     0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 
+     0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
+ symmetric_key key;
+ unsigned char tmp[2][16];
+
+ if ((errno = rijndael_setup(key128, 16, 0, &key)) != CRYPT_OK) { 
+    return errno;
+ }
+
+ rijndael_ecb_encrypt(pt128, tmp[0], &key);
+ rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct128, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+ if (memcmp(tmp[1], pt128, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ if ((errno = rijndael_setup(key192, 24, 0, &key)) != CRYPT_OK) { 
+    return errno; 
+ }
+
+ rijndael_ecb_encrypt(pt128, tmp[0], &key);
+ rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct192, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+ if (memcmp(tmp[1], pt128, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ if ((errno = rijndael_setup(key256, 32, 0, &key)) != CRYPT_OK) {
+    return errno; 
+ }
+ rijndael_ecb_encrypt(pt128, tmp[0], &key);
+ rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct256, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+ if (memcmp(tmp[1], pt128, 16)) { 
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+ return CRYPT_OK;
+}
+
+int rijndael_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+
+   if (*desired_keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*desired_keysize < 24) {
+      *desired_keysize = 16;
+      return CRYPT_OK;
+   } else if (*desired_keysize < 32) {
+      *desired_keysize = 24;
+      return CRYPT_OK;
+   } else {
+      *desired_keysize = 32;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+

+ 851 - 0
aes_tab.c

@@ -0,0 +1,851 @@
+/* The precompute tables for AES */
+
+static const unsigned long ft_tab[4][256] = {
+{0xa56363c6UL, 0x847c7cf8UL, 0x997777eeUL, 0x8d7b7bf6UL, 0x0df2f2ffUL, 
+ 0xbd6b6bd6UL, 0xb16f6fdeUL, 0x54c5c591UL, 0x50303060UL, 0x03010102UL, 
+ 0xa96767ceUL, 0x7d2b2b56UL, 0x19fefee7UL, 0x62d7d7b5UL, 0xe6abab4dUL, 
+ 0x9a7676ecUL, 0x45caca8fUL, 0x9d82821fUL, 0x40c9c989UL, 0x877d7dfaUL, 
+ 0x15fafaefUL, 0xeb5959b2UL, 0xc947478eUL, 0x0bf0f0fbUL, 0xecadad41UL, 
+ 0x67d4d4b3UL, 0xfda2a25fUL, 0xeaafaf45UL, 0xbf9c9c23UL, 0xf7a4a453UL, 
+ 0x967272e4UL, 0x5bc0c09bUL, 0xc2b7b775UL, 0x1cfdfde1UL, 0xae93933dUL, 
+ 0x6a26264cUL, 0x5a36366cUL, 0x413f3f7eUL, 0x02f7f7f5UL, 0x4fcccc83UL, 
+ 0x5c343468UL, 0xf4a5a551UL, 0x34e5e5d1UL, 0x08f1f1f9UL, 0x937171e2UL, 
+ 0x73d8d8abUL, 0x53313162UL, 0x3f15152aUL, 0x0c040408UL, 0x52c7c795UL, 
+ 0x65232346UL, 0x5ec3c39dUL, 0x28181830UL, 0xa1969637UL, 0x0f05050aUL, 
+ 0xb59a9a2fUL, 0x0907070eUL, 0x36121224UL, 0x9b80801bUL, 0x3de2e2dfUL, 
+ 0x26ebebcdUL, 0x6927274eUL, 0xcdb2b27fUL, 0x9f7575eaUL, 0x1b090912UL, 
+ 0x9e83831dUL, 0x742c2c58UL, 0x2e1a1a34UL, 0x2d1b1b36UL, 0xb26e6edcUL, 
+ 0xee5a5ab4UL, 0xfba0a05bUL, 0xf65252a4UL, 0x4d3b3b76UL, 0x61d6d6b7UL, 
+ 0xceb3b37dUL, 0x7b292952UL, 0x3ee3e3ddUL, 0x712f2f5eUL, 0x97848413UL, 
+ 0xf55353a6UL, 0x68d1d1b9UL, 0x00000000UL, 0x2cededc1UL, 0x60202040UL, 
+ 0x1ffcfce3UL, 0xc8b1b179UL, 0xed5b5bb6UL, 0xbe6a6ad4UL, 0x46cbcb8dUL, 
+ 0xd9bebe67UL, 0x4b393972UL, 0xde4a4a94UL, 0xd44c4c98UL, 0xe85858b0UL, 
+ 0x4acfcf85UL, 0x6bd0d0bbUL, 0x2aefefc5UL, 0xe5aaaa4fUL, 0x16fbfbedUL, 
+ 0xc5434386UL, 0xd74d4d9aUL, 0x55333366UL, 0x94858511UL, 0xcf45458aUL, 
+ 0x10f9f9e9UL, 0x06020204UL, 0x817f7ffeUL, 0xf05050a0UL, 0x443c3c78UL, 
+ 0xba9f9f25UL, 0xe3a8a84bUL, 0xf35151a2UL, 0xfea3a35dUL, 0xc0404080UL, 
+ 0x8a8f8f05UL, 0xad92923fUL, 0xbc9d9d21UL, 0x48383870UL, 0x04f5f5f1UL, 
+ 0xdfbcbc63UL, 0xc1b6b677UL, 0x75dadaafUL, 0x63212142UL, 0x30101020UL, 
+ 0x1affffe5UL, 0x0ef3f3fdUL, 0x6dd2d2bfUL, 0x4ccdcd81UL, 0x140c0c18UL, 
+ 0x35131326UL, 0x2fececc3UL, 0xe15f5fbeUL, 0xa2979735UL, 0xcc444488UL, 
+ 0x3917172eUL, 0x57c4c493UL, 0xf2a7a755UL, 0x827e7efcUL, 0x473d3d7aUL, 
+ 0xac6464c8UL, 0xe75d5dbaUL, 0x2b191932UL, 0x957373e6UL, 0xa06060c0UL, 
+ 0x98818119UL, 0xd14f4f9eUL, 0x7fdcdca3UL, 0x66222244UL, 0x7e2a2a54UL, 
+ 0xab90903bUL, 0x8388880bUL, 0xca46468cUL, 0x29eeeec7UL, 0xd3b8b86bUL, 
+ 0x3c141428UL, 0x79dedea7UL, 0xe25e5ebcUL, 0x1d0b0b16UL, 0x76dbdbadUL, 
+ 0x3be0e0dbUL, 0x56323264UL, 0x4e3a3a74UL, 0x1e0a0a14UL, 0xdb494992UL, 
+ 0x0a06060cUL, 0x6c242448UL, 0xe45c5cb8UL, 0x5dc2c29fUL, 0x6ed3d3bdUL, 
+ 0xefacac43UL, 0xa66262c4UL, 0xa8919139UL, 0xa4959531UL, 0x37e4e4d3UL, 
+ 0x8b7979f2UL, 0x32e7e7d5UL, 0x43c8c88bUL, 0x5937376eUL, 0xb76d6ddaUL, 
+ 0x8c8d8d01UL, 0x64d5d5b1UL, 0xd24e4e9cUL, 0xe0a9a949UL, 0xb46c6cd8UL, 
+ 0xfa5656acUL, 0x07f4f4f3UL, 0x25eaeacfUL, 0xaf6565caUL, 0x8e7a7af4UL, 
+ 0xe9aeae47UL, 0x18080810UL, 0xd5baba6fUL, 0x887878f0UL, 0x6f25254aUL, 
+ 0x722e2e5cUL, 0x241c1c38UL, 0xf1a6a657UL, 0xc7b4b473UL, 0x51c6c697UL, 
+ 0x23e8e8cbUL, 0x7cdddda1UL, 0x9c7474e8UL, 0x211f1f3eUL, 0xdd4b4b96UL, 
+ 0xdcbdbd61UL, 0x868b8b0dUL, 0x858a8a0fUL, 0x907070e0UL, 0x423e3e7cUL, 
+ 0xc4b5b571UL, 0xaa6666ccUL, 0xd8484890UL, 0x05030306UL, 0x01f6f6f7UL, 
+ 0x120e0e1cUL, 0xa36161c2UL, 0x5f35356aUL, 0xf95757aeUL, 0xd0b9b969UL, 
+ 0x91868617UL, 0x58c1c199UL, 0x271d1d3aUL, 0xb99e9e27UL, 0x38e1e1d9UL, 
+ 0x13f8f8ebUL, 0xb398982bUL, 0x33111122UL, 0xbb6969d2UL, 0x70d9d9a9UL, 
+ 0x898e8e07UL, 0xa7949433UL, 0xb69b9b2dUL, 0x221e1e3cUL, 0x92878715UL, 
+ 0x20e9e9c9UL, 0x49cece87UL, 0xff5555aaUL, 0x78282850UL, 0x7adfdfa5UL, 
+ 0x8f8c8c03UL, 0xf8a1a159UL, 0x80898909UL, 0x170d0d1aUL, 0xdabfbf65UL, 
+ 0x31e6e6d7UL, 0xc6424284UL, 0xb86868d0UL, 0xc3414182UL, 0xb0999929UL, 
+ 0x772d2d5aUL, 0x110f0f1eUL, 0xcbb0b07bUL, 0xfc5454a8UL, 0xd6bbbb6dUL, 
+ 0x3a16162cUL}, 
+{0x6363c6a5UL, 0x7c7cf884UL, 0x7777ee99UL, 0x7b7bf68dUL, 0xf2f2ff0dUL,
+ 0x6b6bd6bdUL, 0x6f6fdeb1UL, 0xc5c59154UL, 0x30306050UL, 0x01010203UL, 
+ 0x6767cea9UL, 0x2b2b567dUL, 0xfefee719UL, 0xd7d7b562UL, 0xabab4de6UL, 
+ 0x7676ec9aUL, 0xcaca8f45UL, 0x82821f9dUL, 0xc9c98940UL, 0x7d7dfa87UL, 
+ 0xfafaef15UL, 0x5959b2ebUL, 0x47478ec9UL, 0xf0f0fb0bUL, 0xadad41ecUL, 
+ 0xd4d4b367UL, 0xa2a25ffdUL, 0xafaf45eaUL, 0x9c9c23bfUL, 0xa4a453f7UL, 
+ 0x7272e496UL, 0xc0c09b5bUL, 0xb7b775c2UL, 0xfdfde11cUL, 0x93933daeUL, 
+ 0x26264c6aUL, 0x36366c5aUL, 0x3f3f7e41UL, 0xf7f7f502UL, 0xcccc834fUL, 
+ 0x3434685cUL, 0xa5a551f4UL, 0xe5e5d134UL, 0xf1f1f908UL, 0x7171e293UL, 
+ 0xd8d8ab73UL, 0x31316253UL, 0x15152a3fUL, 0x0404080cUL, 0xc7c79552UL, 
+ 0x23234665UL, 0xc3c39d5eUL, 0x18183028UL, 0x969637a1UL, 0x05050a0fUL, 
+ 0x9a9a2fb5UL, 0x07070e09UL, 0x12122436UL, 0x80801b9bUL, 0xe2e2df3dUL, 
+ 0xebebcd26UL, 0x27274e69UL, 0xb2b27fcdUL, 0x7575ea9fUL, 0x0909121bUL, 
+ 0x83831d9eUL, 0x2c2c5874UL, 0x1a1a342eUL, 0x1b1b362dUL, 0x6e6edcb2UL, 
+ 0x5a5ab4eeUL, 0xa0a05bfbUL, 0x5252a4f6UL, 0x3b3b764dUL, 0xd6d6b761UL, 
+ 0xb3b37dceUL, 0x2929527bUL, 0xe3e3dd3eUL, 0x2f2f5e71UL, 0x84841397UL, 
+ 0x5353a6f5UL, 0xd1d1b968UL, 0x00000000UL, 0xededc12cUL, 0x20204060UL, 
+ 0xfcfce31fUL, 0xb1b179c8UL, 0x5b5bb6edUL, 0x6a6ad4beUL, 0xcbcb8d46UL, 
+ 0xbebe67d9UL, 0x3939724bUL, 0x4a4a94deUL, 0x4c4c98d4UL, 0x5858b0e8UL, 
+ 0xcfcf854aUL, 0xd0d0bb6bUL, 0xefefc52aUL, 0xaaaa4fe5UL, 0xfbfbed16UL, 
+ 0x434386c5UL, 0x4d4d9ad7UL, 0x33336655UL, 0x85851194UL, 0x45458acfUL, 
+ 0xf9f9e910UL, 0x02020406UL, 0x7f7ffe81UL, 0x5050a0f0UL, 0x3c3c7844UL, 
+ 0x9f9f25baUL, 0xa8a84be3UL, 0x5151a2f3UL, 0xa3a35dfeUL, 0x404080c0UL, 
+ 0x8f8f058aUL, 0x92923fadUL, 0x9d9d21bcUL, 0x38387048UL, 0xf5f5f104UL, 
+ 0xbcbc63dfUL, 0xb6b677c1UL, 0xdadaaf75UL, 0x21214263UL, 0x10102030UL, 
+ 0xffffe51aUL, 0xf3f3fd0eUL, 0xd2d2bf6dUL, 0xcdcd814cUL, 0x0c0c1814UL, 
+ 0x13132635UL, 0xececc32fUL, 0x5f5fbee1UL, 0x979735a2UL, 0x444488ccUL, 
+ 0x17172e39UL, 0xc4c49357UL, 0xa7a755f2UL, 0x7e7efc82UL, 0x3d3d7a47UL, 
+ 0x6464c8acUL, 0x5d5dbae7UL, 0x1919322bUL, 0x7373e695UL, 0x6060c0a0UL, 
+ 0x81811998UL, 0x4f4f9ed1UL, 0xdcdca37fUL, 0x22224466UL, 0x2a2a547eUL, 
+ 0x90903babUL, 0x88880b83UL, 0x46468ccaUL, 0xeeeec729UL, 0xb8b86bd3UL, 
+ 0x1414283cUL, 0xdedea779UL, 0x5e5ebce2UL, 0x0b0b161dUL, 0xdbdbad76UL, 
+ 0xe0e0db3bUL, 0x32326456UL, 0x3a3a744eUL, 0x0a0a141eUL, 0x494992dbUL, 
+ 0x06060c0aUL, 0x2424486cUL, 0x5c5cb8e4UL, 0xc2c29f5dUL, 0xd3d3bd6eUL, 
+ 0xacac43efUL, 0x6262c4a6UL, 0x919139a8UL, 0x959531a4UL, 0xe4e4d337UL, 
+ 0x7979f28bUL, 0xe7e7d532UL, 0xc8c88b43UL, 0x37376e59UL, 0x6d6ddab7UL, 
+ 0x8d8d018cUL, 0xd5d5b164UL, 0x4e4e9cd2UL, 0xa9a949e0UL, 0x6c6cd8b4UL, 
+ 0x5656acfaUL, 0xf4f4f307UL, 0xeaeacf25UL, 0x6565caafUL, 0x7a7af48eUL, 
+ 0xaeae47e9UL, 0x08081018UL, 0xbaba6fd5UL, 0x7878f088UL, 0x25254a6fUL, 
+ 0x2e2e5c72UL, 0x1c1c3824UL, 0xa6a657f1UL, 0xb4b473c7UL, 0xc6c69751UL, 
+ 0xe8e8cb23UL, 0xdddda17cUL, 0x7474e89cUL, 0x1f1f3e21UL, 0x4b4b96ddUL, 
+ 0xbdbd61dcUL, 0x8b8b0d86UL, 0x8a8a0f85UL, 0x7070e090UL, 0x3e3e7c42UL, 
+ 0xb5b571c4UL, 0x6666ccaaUL, 0x484890d8UL, 0x03030605UL, 0xf6f6f701UL, 
+ 0x0e0e1c12UL, 0x6161c2a3UL, 0x35356a5fUL, 0x5757aef9UL, 0xb9b969d0UL, 
+ 0x86861791UL, 0xc1c19958UL, 0x1d1d3a27UL, 0x9e9e27b9UL, 0xe1e1d938UL, 
+ 0xf8f8eb13UL, 0x98982bb3UL, 0x11112233UL, 0x6969d2bbUL, 0xd9d9a970UL, 
+ 0x8e8e0789UL, 0x949433a7UL, 0x9b9b2db6UL, 0x1e1e3c22UL, 0x87871592UL, 
+ 0xe9e9c920UL, 0xcece8749UL, 0x5555aaffUL, 0x28285078UL, 0xdfdfa57aUL, 
+ 0x8c8c038fUL, 0xa1a159f8UL, 0x89890980UL, 0x0d0d1a17UL, 0xbfbf65daUL, 
+ 0xe6e6d731UL, 0x424284c6UL, 0x6868d0b8UL, 0x414182c3UL, 0x999929b0UL, 
+ 0x2d2d5a77UL, 0x0f0f1e11UL, 0xb0b07bcbUL, 0x5454a8fcUL, 0xbbbb6dd6UL, 
+ 0x16162c3aUL}, 
+{0x63c6a563UL, 0x7cf8847cUL, 0x77ee9977UL, 0x7bf68d7bUL, 0xf2ff0df2UL, 
+ 0x6bd6bd6bUL, 0x6fdeb16fUL, 0xc59154c5UL, 0x30605030UL, 0x01020301UL, 
+ 0x67cea967UL, 0x2b567d2bUL, 0xfee719feUL, 0xd7b562d7UL, 0xab4de6abUL, 
+ 0x76ec9a76UL, 0xca8f45caUL, 0x821f9d82UL, 0xc98940c9UL, 0x7dfa877dUL,
+ 0xfaef15faUL, 0x59b2eb59UL, 0x478ec947UL, 0xf0fb0bf0UL, 0xad41ecadUL, 
+ 0xd4b367d4UL, 0xa25ffda2UL, 0xaf45eaafUL, 0x9c23bf9cUL, 0xa453f7a4UL, 
+ 0x72e49672UL, 0xc09b5bc0UL, 0xb775c2b7UL, 0xfde11cfdUL, 0x933dae93UL, 
+ 0x264c6a26UL, 0x366c5a36UL, 0x3f7e413fUL, 0xf7f502f7UL, 0xcc834fccUL, 
+ 0x34685c34UL, 0xa551f4a5UL, 0xe5d134e5UL, 0xf1f908f1UL, 0x71e29371UL, 
+ 0xd8ab73d8UL, 0x31625331UL, 0x152a3f15UL, 0x04080c04UL, 0xc79552c7UL, 
+ 0x23466523UL, 0xc39d5ec3UL, 0x18302818UL, 0x9637a196UL, 0x050a0f05UL, 
+ 0x9a2fb59aUL, 0x070e0907UL, 0x12243612UL, 0x801b9b80UL, 0xe2df3de2UL, 
+ 0xebcd26ebUL, 0x274e6927UL, 0xb27fcdb2UL, 0x75ea9f75UL, 0x09121b09UL, 
+ 0x831d9e83UL, 0x2c58742cUL, 0x1a342e1aUL, 0x1b362d1bUL, 0x6edcb26eUL, 
+ 0x5ab4ee5aUL, 0xa05bfba0UL, 0x52a4f652UL, 0x3b764d3bUL, 0xd6b761d6UL, 
+ 0xb37dceb3UL, 0x29527b29UL, 0xe3dd3ee3UL, 0x2f5e712fUL, 0x84139784UL, 
+ 0x53a6f553UL, 0xd1b968d1UL, 0x00000000UL, 0xedc12cedUL, 0x20406020UL, 
+ 0xfce31ffcUL, 0xb179c8b1UL, 0x5bb6ed5bUL, 0x6ad4be6aUL, 0xcb8d46cbUL, 
+ 0xbe67d9beUL, 0x39724b39UL, 0x4a94de4aUL, 0x4c98d44cUL, 0x58b0e858UL, 
+ 0xcf854acfUL, 0xd0bb6bd0UL, 0xefc52aefUL, 0xaa4fe5aaUL, 0xfbed16fbUL, 
+ 0x4386c543UL, 0x4d9ad74dUL, 0x33665533UL, 0x85119485UL, 0x458acf45UL, 
+ 0xf9e910f9UL, 0x02040602UL, 0x7ffe817fUL, 0x50a0f050UL, 0x3c78443cUL, 
+ 0x9f25ba9fUL, 0xa84be3a8UL, 0x51a2f351UL, 0xa35dfea3UL, 0x4080c040UL, 
+ 0x8f058a8fUL, 0x923fad92UL, 0x9d21bc9dUL, 0x38704838UL, 0xf5f104f5UL, 
+ 0xbc63dfbcUL, 0xb677c1b6UL, 0xdaaf75daUL, 0x21426321UL, 0x10203010UL, 
+ 0xffe51affUL, 0xf3fd0ef3UL, 0xd2bf6dd2UL, 0xcd814ccdUL, 0x0c18140cUL, 
+ 0x13263513UL, 0xecc32fecUL, 0x5fbee15fUL, 0x9735a297UL, 0x4488cc44UL, 
+ 0x172e3917UL, 0xc49357c4UL, 0xa755f2a7UL, 0x7efc827eUL, 0x3d7a473dUL, 
+ 0x64c8ac64UL, 0x5dbae75dUL, 0x19322b19UL, 0x73e69573UL, 0x60c0a060UL, 
+ 0x81199881UL, 0x4f9ed14fUL, 0xdca37fdcUL, 0x22446622UL, 0x2a547e2aUL, 
+ 0x903bab90UL, 0x880b8388UL, 0x468cca46UL, 0xeec729eeUL, 0xb86bd3b8UL, 
+ 0x14283c14UL, 0xdea779deUL, 0x5ebce25eUL, 0x0b161d0bUL, 0xdbad76dbUL, 
+ 0xe0db3be0UL, 0x32645632UL, 0x3a744e3aUL, 0x0a141e0aUL, 0x4992db49UL, 
+ 0x060c0a06UL, 0x24486c24UL, 0x5cb8e45cUL, 0xc29f5dc2UL, 0xd3bd6ed3UL, 
+ 0xac43efacUL, 0x62c4a662UL, 0x9139a891UL, 0x9531a495UL, 0xe4d337e4UL, 
+ 0x79f28b79UL, 0xe7d532e7UL, 0xc88b43c8UL, 0x376e5937UL, 0x6ddab76dUL, 
+ 0x8d018c8dUL, 0xd5b164d5UL, 0x4e9cd24eUL, 0xa949e0a9UL, 0x6cd8b46cUL, 
+ 0x56acfa56UL, 0xf4f307f4UL, 0xeacf25eaUL, 0x65caaf65UL, 0x7af48e7aUL, 
+ 0xae47e9aeUL, 0x08101808UL, 0xba6fd5baUL, 0x78f08878UL, 0x254a6f25UL, 
+ 0x2e5c722eUL, 0x1c38241cUL, 0xa657f1a6UL, 0xb473c7b4UL, 0xc69751c6UL, 
+ 0xe8cb23e8UL, 0xdda17cddUL, 0x74e89c74UL, 0x1f3e211fUL, 0x4b96dd4bUL, 
+ 0xbd61dcbdUL, 0x8b0d868bUL, 0x8a0f858aUL, 0x70e09070UL, 0x3e7c423eUL, 
+ 0xb571c4b5UL, 0x66ccaa66UL, 0x4890d848UL, 0x03060503UL, 0xf6f701f6UL, 
+ 0x0e1c120eUL, 0x61c2a361UL, 0x356a5f35UL, 0x57aef957UL, 0xb969d0b9UL, 
+ 0x86179186UL, 0xc19958c1UL, 0x1d3a271dUL, 0x9e27b99eUL, 0xe1d938e1UL, 
+ 0xf8eb13f8UL, 0x982bb398UL, 0x11223311UL, 0x69d2bb69UL, 0xd9a970d9UL, 
+ 0x8e07898eUL, 0x9433a794UL, 0x9b2db69bUL, 0x1e3c221eUL, 0x87159287UL, 
+ 0xe9c920e9UL, 0xce8749ceUL, 0x55aaff55UL, 0x28507828UL, 0xdfa57adfUL, 
+ 0x8c038f8cUL, 0xa159f8a1UL, 0x89098089UL, 0x0d1a170dUL, 0xbf65dabfUL, 
+ 0xe6d731e6UL, 0x4284c642UL, 0x68d0b868UL, 0x4182c341UL, 0x9929b099UL, 
+ 0x2d5a772dUL, 0x0f1e110fUL, 0xb07bcbb0UL, 0x54a8fc54UL, 0xbb6dd6bbUL, 
+ 0x162c3a16UL}, 
+{0xc6a56363UL, 0xf8847c7cUL, 0xee997777UL, 0xf68d7b7bUL, 0xff0df2f2UL, 
+ 0xd6bd6b6bUL, 0xdeb16f6fUL, 0x9154c5c5UL, 0x60503030UL, 0x02030101UL, 
+ 0xcea96767UL, 0x567d2b2bUL, 0xe719fefeUL, 0xb562d7d7UL, 0x4de6ababUL, 
+ 0xec9a7676UL, 0x8f45cacaUL, 0x1f9d8282UL, 0x8940c9c9UL, 0xfa877d7dUL, 
+ 0xef15fafaUL, 0xb2eb5959UL, 0x8ec94747UL, 0xfb0bf0f0UL, 0x41ecadadUL, 
+ 0xb367d4d4UL, 0x5ffda2a2UL, 0x45eaafafUL, 0x23bf9c9cUL, 0x53f7a4a4UL, 
+ 0xe4967272UL, 0x9b5bc0c0UL, 0x75c2b7b7UL, 0xe11cfdfdUL, 0x3dae9393UL, 
+ 0x4c6a2626UL, 0x6c5a3636UL, 0x7e413f3fUL, 0xf502f7f7UL, 0x834fccccUL, 
+ 0x685c3434UL, 0x51f4a5a5UL, 0xd134e5e5UL, 0xf908f1f1UL, 0xe2937171UL, 
+ 0xab73d8d8UL, 0x62533131UL, 0x2a3f1515UL, 0x080c0404UL, 0x9552c7c7UL, 
+ 0x46652323UL, 0x9d5ec3c3UL, 0x30281818UL, 0x37a19696UL, 0x0a0f0505UL, 
+ 0x2fb59a9aUL, 0x0e090707UL, 0x24361212UL, 0x1b9b8080UL, 0xdf3de2e2UL, 
+ 0xcd26ebebUL, 0x4e692727UL, 0x7fcdb2b2UL, 0xea9f7575UL, 0x121b0909UL, 
+ 0x1d9e8383UL, 0x58742c2cUL, 0x342e1a1aUL, 0x362d1b1bUL, 0xdcb26e6eUL, 
+ 0xb4ee5a5aUL, 0x5bfba0a0UL, 0xa4f65252UL, 0x764d3b3bUL, 0xb761d6d6UL, 
+ 0x7dceb3b3UL, 0x527b2929UL, 0xdd3ee3e3UL, 0x5e712f2fUL, 0x13978484UL, 
+ 0xa6f55353UL, 0xb968d1d1UL, 0x00000000UL, 0xc12cededUL, 0x40602020UL, 
+ 0xe31ffcfcUL, 0x79c8b1b1UL, 0xb6ed5b5bUL, 0xd4be6a6aUL, 0x8d46cbcbUL, 
+ 0x67d9bebeUL, 0x724b3939UL, 0x94de4a4aUL, 0x98d44c4cUL, 0xb0e85858UL, 
+ 0x854acfcfUL, 0xbb6bd0d0UL, 0xc52aefefUL, 0x4fe5aaaaUL, 0xed16fbfbUL, 
+ 0x86c54343UL, 0x9ad74d4dUL, 0x66553333UL, 0x11948585UL, 0x8acf4545UL, 
+ 0xe910f9f9UL, 0x04060202UL, 0xfe817f7fUL, 0xa0f05050UL, 0x78443c3cUL, 
+ 0x25ba9f9fUL, 0x4be3a8a8UL, 0xa2f35151UL, 0x5dfea3a3UL, 0x80c04040UL, 
+ 0x058a8f8fUL, 0x3fad9292UL, 0x21bc9d9dUL, 0x70483838UL, 0xf104f5f5UL, 
+ 0x63dfbcbcUL, 0x77c1b6b6UL, 0xaf75dadaUL, 0x42632121UL, 0x20301010UL, 
+ 0xe51affffUL, 0xfd0ef3f3UL, 0xbf6dd2d2UL, 0x814ccdcdUL, 0x18140c0cUL, 
+ 0x26351313UL, 0xc32fececUL, 0xbee15f5fUL, 0x35a29797UL, 0x88cc4444UL, 
+ 0x2e391717UL, 0x9357c4c4UL, 0x55f2a7a7UL, 0xfc827e7eUL, 0x7a473d3dUL, 
+ 0xc8ac6464UL, 0xbae75d5dUL, 0x322b1919UL, 0xe6957373UL, 0xc0a06060UL, 
+ 0x19988181UL, 0x9ed14f4fUL, 0xa37fdcdcUL, 0x44662222UL, 0x547e2a2aUL, 
+ 0x3bab9090UL, 0x0b838888UL, 0x8cca4646UL, 0xc729eeeeUL, 0x6bd3b8b8UL, 
+ 0x283c1414UL, 0xa779dedeUL, 0xbce25e5eUL, 0x161d0b0bUL, 0xad76dbdbUL, 
+ 0xdb3be0e0UL, 0x64563232UL, 0x744e3a3aUL, 0x141e0a0aUL, 0x92db4949UL, 
+ 0x0c0a0606UL, 0x486c2424UL, 0xb8e45c5cUL, 0x9f5dc2c2UL, 0xbd6ed3d3UL, 
+ 0x43efacacUL, 0xc4a66262UL, 0x39a89191UL, 0x31a49595UL, 0xd337e4e4UL, 
+ 0xf28b7979UL, 0xd532e7e7UL, 0x8b43c8c8UL, 0x6e593737UL, 0xdab76d6dUL, 
+ 0x018c8d8dUL, 0xb164d5d5UL, 0x9cd24e4eUL, 0x49e0a9a9UL, 0xd8b46c6cUL, 
+ 0xacfa5656UL, 0xf307f4f4UL, 0xcf25eaeaUL, 0xcaaf6565UL, 0xf48e7a7aUL, 
+ 0x47e9aeaeUL, 0x10180808UL, 0x6fd5babaUL, 0xf0887878UL, 0x4a6f2525UL, 
+ 0x5c722e2eUL, 0x38241c1cUL, 0x57f1a6a6UL, 0x73c7b4b4UL, 0x9751c6c6UL, 
+ 0xcb23e8e8UL, 0xa17cddddUL, 0xe89c7474UL, 0x3e211f1fUL, 0x96dd4b4bUL, 
+ 0x61dcbdbdUL, 0x0d868b8bUL, 0x0f858a8aUL, 0xe0907070UL, 0x7c423e3eUL, 
+ 0x71c4b5b5UL, 0xccaa6666UL, 0x90d84848UL, 0x06050303UL, 0xf701f6f6UL, 
+ 0x1c120e0eUL, 0xc2a36161UL, 0x6a5f3535UL, 0xaef95757UL, 0x69d0b9b9UL, 
+ 0x17918686UL, 0x9958c1c1UL, 0x3a271d1dUL, 0x27b99e9eUL, 0xd938e1e1UL, 
+ 0xeb13f8f8UL, 0x2bb39898UL, 0x22331111UL, 0xd2bb6969UL, 0xa970d9d9UL, 
+ 0x07898e8eUL, 0x33a79494UL, 0x2db69b9bUL, 0x3c221e1eUL, 0x15928787UL, 
+ 0xc920e9e9UL, 0x8749ceceUL, 0xaaff5555UL, 0x50782828UL, 0xa57adfdfUL, 
+ 0x038f8c8cUL, 0x59f8a1a1UL, 0x09808989UL, 0x1a170d0dUL, 0x65dabfbfUL, 
+ 0xd731e6e6UL, 0x84c64242UL, 0xd0b86868UL, 0x82c34141UL, 0x29b09999UL, 
+ 0x5a772d2dUL, 0x1e110f0fUL, 0x7bcbb0b0UL, 0xa8fc5454UL, 0x6dd6bbbbUL, 
+ 0x2c3a1616UL}
+ };
+
+static const unsigned long it_tab[4][256] = {
+{0x50a7f451UL, 0x5365417eUL, 0xc3a4171aUL, 0x965e273aUL, 0xcb6bab3bUL, 
+ 0xf1459d1fUL, 0xab58faacUL, 0x9303e34bUL, 0x55fa3020UL, 0xf66d76adUL, 
+ 0x9176cc88UL, 0x254c02f5UL, 0xfcd7e54fUL, 0xd7cb2ac5UL, 0x80443526UL, 
+ 0x8fa362b5UL, 0x495ab1deUL, 0x671bba25UL, 0x980eea45UL, 0xe1c0fe5dUL, 
+ 0x02752fc3UL, 0x12f04c81UL, 0xa397468dUL, 0xc6f9d36bUL, 0xe75f8f03UL, 
+ 0x959c9215UL, 0xeb7a6dbfUL, 0xda595295UL, 0x2d83bed4UL, 0xd3217458UL, 
+ 0x2969e049UL, 0x44c8c98eUL, 0x6a89c275UL, 0x78798ef4UL, 0x6b3e5899UL, 
+ 0xdd71b927UL, 0xb64fe1beUL, 0x17ad88f0UL, 0x66ac20c9UL, 0xb43ace7dUL, 
+ 0x184adf63UL, 0x82311ae5UL, 0x60335197UL, 0x457f5362UL, 0xe07764b1UL, 
+ 0x84ae6bbbUL, 0x1ca081feUL, 0x942b08f9UL, 0x58684870UL, 0x19fd458fUL, 
+ 0x876cde94UL, 0xb7f87b52UL, 0x23d373abUL, 0xe2024b72UL, 0x578f1fe3UL, 
+ 0x2aab5566UL, 0x0728ebb2UL, 0x03c2b52fUL, 0x9a7bc586UL, 0xa50837d3UL, 
+ 0xf2872830UL, 0xb2a5bf23UL, 0xba6a0302UL, 0x5c8216edUL, 0x2b1ccf8aUL, 
+ 0x92b479a7UL, 0xf0f207f3UL, 0xa1e2694eUL, 0xcdf4da65UL, 0xd5be0506UL, 
+ 0x1f6234d1UL, 0x8afea6c4UL, 0x9d532e34UL, 0xa055f3a2UL, 0x32e18a05UL, 
+ 0x75ebf6a4UL, 0x39ec830bUL, 0xaaef6040UL, 0x069f715eUL, 0x51106ebdUL, 
+ 0xf98a213eUL, 0x3d06dd96UL, 0xae053eddUL, 0x46bde64dUL, 0xb58d5491UL, 
+ 0x055dc471UL, 0x6fd40604UL, 0xff155060UL, 0x24fb9819UL, 0x97e9bdd6UL, 
+ 0xcc434089UL, 0x779ed967UL, 0xbd42e8b0UL, 0x888b8907UL, 0x385b19e7UL, 
+ 0xdbeec879UL, 0x470a7ca1UL, 0xe90f427cUL, 0xc91e84f8UL, 0x00000000UL, 
+ 0x83868009UL, 0x48ed2b32UL, 0xac70111eUL, 0x4e725a6cUL, 0xfbff0efdUL, 
+ 0x5638850fUL, 0x1ed5ae3dUL, 0x27392d36UL, 0x64d90f0aUL, 0x21a65c68UL, 
+ 0xd1545b9bUL, 0x3a2e3624UL, 0xb1670a0cUL, 0x0fe75793UL, 0xd296eeb4UL, 
+ 0x9e919b1bUL, 0x4fc5c080UL, 0xa220dc61UL, 0x694b775aUL, 0x161a121cUL, 
+ 0x0aba93e2UL, 0xe52aa0c0UL, 0x43e0223cUL, 0x1d171b12UL, 0x0b0d090eUL, 
+ 0xadc78bf2UL, 0xb9a8b62dUL, 0xc8a91e14UL, 0x8519f157UL, 0x4c0775afUL, 
+ 0xbbdd99eeUL, 0xfd607fa3UL, 0x9f2601f7UL, 0xbcf5725cUL, 0xc53b6644UL, 
+ 0x347efb5bUL, 0x7629438bUL, 0xdcc623cbUL, 0x68fcedb6UL, 0x63f1e4b8UL, 
+ 0xcadc31d7UL, 0x10856342UL, 0x40229713UL, 0x2011c684UL, 0x7d244a85UL, 
+ 0xf83dbbd2UL, 0x1132f9aeUL, 0x6da129c7UL, 0x4b2f9e1dUL, 0xf330b2dcUL, 
+ 0xec52860dUL, 0xd0e3c177UL, 0x6c16b32bUL, 0x99b970a9UL, 0xfa489411UL, 
+ 0x2264e947UL, 0xc48cfca8UL, 0x1a3ff0a0UL, 0xd82c7d56UL, 0xef903322UL, 
+ 0xc74e4987UL, 0xc1d138d9UL, 0xfea2ca8cUL, 0x360bd498UL, 0xcf81f5a6UL, 
+ 0x28de7aa5UL, 0x268eb7daUL, 0xa4bfad3fUL, 0xe49d3a2cUL, 0x0d927850UL, 
+ 0x9bcc5f6aUL, 0x62467e54UL, 0xc2138df6UL, 0xe8b8d890UL, 0x5ef7392eUL, 
+ 0xf5afc382UL, 0xbe805d9fUL, 0x7c93d069UL, 0xa92dd56fUL, 0xb31225cfUL, 
+ 0x3b99acc8UL, 0xa77d1810UL, 0x6e639ce8UL, 0x7bbb3bdbUL, 0x097826cdUL, 
+ 0xf418596eUL, 0x01b79aecUL, 0xa89a4f83UL, 0x656e95e6UL, 0x7ee6ffaaUL, 
+ 0x08cfbc21UL, 0xe6e815efUL, 0xd99be7baUL, 0xce366f4aUL, 0xd4099feaUL, 
+ 0xd67cb029UL, 0xafb2a431UL, 0x31233f2aUL, 0x3094a5c6UL, 0xc066a235UL, 
+ 0x37bc4e74UL, 0xa6ca82fcUL, 0xb0d090e0UL, 0x15d8a733UL, 0x4a9804f1UL, 
+ 0xf7daec41UL, 0x0e50cd7fUL, 0x2ff69117UL, 0x8dd64d76UL, 0x4db0ef43UL, 
+ 0x544daaccUL, 0xdf0496e4UL, 0xe3b5d19eUL, 0x1b886a4cUL, 0xb81f2cc1UL, 
+ 0x7f516546UL, 0x04ea5e9dUL, 0x5d358c01UL, 0x737487faUL, 0x2e410bfbUL, 
+ 0x5a1d67b3UL, 0x52d2db92UL, 0x335610e9UL, 0x1347d66dUL, 0x8c61d79aUL, 
+ 0x7a0ca137UL, 0x8e14f859UL, 0x893c13ebUL, 0xee27a9ceUL, 0x35c961b7UL, 
+ 0xede51ce1UL, 0x3cb1477aUL, 0x59dfd29cUL, 0x3f73f255UL, 0x79ce1418UL, 
+ 0xbf37c773UL, 0xeacdf753UL, 0x5baafd5fUL, 0x146f3ddfUL, 0x86db4478UL, 
+ 0x81f3afcaUL, 0x3ec468b9UL, 0x2c342438UL, 0x5f40a3c2UL, 0x72c31d16UL, 
+ 0x0c25e2bcUL, 0x8b493c28UL, 0x41950dffUL, 0x7101a839UL, 0xdeb30c08UL, 
+ 0x9ce4b4d8UL, 0x90c15664UL, 0x6184cb7bUL, 0x70b632d5UL, 0x745c6c48UL, 
+ 0x4257b8d0UL}, 
+{0xa7f45150UL, 0x65417e53UL, 0xa4171ac3UL, 0x5e273a96UL, 0x6bab3bcbUL, 
+ 0x459d1ff1UL, 0x58faacabUL, 0x03e34b93UL, 0xfa302055UL, 0x6d76adf6UL, 
+ 0x76cc8891UL, 0x4c02f525UL, 0xd7e54ffcUL, 0xcb2ac5d7UL, 0x44352680UL, 
+ 0xa362b58fUL, 0x5ab1de49UL, 0x1bba2567UL, 0x0eea4598UL, 0xc0fe5de1UL, 
+ 0x752fc302UL, 0xf04c8112UL, 0x97468da3UL, 0xf9d36bc6UL, 0x5f8f03e7UL, 
+ 0x9c921595UL, 0x7a6dbfebUL, 0x595295daUL, 0x83bed42dUL, 0x217458d3UL, 
+ 0x69e04929UL, 0xc8c98e44UL, 0x89c2756aUL, 0x798ef478UL, 0x3e58996bUL, 
+ 0x71b927ddUL, 0x4fe1beb6UL, 0xad88f017UL, 0xac20c966UL, 0x3ace7db4UL, 
+ 0x4adf6318UL, 0x311ae582UL, 0x33519760UL, 0x7f536245UL, 0x7764b1e0UL, 
+ 0xae6bbb84UL, 0xa081fe1cUL, 0x2b08f994UL, 0x68487058UL, 0xfd458f19UL, 
+ 0x6cde9487UL, 0xf87b52b7UL, 0xd373ab23UL, 0x024b72e2UL, 0x8f1fe357UL, 
+ 0xab55662aUL, 0x28ebb207UL, 0xc2b52f03UL, 0x7bc5869aUL, 0x0837d3a5UL, 
+ 0x872830f2UL, 0xa5bf23b2UL, 0x6a0302baUL, 0x8216ed5cUL, 0x1ccf8a2bUL, 
+ 0xb479a792UL, 0xf207f3f0UL, 0xe2694ea1UL, 0xf4da65cdUL, 0xbe0506d5UL, 
+ 0x6234d11fUL, 0xfea6c48aUL, 0x532e349dUL, 0x55f3a2a0UL, 0xe18a0532UL, 
+ 0xebf6a475UL, 0xec830b39UL, 0xef6040aaUL, 0x9f715e06UL, 0x106ebd51UL, 
+ 0x8a213ef9UL, 0x06dd963dUL, 0x053eddaeUL, 0xbde64d46UL, 0x8d5491b5UL, 
+ 0x5dc47105UL, 0xd406046fUL, 0x155060ffUL, 0xfb981924UL, 0xe9bdd697UL, 
+ 0x434089ccUL, 0x9ed96777UL, 0x42e8b0bdUL, 0x8b890788UL, 0x5b19e738UL, 
+ 0xeec879dbUL, 0x0a7ca147UL, 0x0f427ce9UL, 0x1e84f8c9UL, 0x00000000UL, 
+ 0x86800983UL, 0xed2b3248UL, 0x70111eacUL, 0x725a6c4eUL, 0xff0efdfbUL, 
+ 0x38850f56UL, 0xd5ae3d1eUL, 0x392d3627UL, 0xd90f0a64UL, 0xa65c6821UL, 
+ 0x545b9bd1UL, 0x2e36243aUL, 0x670a0cb1UL, 0xe757930fUL, 0x96eeb4d2UL, 
+ 0x919b1b9eUL, 0xc5c0804fUL, 0x20dc61a2UL, 0x4b775a69UL, 0x1a121c16UL, 
+ 0xba93e20aUL, 0x2aa0c0e5UL, 0xe0223c43UL, 0x171b121dUL, 0x0d090e0bUL, 
+ 0xc78bf2adUL, 0xa8b62db9UL, 0xa91e14c8UL, 0x19f15785UL, 0x0775af4cUL, 
+ 0xdd99eebbUL, 0x607fa3fdUL, 0x2601f79fUL, 0xf5725cbcUL, 0x3b6644c5UL, 
+ 0x7efb5b34UL, 0x29438b76UL, 0xc623cbdcUL, 0xfcedb668UL, 0xf1e4b863UL, 
+ 0xdc31d7caUL, 0x85634210UL, 0x22971340UL, 0x11c68420UL, 0x244a857dUL, 
+ 0x3dbbd2f8UL, 0x32f9ae11UL, 0xa129c76dUL, 0x2f9e1d4bUL, 0x30b2dcf3UL, 
+ 0x52860decUL, 0xe3c177d0UL, 0x16b32b6cUL, 0xb970a999UL, 0x489411faUL, 
+ 0x64e94722UL, 0x8cfca8c4UL, 0x3ff0a01aUL, 0x2c7d56d8UL, 0x903322efUL, 
+ 0x4e4987c7UL, 0xd138d9c1UL, 0xa2ca8cfeUL, 0x0bd49836UL, 0x81f5a6cfUL, 
+ 0xde7aa528UL, 0x8eb7da26UL, 0xbfad3fa4UL, 0x9d3a2ce4UL, 0x9278500dUL, 
+ 0xcc5f6a9bUL, 0x467e5462UL, 0x138df6c2UL, 0xb8d890e8UL, 0xf7392e5eUL, 
+ 0xafc382f5UL, 0x805d9fbeUL, 0x93d0697cUL, 0x2dd56fa9UL, 0x1225cfb3UL, 
+ 0x99acc83bUL, 0x7d1810a7UL, 0x639ce86eUL, 0xbb3bdb7bUL, 0x7826cd09UL, 
+ 0x18596ef4UL, 0xb79aec01UL, 0x9a4f83a8UL, 0x6e95e665UL, 0xe6ffaa7eUL, 
+ 0xcfbc2108UL, 0xe815efe6UL, 0x9be7bad9UL, 0x366f4aceUL, 0x099fead4UL, 
+ 0x7cb029d6UL, 0xb2a431afUL, 0x233f2a31UL, 0x94a5c630UL, 0x66a235c0UL, 
+ 0xbc4e7437UL, 0xca82fca6UL, 0xd090e0b0UL, 0xd8a73315UL, 0x9804f14aUL, 
+ 0xdaec41f7UL, 0x50cd7f0eUL, 0xf691172fUL, 0xd64d768dUL, 0xb0ef434dUL, 
+ 0x4daacc54UL, 0x0496e4dfUL, 0xb5d19ee3UL, 0x886a4c1bUL, 0x1f2cc1b8UL, 
+ 0x5165467fUL, 0xea5e9d04UL, 0x358c015dUL, 0x7487fa73UL, 0x410bfb2eUL, 
+ 0x1d67b35aUL, 0xd2db9252UL, 0x5610e933UL, 0x47d66d13UL, 0x61d79a8cUL, 
+ 0x0ca1377aUL, 0x14f8598eUL, 0x3c13eb89UL, 0x27a9ceeeUL, 0xc961b735UL, 
+ 0xe51ce1edUL, 0xb1477a3cUL, 0xdfd29c59UL, 0x73f2553fUL, 0xce141879UL, 
+ 0x37c773bfUL, 0xcdf753eaUL, 0xaafd5f5bUL, 0x6f3ddf14UL, 0xdb447886UL, 
+ 0xf3afca81UL, 0xc468b93eUL, 0x3424382cUL, 0x40a3c25fUL, 0xc31d1672UL, 
+ 0x25e2bc0cUL, 0x493c288bUL, 0x950dff41UL, 0x01a83971UL, 0xb30c08deUL, 
+ 0xe4b4d89cUL, 0xc1566490UL, 0x84cb7b61UL, 0xb632d570UL, 0x5c6c4874UL, 
+ 0x57b8d042UL}, 
+{0xf45150a7UL, 0x417e5365UL, 0x171ac3a4UL, 0x273a965eUL, 0xab3bcb6bUL, 
+ 0x9d1ff145UL, 0xfaacab58UL, 0xe34b9303UL, 0x302055faUL, 0x76adf66dUL, 
+ 0xcc889176UL, 0x02f5254cUL, 0xe54ffcd7UL, 0x2ac5d7cbUL, 0x35268044UL, 
+ 0x62b58fa3UL, 0xb1de495aUL, 0xba25671bUL, 0xea45980eUL, 0xfe5de1c0UL, 
+ 0x2fc30275UL, 0x4c8112f0UL, 0x468da397UL, 0xd36bc6f9UL, 0x8f03e75fUL, 
+ 0x9215959cUL, 0x6dbfeb7aUL, 0x5295da59UL, 0xbed42d83UL, 0x7458d321UL, 
+ 0xe0492969UL, 0xc98e44c8UL, 0xc2756a89UL, 0x8ef47879UL, 0x58996b3eUL, 
+ 0xb927dd71UL, 0xe1beb64fUL, 0x88f017adUL, 0x20c966acUL, 0xce7db43aUL, 
+ 0xdf63184aUL, 0x1ae58231UL, 0x51976033UL, 0x5362457fUL, 0x64b1e077UL, 
+ 0x6bbb84aeUL, 0x81fe1ca0UL, 0x08f9942bUL, 0x48705868UL, 0x458f19fdUL, 
+ 0xde94876cUL, 0x7b52b7f8UL, 0x73ab23d3UL, 0x4b72e202UL, 0x1fe3578fUL, 
+ 0x55662aabUL, 0xebb20728UL, 0xb52f03c2UL, 0xc5869a7bUL, 0x37d3a508UL, 
+ 0x2830f287UL, 0xbf23b2a5UL, 0x0302ba6aUL, 0x16ed5c82UL, 0xcf8a2b1cUL, 
+ 0x79a792b4UL, 0x07f3f0f2UL, 0x694ea1e2UL, 0xda65cdf4UL, 0x0506d5beUL, 
+ 0x34d11f62UL, 0xa6c48afeUL, 0x2e349d53UL, 0xf3a2a055UL, 0x8a0532e1UL, 
+ 0xf6a475ebUL, 0x830b39ecUL, 0x6040aaefUL, 0x715e069fUL, 0x6ebd5110UL, 
+ 0x213ef98aUL, 0xdd963d06UL, 0x3eddae05UL, 0xe64d46bdUL, 0x5491b58dUL, 
+ 0xc471055dUL, 0x06046fd4UL, 0x5060ff15UL, 0x981924fbUL, 0xbdd697e9UL, 
+ 0x4089cc43UL, 0xd967779eUL, 0xe8b0bd42UL, 0x8907888bUL, 0x19e7385bUL, 
+ 0xc879dbeeUL, 0x7ca1470aUL, 0x427ce90fUL, 0x84f8c91eUL, 0x00000000UL, 
+ 0x80098386UL, 0x2b3248edUL, 0x111eac70UL, 0x5a6c4e72UL, 0x0efdfbffUL, 
+ 0x850f5638UL, 0xae3d1ed5UL, 0x2d362739UL, 0x0f0a64d9UL, 0x5c6821a6UL, 
+ 0x5b9bd154UL, 0x36243a2eUL, 0x0a0cb167UL, 0x57930fe7UL, 0xeeb4d296UL, 
+ 0x9b1b9e91UL, 0xc0804fc5UL, 0xdc61a220UL, 0x775a694bUL, 0x121c161aUL, 
+ 0x93e20abaUL, 0xa0c0e52aUL, 0x223c43e0UL, 0x1b121d17UL, 0x090e0b0dUL, 
+ 0x8bf2adc7UL, 0xb62db9a8UL, 0x1e14c8a9UL, 0xf1578519UL, 0x75af4c07UL, 
+ 0x99eebbddUL, 0x7fa3fd60UL, 0x01f79f26UL, 0x725cbcf5UL, 0x6644c53bUL, 
+ 0xfb5b347eUL, 0x438b7629UL, 0x23cbdcc6UL, 0xedb668fcUL, 0xe4b863f1UL, 
+ 0x31d7cadcUL, 0x63421085UL, 0x97134022UL, 0xc6842011UL, 0x4a857d24UL, 
+ 0xbbd2f83dUL, 0xf9ae1132UL, 0x29c76da1UL, 0x9e1d4b2fUL, 0xb2dcf330UL, 
+ 0x860dec52UL, 0xc177d0e3UL, 0xb32b6c16UL, 0x70a999b9UL, 0x9411fa48UL, 
+ 0xe9472264UL, 0xfca8c48cUL, 0xf0a01a3fUL, 0x7d56d82cUL, 0x3322ef90UL, 
+ 0x4987c74eUL, 0x38d9c1d1UL, 0xca8cfea2UL, 0xd498360bUL, 0xf5a6cf81UL, 
+ 0x7aa528deUL, 0xb7da268eUL, 0xad3fa4bfUL, 0x3a2ce49dUL, 0x78500d92UL, 
+ 0x5f6a9bccUL, 0x7e546246UL, 0x8df6c213UL, 0xd890e8b8UL, 0x392e5ef7UL, 
+ 0xc382f5afUL, 0x5d9fbe80UL, 0xd0697c93UL, 0xd56fa92dUL, 0x25cfb312UL, 
+ 0xacc83b99UL, 0x1810a77dUL, 0x9ce86e63UL, 0x3bdb7bbbUL, 0x26cd0978UL, 
+ 0x596ef418UL, 0x9aec01b7UL, 0x4f83a89aUL, 0x95e6656eUL, 0xffaa7ee6UL, 
+ 0xbc2108cfUL, 0x15efe6e8UL, 0xe7bad99bUL, 0x6f4ace36UL, 0x9fead409UL, 
+ 0xb029d67cUL, 0xa431afb2UL, 0x3f2a3123UL, 0xa5c63094UL, 0xa235c066UL, 
+ 0x4e7437bcUL, 0x82fca6caUL, 0x90e0b0d0UL, 0xa73315d8UL, 0x04f14a98UL, 
+ 0xec41f7daUL, 0xcd7f0e50UL, 0x91172ff6UL, 0x4d768dd6UL, 0xef434db0UL, 
+ 0xaacc544dUL, 0x96e4df04UL, 0xd19ee3b5UL, 0x6a4c1b88UL, 0x2cc1b81fUL, 
+ 0x65467f51UL, 0x5e9d04eaUL, 0x8c015d35UL, 0x87fa7374UL, 0x0bfb2e41UL, 
+ 0x67b35a1dUL, 0xdb9252d2UL, 0x10e93356UL, 0xd66d1347UL, 0xd79a8c61UL, 
+ 0xa1377a0cUL, 0xf8598e14UL, 0x13eb893cUL, 0xa9ceee27UL, 0x61b735c9UL, 
+ 0x1ce1ede5UL, 0x477a3cb1UL, 0xd29c59dfUL, 0xf2553f73UL, 0x141879ceUL, 
+ 0xc773bf37UL, 0xf753eacdUL, 0xfd5f5baaUL, 0x3ddf146fUL, 0x447886dbUL, 
+ 0xafca81f3UL, 0x68b93ec4UL, 0x24382c34UL, 0xa3c25f40UL, 0x1d1672c3UL, 
+ 0xe2bc0c25UL, 0x3c288b49UL, 0x0dff4195UL, 0xa8397101UL, 0x0c08deb3UL, 
+ 0xb4d89ce4UL, 0x566490c1UL, 0xcb7b6184UL, 0x32d570b6UL, 0x6c48745cUL, 
+ 0xb8d04257UL}, 
+{0x5150a7f4UL, 0x7e536541UL, 0x1ac3a417UL, 0x3a965e27UL, 0x3bcb6babUL, 
+ 0x1ff1459dUL, 0xacab58faUL, 0x4b9303e3UL, 0x2055fa30UL, 0xadf66d76UL, 
+ 0x889176ccUL, 0xf5254c02UL, 0x4ffcd7e5UL, 0xc5d7cb2aUL, 0x26804435UL, 
+ 0xb58fa362UL, 0xde495ab1UL, 0x25671bbaUL, 0x45980eeaUL, 0x5de1c0feUL, 
+ 0xc302752fUL, 0x8112f04cUL, 0x8da39746UL, 0x6bc6f9d3UL, 0x03e75f8fUL, 
+ 0x15959c92UL, 0xbfeb7a6dUL, 0x95da5952UL, 0xd42d83beUL, 0x58d32174UL, 
+ 0x492969e0UL, 0x8e44c8c9UL, 0x756a89c2UL, 0xf478798eUL, 0x996b3e58UL, 
+ 0x27dd71b9UL, 0xbeb64fe1UL, 0xf017ad88UL, 0xc966ac20UL, 0x7db43aceUL, 
+ 0x63184adfUL, 0xe582311aUL, 0x97603351UL, 0x62457f53UL, 0xb1e07764UL, 
+ 0xbb84ae6bUL, 0xfe1ca081UL, 0xf9942b08UL, 0x70586848UL, 0x8f19fd45UL, 
+ 0x94876cdeUL, 0x52b7f87bUL, 0xab23d373UL, 0x72e2024bUL, 0xe3578f1fUL, 
+ 0x662aab55UL, 0xb20728ebUL, 0x2f03c2b5UL, 0x869a7bc5UL, 0xd3a50837UL, 
+ 0x30f28728UL, 0x23b2a5bfUL, 0x02ba6a03UL, 0xed5c8216UL, 0x8a2b1ccfUL, 
+ 0xa792b479UL, 0xf3f0f207UL, 0x4ea1e269UL, 0x65cdf4daUL, 0x06d5be05UL, 
+ 0xd11f6234UL, 0xc48afea6UL, 0x349d532eUL, 0xa2a055f3UL, 0x0532e18aUL, 
+ 0xa475ebf6UL, 0x0b39ec83UL, 0x40aaef60UL, 0x5e069f71UL, 0xbd51106eUL, 
+ 0x3ef98a21UL, 0x963d06ddUL, 0xddae053eUL, 0x4d46bde6UL, 0x91b58d54UL, 
+ 0x71055dc4UL, 0x046fd406UL, 0x60ff1550UL, 0x1924fb98UL, 0xd697e9bdUL, 
+ 0x89cc4340UL, 0x67779ed9UL, 0xb0bd42e8UL, 0x07888b89UL, 0xe7385b19UL, 
+ 0x79dbeec8UL, 0xa1470a7cUL, 0x7ce90f42UL, 0xf8c91e84UL, 0x00000000UL, 
+ 0x09838680UL, 0x3248ed2bUL, 0x1eac7011UL, 0x6c4e725aUL, 0xfdfbff0eUL, 
+ 0x0f563885UL, 0x3d1ed5aeUL, 0x3627392dUL, 0x0a64d90fUL, 0x6821a65cUL, 
+ 0x9bd1545bUL, 0x243a2e36UL, 0x0cb1670aUL, 0x930fe757UL, 0xb4d296eeUL, 
+ 0x1b9e919bUL, 0x804fc5c0UL, 0x61a220dcUL, 0x5a694b77UL, 0x1c161a12UL, 
+ 0xe20aba93UL, 0xc0e52aa0UL, 0x3c43e022UL, 0x121d171bUL, 0x0e0b0d09UL, 
+ 0xf2adc78bUL, 0x2db9a8b6UL, 0x14c8a91eUL, 0x578519f1UL, 0xaf4c0775UL, 
+ 0xeebbdd99UL, 0xa3fd607fUL, 0xf79f2601UL, 0x5cbcf572UL, 0x44c53b66UL, 
+ 0x5b347efbUL, 0x8b762943UL, 0xcbdcc623UL, 0xb668fcedUL, 0xb863f1e4UL, 
+ 0xd7cadc31UL, 0x42108563UL, 0x13402297UL, 0x842011c6UL, 0x857d244aUL, 
+ 0xd2f83dbbUL, 0xae1132f9UL, 0xc76da129UL, 0x1d4b2f9eUL, 0xdcf330b2UL, 
+ 0x0dec5286UL, 0x77d0e3c1UL, 0x2b6c16b3UL, 0xa999b970UL, 0x11fa4894UL, 
+ 0x472264e9UL, 0xa8c48cfcUL, 0xa01a3ff0UL, 0x56d82c7dUL, 0x22ef9033UL, 
+ 0x87c74e49UL, 0xd9c1d138UL, 0x8cfea2caUL, 0x98360bd4UL, 0xa6cf81f5UL, 
+ 0xa528de7aUL, 0xda268eb7UL, 0x3fa4bfadUL, 0x2ce49d3aUL, 0x500d9278UL, 
+ 0x6a9bcc5fUL, 0x5462467eUL, 0xf6c2138dUL, 0x90e8b8d8UL, 0x2e5ef739UL, 
+ 0x82f5afc3UL, 0x9fbe805dUL, 0x697c93d0UL, 0x6fa92dd5UL, 0xcfb31225UL, 
+ 0xc83b99acUL, 0x10a77d18UL, 0xe86e639cUL, 0xdb7bbb3bUL, 0xcd097826UL, 
+ 0x6ef41859UL, 0xec01b79aUL, 0x83a89a4fUL, 0xe6656e95UL, 0xaa7ee6ffUL, 
+ 0x2108cfbcUL, 0xefe6e815UL, 0xbad99be7UL, 0x4ace366fUL, 0xead4099fUL, 
+ 0x29d67cb0UL, 0x31afb2a4UL, 0x2a31233fUL, 0xc63094a5UL, 0x35c066a2UL, 
+ 0x7437bc4eUL, 0xfca6ca82UL, 0xe0b0d090UL, 0x3315d8a7UL, 0xf14a9804UL, 
+ 0x41f7daecUL, 0x7f0e50cdUL, 0x172ff691UL, 0x768dd64dUL, 0x434db0efUL, 
+ 0xcc544daaUL, 0xe4df0496UL, 0x9ee3b5d1UL, 0x4c1b886aUL, 0xc1b81f2cUL, 
+ 0x467f5165UL, 0x9d04ea5eUL, 0x015d358cUL, 0xfa737487UL, 0xfb2e410bUL, 
+ 0xb35a1d67UL, 0x9252d2dbUL, 0xe9335610UL, 0x6d1347d6UL, 0x9a8c61d7UL, 
+ 0x377a0ca1UL, 0x598e14f8UL, 0xeb893c13UL, 0xceee27a9UL, 0xb735c961UL, 
+ 0xe1ede51cUL, 0x7a3cb147UL, 0x9c59dfd2UL, 0x553f73f2UL, 0x1879ce14UL, 
+ 0x73bf37c7UL, 0x53eacdf7UL, 0x5f5baafdUL, 0xdf146f3dUL, 0x7886db44UL, 
+ 0xca81f3afUL, 0xb93ec468UL, 0x382c3424UL, 0xc25f40a3UL, 0x1672c31dUL, 
+ 0xbc0c25e2UL, 0x288b493cUL, 0xff41950dUL, 0x397101a8UL, 0x08deb30cUL, 
+ 0xd89ce4b4UL, 0x6490c156UL, 0x7b6184cbUL, 0xd570b632UL, 0x48745c6cUL, 
+ 0xd04257b8UL}
+ };
+
+static const unsigned long fl_tab[4][256] = {
+{0x00000063UL, 0x0000007cUL, 0x00000077UL, 0x0000007bUL, 0x000000f2UL, 
+ 0x0000006bUL, 0x0000006fUL, 0x000000c5UL, 0x00000030UL, 0x00000001UL, 
+ 0x00000067UL, 0x0000002bUL, 0x000000feUL, 0x000000d7UL, 0x000000abUL, 
+ 0x00000076UL, 0x000000caUL, 0x00000082UL, 0x000000c9UL, 0x0000007dUL, 
+ 0x000000faUL, 0x00000059UL, 0x00000047UL, 0x000000f0UL, 0x000000adUL, 
+ 0x000000d4UL, 0x000000a2UL, 0x000000afUL, 0x0000009cUL, 0x000000a4UL, 
+ 0x00000072UL, 0x000000c0UL, 0x000000b7UL, 0x000000fdUL, 0x00000093UL, 
+ 0x00000026UL, 0x00000036UL, 0x0000003fUL, 0x000000f7UL, 0x000000ccUL, 
+ 0x00000034UL, 0x000000a5UL, 0x000000e5UL, 0x000000f1UL, 0x00000071UL, 
+ 0x000000d8UL, 0x00000031UL, 0x00000015UL, 0x00000004UL, 0x000000c7UL, 
+ 0x00000023UL, 0x000000c3UL, 0x00000018UL, 0x00000096UL, 0x00000005UL, 
+ 0x0000009aUL, 0x00000007UL, 0x00000012UL, 0x00000080UL, 0x000000e2UL, 
+ 0x000000ebUL, 0x00000027UL, 0x000000b2UL, 0x00000075UL, 0x00000009UL, 
+ 0x00000083UL, 0x0000002cUL, 0x0000001aUL, 0x0000001bUL, 0x0000006eUL, 
+ 0x0000005aUL, 0x000000a0UL, 0x00000052UL, 0x0000003bUL, 0x000000d6UL, 
+ 0x000000b3UL, 0x00000029UL, 0x000000e3UL, 0x0000002fUL, 0x00000084UL, 
+ 0x00000053UL, 0x000000d1UL, 0x00000000UL, 0x000000edUL, 0x00000020UL, 
+ 0x000000fcUL, 0x000000b1UL, 0x0000005bUL, 0x0000006aUL, 0x000000cbUL, 
+ 0x000000beUL, 0x00000039UL, 0x0000004aUL, 0x0000004cUL, 0x00000058UL, 
+ 0x000000cfUL, 0x000000d0UL, 0x000000efUL, 0x000000aaUL, 0x000000fbUL, 
+ 0x00000043UL, 0x0000004dUL, 0x00000033UL, 0x00000085UL, 0x00000045UL, 
+ 0x000000f9UL, 0x00000002UL, 0x0000007fUL, 0x00000050UL, 0x0000003cUL, 
+ 0x0000009fUL, 0x000000a8UL, 0x00000051UL, 0x000000a3UL, 0x00000040UL, 
+ 0x0000008fUL, 0x00000092UL, 0x0000009dUL, 0x00000038UL, 0x000000f5UL, 
+ 0x000000bcUL, 0x000000b6UL, 0x000000daUL, 0x00000021UL, 0x00000010UL, 
+ 0x000000ffUL, 0x000000f3UL, 0x000000d2UL, 0x000000cdUL, 0x0000000cUL, 
+ 0x00000013UL, 0x000000ecUL, 0x0000005fUL, 0x00000097UL, 0x00000044UL, 
+ 0x00000017UL, 0x000000c4UL, 0x000000a7UL, 0x0000007eUL, 0x0000003dUL, 
+ 0x00000064UL, 0x0000005dUL, 0x00000019UL, 0x00000073UL, 0x00000060UL, 
+ 0x00000081UL, 0x0000004fUL, 0x000000dcUL, 0x00000022UL, 0x0000002aUL, 
+ 0x00000090UL, 0x00000088UL, 0x00000046UL, 0x000000eeUL, 0x000000b8UL, 
+ 0x00000014UL, 0x000000deUL, 0x0000005eUL, 0x0000000bUL, 0x000000dbUL, 
+ 0x000000e0UL, 0x00000032UL, 0x0000003aUL, 0x0000000aUL, 0x00000049UL, 
+ 0x00000006UL, 0x00000024UL, 0x0000005cUL, 0x000000c2UL, 0x000000d3UL, 
+ 0x000000acUL, 0x00000062UL, 0x00000091UL, 0x00000095UL, 0x000000e4UL, 
+ 0x00000079UL, 0x000000e7UL, 0x000000c8UL, 0x00000037UL, 0x0000006dUL, 
+ 0x0000008dUL, 0x000000d5UL, 0x0000004eUL, 0x000000a9UL, 0x0000006cUL, 
+ 0x00000056UL, 0x000000f4UL, 0x000000eaUL, 0x00000065UL, 0x0000007aUL, 
+ 0x000000aeUL, 0x00000008UL, 0x000000baUL, 0x00000078UL, 0x00000025UL, 
+ 0x0000002eUL, 0x0000001cUL, 0x000000a6UL, 0x000000b4UL, 0x000000c6UL, 
+ 0x000000e8UL, 0x000000ddUL, 0x00000074UL, 0x0000001fUL, 0x0000004bUL, 
+ 0x000000bdUL, 0x0000008bUL, 0x0000008aUL, 0x00000070UL, 0x0000003eUL, 
+ 0x000000b5UL, 0x00000066UL, 0x00000048UL, 0x00000003UL, 0x000000f6UL, 
+ 0x0000000eUL, 0x00000061UL, 0x00000035UL, 0x00000057UL, 0x000000b9UL, 
+ 0x00000086UL, 0x000000c1UL, 0x0000001dUL, 0x0000009eUL, 0x000000e1UL, 
+ 0x000000f8UL, 0x00000098UL, 0x00000011UL, 0x00000069UL, 0x000000d9UL, 
+ 0x0000008eUL, 0x00000094UL, 0x0000009bUL, 0x0000001eUL, 0x00000087UL, 
+ 0x000000e9UL, 0x000000ceUL, 0x00000055UL, 0x00000028UL, 0x000000dfUL, 
+ 0x0000008cUL, 0x000000a1UL, 0x00000089UL, 0x0000000dUL, 0x000000bfUL, 
+ 0x000000e6UL, 0x00000042UL, 0x00000068UL, 0x00000041UL, 0x00000099UL, 
+ 0x0000002dUL, 0x0000000fUL, 0x000000b0UL, 0x00000054UL, 0x000000bbUL, 
+ 0x00000016UL}, 
+{0x00006300UL, 0x00007c00UL, 0x00007700UL, 0x00007b00UL, 0x0000f200UL, 
+ 0x00006b00UL, 0x00006f00UL, 0x0000c500UL, 0x00003000UL, 0x00000100UL, 
+ 0x00006700UL, 0x00002b00UL, 0x0000fe00UL, 0x0000d700UL, 0x0000ab00UL, 
+ 0x00007600UL, 0x0000ca00UL, 0x00008200UL, 0x0000c900UL, 0x00007d00UL, 
+ 0x0000fa00UL, 0x00005900UL, 0x00004700UL, 0x0000f000UL, 0x0000ad00UL, 
+ 0x0000d400UL, 0x0000a200UL, 0x0000af00UL, 0x00009c00UL, 0x0000a400UL, 
+ 0x00007200UL, 0x0000c000UL, 0x0000b700UL, 0x0000fd00UL, 0x00009300UL, 
+ 0x00002600UL, 0x00003600UL, 0x00003f00UL, 0x0000f700UL, 0x0000cc00UL, 
+ 0x00003400UL, 0x0000a500UL, 0x0000e500UL, 0x0000f100UL, 0x00007100UL, 
+ 0x0000d800UL, 0x00003100UL, 0x00001500UL, 0x00000400UL, 0x0000c700UL, 
+ 0x00002300UL, 0x0000c300UL, 0x00001800UL, 0x00009600UL, 0x00000500UL, 
+ 0x00009a00UL, 0x00000700UL, 0x00001200UL, 0x00008000UL, 0x0000e200UL, 
+ 0x0000eb00UL, 0x00002700UL, 0x0000b200UL, 0x00007500UL, 0x00000900UL, 
+ 0x00008300UL, 0x00002c00UL, 0x00001a00UL, 0x00001b00UL, 0x00006e00UL, 
+ 0x00005a00UL, 0x0000a000UL, 0x00005200UL, 0x00003b00UL, 0x0000d600UL, 
+ 0x0000b300UL, 0x00002900UL, 0x0000e300UL, 0x00002f00UL, 0x00008400UL, 
+ 0x00005300UL, 0x0000d100UL, 0x00000000UL, 0x0000ed00UL, 0x00002000UL, 
+ 0x0000fc00UL, 0x0000b100UL, 0x00005b00UL, 0x00006a00UL, 0x0000cb00UL, 
+ 0x0000be00UL, 0x00003900UL, 0x00004a00UL, 0x00004c00UL, 0x00005800UL, 
+ 0x0000cf00UL, 0x0000d000UL, 0x0000ef00UL, 0x0000aa00UL, 0x0000fb00UL, 
+ 0x00004300UL, 0x00004d00UL, 0x00003300UL, 0x00008500UL, 0x00004500UL, 
+ 0x0000f900UL, 0x00000200UL, 0x00007f00UL, 0x00005000UL, 0x00003c00UL, 
+ 0x00009f00UL, 0x0000a800UL, 0x00005100UL, 0x0000a300UL, 0x00004000UL, 
+ 0x00008f00UL, 0x00009200UL, 0x00009d00UL, 0x00003800UL, 0x0000f500UL, 
+ 0x0000bc00UL, 0x0000b600UL, 0x0000da00UL, 0x00002100UL, 0x00001000UL, 
+ 0x0000ff00UL, 0x0000f300UL, 0x0000d200UL, 0x0000cd00UL, 0x00000c00UL, 
+ 0x00001300UL, 0x0000ec00UL, 0x00005f00UL, 0x00009700UL, 0x00004400UL, 
+ 0x00001700UL, 0x0000c400UL, 0x0000a700UL, 0x00007e00UL, 0x00003d00UL, 
+ 0x00006400UL, 0x00005d00UL, 0x00001900UL, 0x00007300UL, 0x00006000UL, 
+ 0x00008100UL, 0x00004f00UL, 0x0000dc00UL, 0x00002200UL, 0x00002a00UL, 
+ 0x00009000UL, 0x00008800UL, 0x00004600UL, 0x0000ee00UL, 0x0000b800UL, 
+ 0x00001400UL, 0x0000de00UL, 0x00005e00UL, 0x00000b00UL, 0x0000db00UL, 
+ 0x0000e000UL, 0x00003200UL, 0x00003a00UL, 0x00000a00UL, 0x00004900UL, 
+ 0x00000600UL, 0x00002400UL, 0x00005c00UL, 0x0000c200UL, 0x0000d300UL, 
+ 0x0000ac00UL, 0x00006200UL, 0x00009100UL, 0x00009500UL, 0x0000e400UL, 
+ 0x00007900UL, 0x0000e700UL, 0x0000c800UL, 0x00003700UL, 0x00006d00UL, 
+ 0x00008d00UL, 0x0000d500UL, 0x00004e00UL, 0x0000a900UL, 0x00006c00UL, 
+ 0x00005600UL, 0x0000f400UL, 0x0000ea00UL, 0x00006500UL, 0x00007a00UL, 
+ 0x0000ae00UL, 0x00000800UL, 0x0000ba00UL, 0x00007800UL, 0x00002500UL, 
+ 0x00002e00UL, 0x00001c00UL, 0x0000a600UL, 0x0000b400UL, 0x0000c600UL, 
+ 0x0000e800UL, 0x0000dd00UL, 0x00007400UL, 0x00001f00UL, 0x00004b00UL, 
+ 0x0000bd00UL, 0x00008b00UL, 0x00008a00UL, 0x00007000UL, 0x00003e00UL, 
+ 0x0000b500UL, 0x00006600UL, 0x00004800UL, 0x00000300UL, 0x0000f600UL, 
+ 0x00000e00UL, 0x00006100UL, 0x00003500UL, 0x00005700UL, 0x0000b900UL, 
+ 0x00008600UL, 0x0000c100UL, 0x00001d00UL, 0x00009e00UL, 0x0000e100UL, 
+ 0x0000f800UL, 0x00009800UL, 0x00001100UL, 0x00006900UL, 0x0000d900UL, 
+ 0x00008e00UL, 0x00009400UL, 0x00009b00UL, 0x00001e00UL, 0x00008700UL, 
+ 0x0000e900UL, 0x0000ce00UL, 0x00005500UL, 0x00002800UL, 0x0000df00UL, 
+ 0x00008c00UL, 0x0000a100UL, 0x00008900UL, 0x00000d00UL, 0x0000bf00UL, 
+ 0x0000e600UL, 0x00004200UL, 0x00006800UL, 0x00004100UL, 0x00009900UL, 
+ 0x00002d00UL, 0x00000f00UL, 0x0000b000UL, 0x00005400UL, 0x0000bb00UL, 
+ 0x00001600UL}, 
+{0x00630000UL, 0x007c0000UL, 0x00770000UL, 0x007b0000UL, 0x00f20000UL, 
+ 0x006b0000UL, 0x006f0000UL, 0x00c50000UL, 0x00300000UL, 0x00010000UL, 
+ 0x00670000UL, 0x002b0000UL, 0x00fe0000UL, 0x00d70000UL, 0x00ab0000UL, 
+ 0x00760000UL, 0x00ca0000UL, 0x00820000UL, 0x00c90000UL, 0x007d0000UL, 
+ 0x00fa0000UL, 0x00590000UL, 0x00470000UL, 0x00f00000UL, 0x00ad0000UL, 
+ 0x00d40000UL, 0x00a20000UL, 0x00af0000UL, 0x009c0000UL, 0x00a40000UL, 
+ 0x00720000UL, 0x00c00000UL, 0x00b70000UL, 0x00fd0000UL, 0x00930000UL, 
+ 0x00260000UL, 0x00360000UL, 0x003f0000UL, 0x00f70000UL, 0x00cc0000UL, 
+ 0x00340000UL, 0x00a50000UL, 0x00e50000UL, 0x00f10000UL, 0x00710000UL, 
+ 0x00d80000UL, 0x00310000UL, 0x00150000UL, 0x00040000UL, 0x00c70000UL, 
+ 0x00230000UL, 0x00c30000UL, 0x00180000UL, 0x00960000UL, 0x00050000UL, 
+ 0x009a0000UL, 0x00070000UL, 0x00120000UL, 0x00800000UL, 0x00e20000UL, 
+ 0x00eb0000UL, 0x00270000UL, 0x00b20000UL, 0x00750000UL, 0x00090000UL, 
+ 0x00830000UL, 0x002c0000UL, 0x001a0000UL, 0x001b0000UL, 0x006e0000UL, 
+ 0x005a0000UL, 0x00a00000UL, 0x00520000UL, 0x003b0000UL, 0x00d60000UL, 
+ 0x00b30000UL, 0x00290000UL, 0x00e30000UL, 0x002f0000UL, 0x00840000UL, 
+ 0x00530000UL, 0x00d10000UL, 0x00000000UL, 0x00ed0000UL, 0x00200000UL, 
+ 0x00fc0000UL, 0x00b10000UL, 0x005b0000UL, 0x006a0000UL, 0x00cb0000UL, 
+ 0x00be0000UL, 0x00390000UL, 0x004a0000UL, 0x004c0000UL, 0x00580000UL, 
+ 0x00cf0000UL, 0x00d00000UL, 0x00ef0000UL, 0x00aa0000UL, 0x00fb0000UL, 
+ 0x00430000UL, 0x004d0000UL, 0x00330000UL, 0x00850000UL, 0x00450000UL, 
+ 0x00f90000UL, 0x00020000UL, 0x007f0000UL, 0x00500000UL, 0x003c0000UL, 
+ 0x009f0000UL, 0x00a80000UL, 0x00510000UL, 0x00a30000UL, 0x00400000UL, 
+ 0x008f0000UL, 0x00920000UL, 0x009d0000UL, 0x00380000UL, 0x00f50000UL, 
+ 0x00bc0000UL, 0x00b60000UL, 0x00da0000UL, 0x00210000UL, 0x00100000UL, 
+ 0x00ff0000UL, 0x00f30000UL, 0x00d20000UL, 0x00cd0000UL, 0x000c0000UL, 
+ 0x00130000UL, 0x00ec0000UL, 0x005f0000UL, 0x00970000UL, 0x00440000UL, 
+ 0x00170000UL, 0x00c40000UL, 0x00a70000UL, 0x007e0000UL, 0x003d0000UL, 
+ 0x00640000UL, 0x005d0000UL, 0x00190000UL, 0x00730000UL, 0x00600000UL, 
+ 0x00810000UL, 0x004f0000UL, 0x00dc0000UL, 0x00220000UL, 0x002a0000UL, 
+ 0x00900000UL, 0x00880000UL, 0x00460000UL, 0x00ee0000UL, 0x00b80000UL, 
+ 0x00140000UL, 0x00de0000UL, 0x005e0000UL, 0x000b0000UL, 0x00db0000UL, 
+ 0x00e00000UL, 0x00320000UL, 0x003a0000UL, 0x000a0000UL, 0x00490000UL, 
+ 0x00060000UL, 0x00240000UL, 0x005c0000UL, 0x00c20000UL, 0x00d30000UL, 
+ 0x00ac0000UL, 0x00620000UL, 0x00910000UL, 0x00950000UL, 0x00e40000UL, 
+ 0x00790000UL, 0x00e70000UL, 0x00c80000UL, 0x00370000UL, 0x006d0000UL, 
+ 0x008d0000UL, 0x00d50000UL, 0x004e0000UL, 0x00a90000UL, 0x006c0000UL, 
+ 0x00560000UL, 0x00f40000UL, 0x00ea0000UL, 0x00650000UL, 0x007a0000UL, 
+ 0x00ae0000UL, 0x00080000UL, 0x00ba0000UL, 0x00780000UL, 0x00250000UL, 
+ 0x002e0000UL, 0x001c0000UL, 0x00a60000UL, 0x00b40000UL, 0x00c60000UL, 
+ 0x00e80000UL, 0x00dd0000UL, 0x00740000UL, 0x001f0000UL, 0x004b0000UL, 
+ 0x00bd0000UL, 0x008b0000UL, 0x008a0000UL, 0x00700000UL, 0x003e0000UL, 
+ 0x00b50000UL, 0x00660000UL, 0x00480000UL, 0x00030000UL, 0x00f60000UL, 
+ 0x000e0000UL, 0x00610000UL, 0x00350000UL, 0x00570000UL, 0x00b90000UL, 
+ 0x00860000UL, 0x00c10000UL, 0x001d0000UL, 0x009e0000UL, 0x00e10000UL, 
+ 0x00f80000UL, 0x00980000UL, 0x00110000UL, 0x00690000UL, 0x00d90000UL, 
+ 0x008e0000UL, 0x00940000UL, 0x009b0000UL, 0x001e0000UL, 0x00870000UL, 
+ 0x00e90000UL, 0x00ce0000UL, 0x00550000UL, 0x00280000UL, 0x00df0000UL, 
+ 0x008c0000UL, 0x00a10000UL, 0x00890000UL, 0x000d0000UL, 0x00bf0000UL, 
+ 0x00e60000UL, 0x00420000UL, 0x00680000UL, 0x00410000UL, 0x00990000UL, 
+ 0x002d0000UL, 0x000f0000UL, 0x00b00000UL, 0x00540000UL, 0x00bb0000UL, 
+ 0x00160000UL}, 
+{0x63000000UL, 0x7c000000UL, 0x77000000UL, 0x7b000000UL, 0xf2000000UL, 
+ 0x6b000000UL, 0x6f000000UL, 0xc5000000UL, 0x30000000UL, 0x01000000UL, 
+ 0x67000000UL, 0x2b000000UL, 0xfe000000UL, 0xd7000000UL, 0xab000000UL, 
+ 0x76000000UL, 0xca000000UL, 0x82000000UL, 0xc9000000UL, 0x7d000000UL, 
+ 0xfa000000UL, 0x59000000UL, 0x47000000UL, 0xf0000000UL, 0xad000000UL, 
+ 0xd4000000UL, 0xa2000000UL, 0xaf000000UL, 0x9c000000UL, 0xa4000000UL, 
+ 0x72000000UL, 0xc0000000UL, 0xb7000000UL, 0xfd000000UL, 0x93000000UL, 
+ 0x26000000UL, 0x36000000UL, 0x3f000000UL, 0xf7000000UL, 0xcc000000UL, 
+ 0x34000000UL, 0xa5000000UL, 0xe5000000UL, 0xf1000000UL, 0x71000000UL, 
+ 0xd8000000UL, 0x31000000UL, 0x15000000UL, 0x04000000UL, 0xc7000000UL, 
+ 0x23000000UL, 0xc3000000UL, 0x18000000UL, 0x96000000UL, 0x05000000UL, 
+ 0x9a000000UL, 0x07000000UL, 0x12000000UL, 0x80000000UL, 0xe2000000UL, 
+ 0xeb000000UL, 0x27000000UL, 0xb2000000UL, 0x75000000UL, 0x09000000UL, 
+ 0x83000000UL, 0x2c000000UL, 0x1a000000UL, 0x1b000000UL, 0x6e000000UL, 
+ 0x5a000000UL, 0xa0000000UL, 0x52000000UL, 0x3b000000UL, 0xd6000000UL, 
+ 0xb3000000UL, 0x29000000UL, 0xe3000000UL, 0x2f000000UL, 0x84000000UL, 
+ 0x53000000UL, 0xd1000000UL, 0x00000000UL, 0xed000000UL, 0x20000000UL, 
+ 0xfc000000UL, 0xb1000000UL, 0x5b000000UL, 0x6a000000UL, 0xcb000000UL, 
+ 0xbe000000UL, 0x39000000UL, 0x4a000000UL, 0x4c000000UL, 0x58000000UL, 
+ 0xcf000000UL, 0xd0000000UL, 0xef000000UL, 0xaa000000UL, 0xfb000000UL, 
+ 0x43000000UL, 0x4d000000UL, 0x33000000UL, 0x85000000UL, 0x45000000UL, 
+ 0xf9000000UL, 0x02000000UL, 0x7f000000UL, 0x50000000UL, 0x3c000000UL, 
+ 0x9f000000UL, 0xa8000000UL, 0x51000000UL, 0xa3000000UL, 0x40000000UL, 
+ 0x8f000000UL, 0x92000000UL, 0x9d000000UL, 0x38000000UL, 0xf5000000UL, 
+ 0xbc000000UL, 0xb6000000UL, 0xda000000UL, 0x21000000UL, 0x10000000UL, 
+ 0xff000000UL, 0xf3000000UL, 0xd2000000UL, 0xcd000000UL, 0x0c000000UL, 
+ 0x13000000UL, 0xec000000UL, 0x5f000000UL, 0x97000000UL, 0x44000000UL, 
+ 0x17000000UL, 0xc4000000UL, 0xa7000000UL, 0x7e000000UL, 0x3d000000UL, 
+ 0x64000000UL, 0x5d000000UL, 0x19000000UL, 0x73000000UL, 0x60000000UL, 
+ 0x81000000UL, 0x4f000000UL, 0xdc000000UL, 0x22000000UL, 0x2a000000UL, 
+ 0x90000000UL, 0x88000000UL, 0x46000000UL, 0xee000000UL, 0xb8000000UL, 
+ 0x14000000UL, 0xde000000UL, 0x5e000000UL, 0x0b000000UL, 0xdb000000UL, 
+ 0xe0000000UL, 0x32000000UL, 0x3a000000UL, 0x0a000000UL, 0x49000000UL, 
+ 0x06000000UL, 0x24000000UL, 0x5c000000UL, 0xc2000000UL, 0xd3000000UL, 
+ 0xac000000UL, 0x62000000UL, 0x91000000UL, 0x95000000UL, 0xe4000000UL, 
+ 0x79000000UL, 0xe7000000UL, 0xc8000000UL, 0x37000000UL, 0x6d000000UL, 
+ 0x8d000000UL, 0xd5000000UL, 0x4e000000UL, 0xa9000000UL, 0x6c000000UL, 
+ 0x56000000UL, 0xf4000000UL, 0xea000000UL, 0x65000000UL, 0x7a000000UL, 
+ 0xae000000UL, 0x08000000UL, 0xba000000UL, 0x78000000UL, 0x25000000UL, 
+ 0x2e000000UL, 0x1c000000UL, 0xa6000000UL, 0xb4000000UL, 0xc6000000UL, 
+ 0xe8000000UL, 0xdd000000UL, 0x74000000UL, 0x1f000000UL, 0x4b000000UL, 
+ 0xbd000000UL, 0x8b000000UL, 0x8a000000UL, 0x70000000UL, 0x3e000000UL, 
+ 0xb5000000UL, 0x66000000UL, 0x48000000UL, 0x03000000UL, 0xf6000000UL, 
+ 0x0e000000UL, 0x61000000UL, 0x35000000UL, 0x57000000UL, 0xb9000000UL, 
+ 0x86000000UL, 0xc1000000UL, 0x1d000000UL, 0x9e000000UL, 0xe1000000UL, 
+ 0xf8000000UL, 0x98000000UL, 0x11000000UL, 0x69000000UL, 0xd9000000UL, 
+ 0x8e000000UL, 0x94000000UL, 0x9b000000UL, 0x1e000000UL, 0x87000000UL, 
+ 0xe9000000UL, 0xce000000UL, 0x55000000UL, 0x28000000UL, 0xdf000000UL, 
+ 0x8c000000UL, 0xa1000000UL, 0x89000000UL, 0x0d000000UL, 0xbf000000UL, 
+ 0xe6000000UL, 0x42000000UL, 0x68000000UL, 0x41000000UL, 0x99000000UL, 
+ 0x2d000000UL, 0x0f000000UL, 0xb0000000UL, 0x54000000UL, 0xbb000000UL, 
+ 0x16000000UL}
+ };
+
+static const unsigned long il_tab[4][256] = {
+{0x00000052UL, 0x00000009UL, 0x0000006aUL, 0x000000d5UL, 0x00000030UL, 
+ 0x00000036UL, 0x000000a5UL, 0x00000038UL, 0x000000bfUL, 0x00000040UL, 
+ 0x000000a3UL, 0x0000009eUL, 0x00000081UL, 0x000000f3UL, 0x000000d7UL, 
+ 0x000000fbUL, 0x0000007cUL, 0x000000e3UL, 0x00000039UL, 0x00000082UL, 
+ 0x0000009bUL, 0x0000002fUL, 0x000000ffUL, 0x00000087UL, 0x00000034UL, 
+ 0x0000008eUL, 0x00000043UL, 0x00000044UL, 0x000000c4UL, 0x000000deUL, 
+ 0x000000e9UL, 0x000000cbUL, 0x00000054UL, 0x0000007bUL, 0x00000094UL, 
+ 0x00000032UL, 0x000000a6UL, 0x000000c2UL, 0x00000023UL, 0x0000003dUL, 
+ 0x000000eeUL, 0x0000004cUL, 0x00000095UL, 0x0000000bUL, 0x00000042UL, 
+ 0x000000faUL, 0x000000c3UL, 0x0000004eUL, 0x00000008UL, 0x0000002eUL, 
+ 0x000000a1UL, 0x00000066UL, 0x00000028UL, 0x000000d9UL, 0x00000024UL, 
+ 0x000000b2UL, 0x00000076UL, 0x0000005bUL, 0x000000a2UL, 0x00000049UL, 
+ 0x0000006dUL, 0x0000008bUL, 0x000000d1UL, 0x00000025UL, 0x00000072UL, 
+ 0x000000f8UL, 0x000000f6UL, 0x00000064UL, 0x00000086UL, 0x00000068UL, 
+ 0x00000098UL, 0x00000016UL, 0x000000d4UL, 0x000000a4UL, 0x0000005cUL, 
+ 0x000000ccUL, 0x0000005dUL, 0x00000065UL, 0x000000b6UL, 0x00000092UL, 
+ 0x0000006cUL, 0x00000070UL, 0x00000048UL, 0x00000050UL, 0x000000fdUL, 
+ 0x000000edUL, 0x000000b9UL, 0x000000daUL, 0x0000005eUL, 0x00000015UL, 
+ 0x00000046UL, 0x00000057UL, 0x000000a7UL, 0x0000008dUL, 0x0000009dUL, 
+ 0x00000084UL, 0x00000090UL, 0x000000d8UL, 0x000000abUL, 0x00000000UL, 
+ 0x0000008cUL, 0x000000bcUL, 0x000000d3UL, 0x0000000aUL, 0x000000f7UL, 
+ 0x000000e4UL, 0x00000058UL, 0x00000005UL, 0x000000b8UL, 0x000000b3UL, 
+ 0x00000045UL, 0x00000006UL, 0x000000d0UL, 0x0000002cUL, 0x0000001eUL, 
+ 0x0000008fUL, 0x000000caUL, 0x0000003fUL, 0x0000000fUL, 0x00000002UL, 
+ 0x000000c1UL, 0x000000afUL, 0x000000bdUL, 0x00000003UL, 0x00000001UL, 
+ 0x00000013UL, 0x0000008aUL, 0x0000006bUL, 0x0000003aUL, 0x00000091UL, 
+ 0x00000011UL, 0x00000041UL, 0x0000004fUL, 0x00000067UL, 0x000000dcUL, 
+ 0x000000eaUL, 0x00000097UL, 0x000000f2UL, 0x000000cfUL, 0x000000ceUL, 
+ 0x000000f0UL, 0x000000b4UL, 0x000000e6UL, 0x00000073UL, 0x00000096UL, 
+ 0x000000acUL, 0x00000074UL, 0x00000022UL, 0x000000e7UL, 0x000000adUL, 
+ 0x00000035UL, 0x00000085UL, 0x000000e2UL, 0x000000f9UL, 0x00000037UL, 
+ 0x000000e8UL, 0x0000001cUL, 0x00000075UL, 0x000000dfUL, 0x0000006eUL, 
+ 0x00000047UL, 0x000000f1UL, 0x0000001aUL, 0x00000071UL, 0x0000001dUL, 
+ 0x00000029UL, 0x000000c5UL, 0x00000089UL, 0x0000006fUL, 0x000000b7UL, 
+ 0x00000062UL, 0x0000000eUL, 0x000000aaUL, 0x00000018UL, 0x000000beUL, 
+ 0x0000001bUL, 0x000000fcUL, 0x00000056UL, 0x0000003eUL, 0x0000004bUL, 
+ 0x000000c6UL, 0x000000d2UL, 0x00000079UL, 0x00000020UL, 0x0000009aUL, 
+ 0x000000dbUL, 0x000000c0UL, 0x000000feUL, 0x00000078UL, 0x000000cdUL, 
+ 0x0000005aUL, 0x000000f4UL, 0x0000001fUL, 0x000000ddUL, 0x000000a8UL, 
+ 0x00000033UL, 0x00000088UL, 0x00000007UL, 0x000000c7UL, 0x00000031UL, 
+ 0x000000b1UL, 0x00000012UL, 0x00000010UL, 0x00000059UL, 0x00000027UL, 
+ 0x00000080UL, 0x000000ecUL, 0x0000005fUL, 0x00000060UL, 0x00000051UL, 
+ 0x0000007fUL, 0x000000a9UL, 0x00000019UL, 0x000000b5UL, 0x0000004aUL, 
+ 0x0000000dUL, 0x0000002dUL, 0x000000e5UL, 0x0000007aUL, 0x0000009fUL, 
+ 0x00000093UL, 0x000000c9UL, 0x0000009cUL, 0x000000efUL, 0x000000a0UL, 
+ 0x000000e0UL, 0x0000003bUL, 0x0000004dUL, 0x000000aeUL, 0x0000002aUL, 
+ 0x000000f5UL, 0x000000b0UL, 0x000000c8UL, 0x000000ebUL, 0x000000bbUL, 
+ 0x0000003cUL, 0x00000083UL, 0x00000053UL, 0x00000099UL, 0x00000061UL, 
+ 0x00000017UL, 0x0000002bUL, 0x00000004UL, 0x0000007eUL, 0x000000baUL, 
+ 0x00000077UL, 0x000000d6UL, 0x00000026UL, 0x000000e1UL, 0x00000069UL, 
+ 0x00000014UL, 0x00000063UL, 0x00000055UL, 0x00000021UL, 0x0000000cUL, 
+ 0x0000007dUL}, 
+{0x00005200UL, 0x00000900UL, 0x00006a00UL, 0x0000d500UL, 0x00003000UL, 
+ 0x00003600UL, 0x0000a500UL, 0x00003800UL, 0x0000bf00UL, 0x00004000UL, 
+ 0x0000a300UL, 0x00009e00UL, 0x00008100UL, 0x0000f300UL, 0x0000d700UL, 
+ 0x0000fb00UL, 0x00007c00UL, 0x0000e300UL, 0x00003900UL, 0x00008200UL, 
+ 0x00009b00UL, 0x00002f00UL, 0x0000ff00UL, 0x00008700UL, 0x00003400UL, 
+ 0x00008e00UL, 0x00004300UL, 0x00004400UL, 0x0000c400UL, 0x0000de00UL, 
+ 0x0000e900UL, 0x0000cb00UL, 0x00005400UL, 0x00007b00UL, 0x00009400UL, 
+ 0x00003200UL, 0x0000a600UL, 0x0000c200UL, 0x00002300UL, 0x00003d00UL, 
+ 0x0000ee00UL, 0x00004c00UL, 0x00009500UL, 0x00000b00UL, 0x00004200UL, 
+ 0x0000fa00UL, 0x0000c300UL, 0x00004e00UL, 0x00000800UL, 0x00002e00UL, 
+ 0x0000a100UL, 0x00006600UL, 0x00002800UL, 0x0000d900UL, 0x00002400UL, 
+ 0x0000b200UL, 0x00007600UL, 0x00005b00UL, 0x0000a200UL, 0x00004900UL, 
+ 0x00006d00UL, 0x00008b00UL, 0x0000d100UL, 0x00002500UL, 0x00007200UL, 
+ 0x0000f800UL, 0x0000f600UL, 0x00006400UL, 0x00008600UL, 0x00006800UL, 
+ 0x00009800UL, 0x00001600UL, 0x0000d400UL, 0x0000a400UL, 0x00005c00UL, 
+ 0x0000cc00UL, 0x00005d00UL, 0x00006500UL, 0x0000b600UL, 0x00009200UL, 
+ 0x00006c00UL, 0x00007000UL, 0x00004800UL, 0x00005000UL, 0x0000fd00UL, 
+ 0x0000ed00UL, 0x0000b900UL, 0x0000da00UL, 0x00005e00UL, 0x00001500UL, 
+ 0x00004600UL, 0x00005700UL, 0x0000a700UL, 0x00008d00UL, 0x00009d00UL, 
+ 0x00008400UL, 0x00009000UL, 0x0000d800UL, 0x0000ab00UL, 0x00000000UL, 
+ 0x00008c00UL, 0x0000bc00UL, 0x0000d300UL, 0x00000a00UL, 0x0000f700UL, 
+ 0x0000e400UL, 0x00005800UL, 0x00000500UL, 0x0000b800UL, 0x0000b300UL, 
+ 0x00004500UL, 0x00000600UL, 0x0000d000UL, 0x00002c00UL, 0x00001e00UL, 
+ 0x00008f00UL, 0x0000ca00UL, 0x00003f00UL, 0x00000f00UL, 0x00000200UL, 
+ 0x0000c100UL, 0x0000af00UL, 0x0000bd00UL, 0x00000300UL, 0x00000100UL, 
+ 0x00001300UL, 0x00008a00UL, 0x00006b00UL, 0x00003a00UL, 0x00009100UL, 
+ 0x00001100UL, 0x00004100UL, 0x00004f00UL, 0x00006700UL, 0x0000dc00UL, 
+ 0x0000ea00UL, 0x00009700UL, 0x0000f200UL, 0x0000cf00UL, 0x0000ce00UL, 
+ 0x0000f000UL, 0x0000b400UL, 0x0000e600UL, 0x00007300UL, 0x00009600UL, 
+ 0x0000ac00UL, 0x00007400UL, 0x00002200UL, 0x0000e700UL, 0x0000ad00UL, 
+ 0x00003500UL, 0x00008500UL, 0x0000e200UL, 0x0000f900UL, 0x00003700UL, 
+ 0x0000e800UL, 0x00001c00UL, 0x00007500UL, 0x0000df00UL, 0x00006e00UL, 
+ 0x00004700UL, 0x0000f100UL, 0x00001a00UL, 0x00007100UL, 0x00001d00UL, 
+ 0x00002900UL, 0x0000c500UL, 0x00008900UL, 0x00006f00UL, 0x0000b700UL, 
+ 0x00006200UL, 0x00000e00UL, 0x0000aa00UL, 0x00001800UL, 0x0000be00UL, 
+ 0x00001b00UL, 0x0000fc00UL, 0x00005600UL, 0x00003e00UL, 0x00004b00UL, 
+ 0x0000c600UL, 0x0000d200UL, 0x00007900UL, 0x00002000UL, 0x00009a00UL, 
+ 0x0000db00UL, 0x0000c000UL, 0x0000fe00UL, 0x00007800UL, 0x0000cd00UL, 
+ 0x00005a00UL, 0x0000f400UL, 0x00001f00UL, 0x0000dd00UL, 0x0000a800UL, 
+ 0x00003300UL, 0x00008800UL, 0x00000700UL, 0x0000c700UL, 0x00003100UL, 
+ 0x0000b100UL, 0x00001200UL, 0x00001000UL, 0x00005900UL, 0x00002700UL, 
+ 0x00008000UL, 0x0000ec00UL, 0x00005f00UL, 0x00006000UL, 0x00005100UL, 
+ 0x00007f00UL, 0x0000a900UL, 0x00001900UL, 0x0000b500UL, 0x00004a00UL, 
+ 0x00000d00UL, 0x00002d00UL, 0x0000e500UL, 0x00007a00UL, 0x00009f00UL, 
+ 0x00009300UL, 0x0000c900UL, 0x00009c00UL, 0x0000ef00UL, 0x0000a000UL, 
+ 0x0000e000UL, 0x00003b00UL, 0x00004d00UL, 0x0000ae00UL, 0x00002a00UL, 
+ 0x0000f500UL, 0x0000b000UL, 0x0000c800UL, 0x0000eb00UL, 0x0000bb00UL, 
+ 0x00003c00UL, 0x00008300UL, 0x00005300UL, 0x00009900UL, 0x00006100UL, 
+ 0x00001700UL, 0x00002b00UL, 0x00000400UL, 0x00007e00UL, 0x0000ba00UL, 
+ 0x00007700UL, 0x0000d600UL, 0x00002600UL, 0x0000e100UL, 0x00006900UL, 
+ 0x00001400UL, 0x00006300UL, 0x00005500UL, 0x00002100UL, 0x00000c00UL, 
+ 0x00007d00UL}, 
+{0x00520000UL, 0x00090000UL, 0x006a0000UL, 0x00d50000UL, 0x00300000UL, 
+ 0x00360000UL, 0x00a50000UL, 0x00380000UL, 0x00bf0000UL, 0x00400000UL, 
+ 0x00a30000UL, 0x009e0000UL, 0x00810000UL, 0x00f30000UL, 0x00d70000UL, 
+ 0x00fb0000UL, 0x007c0000UL, 0x00e30000UL, 0x00390000UL, 0x00820000UL, 
+ 0x009b0000UL, 0x002f0000UL, 0x00ff0000UL, 0x00870000UL, 0x00340000UL, 
+ 0x008e0000UL, 0x00430000UL, 0x00440000UL, 0x00c40000UL, 0x00de0000UL, 
+ 0x00e90000UL, 0x00cb0000UL, 0x00540000UL, 0x007b0000UL, 0x00940000UL, 
+ 0x00320000UL, 0x00a60000UL, 0x00c20000UL, 0x00230000UL, 0x003d0000UL, 
+ 0x00ee0000UL, 0x004c0000UL, 0x00950000UL, 0x000b0000UL, 0x00420000UL, 
+ 0x00fa0000UL, 0x00c30000UL, 0x004e0000UL, 0x00080000UL, 0x002e0000UL, 
+ 0x00a10000UL, 0x00660000UL, 0x00280000UL, 0x00d90000UL, 0x00240000UL, 
+ 0x00b20000UL, 0x00760000UL, 0x005b0000UL, 0x00a20000UL, 0x00490000UL, 
+ 0x006d0000UL, 0x008b0000UL, 0x00d10000UL, 0x00250000UL, 0x00720000UL, 
+ 0x00f80000UL, 0x00f60000UL, 0x00640000UL, 0x00860000UL, 0x00680000UL, 
+ 0x00980000UL, 0x00160000UL, 0x00d40000UL, 0x00a40000UL, 0x005c0000UL, 
+ 0x00cc0000UL, 0x005d0000UL, 0x00650000UL, 0x00b60000UL, 0x00920000UL, 
+ 0x006c0000UL, 0x00700000UL, 0x00480000UL, 0x00500000UL, 0x00fd0000UL, 
+ 0x00ed0000UL, 0x00b90000UL, 0x00da0000UL, 0x005e0000UL, 0x00150000UL, 
+ 0x00460000UL, 0x00570000UL, 0x00a70000UL, 0x008d0000UL, 0x009d0000UL, 
+ 0x00840000UL, 0x00900000UL, 0x00d80000UL, 0x00ab0000UL, 0x00000000UL, 
+ 0x008c0000UL, 0x00bc0000UL, 0x00d30000UL, 0x000a0000UL, 0x00f70000UL, 
+ 0x00e40000UL, 0x00580000UL, 0x00050000UL, 0x00b80000UL, 0x00b30000UL, 
+ 0x00450000UL, 0x00060000UL, 0x00d00000UL, 0x002c0000UL, 0x001e0000UL, 
+ 0x008f0000UL, 0x00ca0000UL, 0x003f0000UL, 0x000f0000UL, 0x00020000UL, 
+ 0x00c10000UL, 0x00af0000UL, 0x00bd0000UL, 0x00030000UL, 0x00010000UL, 
+ 0x00130000UL, 0x008a0000UL, 0x006b0000UL, 0x003a0000UL, 0x00910000UL, 
+ 0x00110000UL, 0x00410000UL, 0x004f0000UL, 0x00670000UL, 0x00dc0000UL, 
+ 0x00ea0000UL, 0x00970000UL, 0x00f20000UL, 0x00cf0000UL, 0x00ce0000UL, 
+ 0x00f00000UL, 0x00b40000UL, 0x00e60000UL, 0x00730000UL, 0x00960000UL, 
+ 0x00ac0000UL, 0x00740000UL, 0x00220000UL, 0x00e70000UL, 0x00ad0000UL, 
+ 0x00350000UL, 0x00850000UL, 0x00e20000UL, 0x00f90000UL, 0x00370000UL, 
+ 0x00e80000UL, 0x001c0000UL, 0x00750000UL, 0x00df0000UL, 0x006e0000UL, 
+ 0x00470000UL, 0x00f10000UL, 0x001a0000UL, 0x00710000UL, 0x001d0000UL, 
+ 0x00290000UL, 0x00c50000UL, 0x00890000UL, 0x006f0000UL, 0x00b70000UL, 
+ 0x00620000UL, 0x000e0000UL, 0x00aa0000UL, 0x00180000UL, 0x00be0000UL, 
+ 0x001b0000UL, 0x00fc0000UL, 0x00560000UL, 0x003e0000UL, 0x004b0000UL, 
+ 0x00c60000UL, 0x00d20000UL, 0x00790000UL, 0x00200000UL, 0x009a0000UL, 
+ 0x00db0000UL, 0x00c00000UL, 0x00fe0000UL, 0x00780000UL, 0x00cd0000UL, 
+ 0x005a0000UL, 0x00f40000UL, 0x001f0000UL, 0x00dd0000UL, 0x00a80000UL, 
+ 0x00330000UL, 0x00880000UL, 0x00070000UL, 0x00c70000UL, 0x00310000UL, 
+ 0x00b10000UL, 0x00120000UL, 0x00100000UL, 0x00590000UL, 0x00270000UL, 
+ 0x00800000UL, 0x00ec0000UL, 0x005f0000UL, 0x00600000UL, 0x00510000UL, 
+ 0x007f0000UL, 0x00a90000UL, 0x00190000UL, 0x00b50000UL, 0x004a0000UL, 
+ 0x000d0000UL, 0x002d0000UL, 0x00e50000UL, 0x007a0000UL, 0x009f0000UL, 
+ 0x00930000UL, 0x00c90000UL, 0x009c0000UL, 0x00ef0000UL, 0x00a00000UL, 
+ 0x00e00000UL, 0x003b0000UL, 0x004d0000UL, 0x00ae0000UL, 0x002a0000UL, 
+ 0x00f50000UL, 0x00b00000UL, 0x00c80000UL, 0x00eb0000UL, 0x00bb0000UL, 
+ 0x003c0000UL, 0x00830000UL, 0x00530000UL, 0x00990000UL, 0x00610000UL, 
+ 0x00170000UL, 0x002b0000UL, 0x00040000UL, 0x007e0000UL, 0x00ba0000UL, 
+ 0x00770000UL, 0x00d60000UL, 0x00260000UL, 0x00e10000UL, 0x00690000UL, 
+ 0x00140000UL, 0x00630000UL, 0x00550000UL, 0x00210000UL, 0x000c0000UL, 
+ 0x007d0000UL}, 
+{0x52000000UL, 0x09000000UL, 0x6a000000UL, 0xd5000000UL, 0x30000000UL, 
+ 0x36000000UL, 0xa5000000UL, 0x38000000UL, 0xbf000000UL, 0x40000000UL, 
+ 0xa3000000UL, 0x9e000000UL, 0x81000000UL, 0xf3000000UL, 0xd7000000UL, 
+ 0xfb000000UL, 0x7c000000UL, 0xe3000000UL, 0x39000000UL, 0x82000000UL, 
+ 0x9b000000UL, 0x2f000000UL, 0xff000000UL, 0x87000000UL, 0x34000000UL, 
+ 0x8e000000UL, 0x43000000UL, 0x44000000UL, 0xc4000000UL, 0xde000000UL, 
+ 0xe9000000UL, 0xcb000000UL, 0x54000000UL, 0x7b000000UL, 0x94000000UL, 
+ 0x32000000UL, 0xa6000000UL, 0xc2000000UL, 0x23000000UL, 0x3d000000UL, 
+ 0xee000000UL, 0x4c000000UL, 0x95000000UL, 0x0b000000UL, 0x42000000UL, 
+ 0xfa000000UL, 0xc3000000UL, 0x4e000000UL, 0x08000000UL, 0x2e000000UL, 
+ 0xa1000000UL, 0x66000000UL, 0x28000000UL, 0xd9000000UL, 0x24000000UL, 
+ 0xb2000000UL, 0x76000000UL, 0x5b000000UL, 0xa2000000UL, 0x49000000UL, 
+ 0x6d000000UL, 0x8b000000UL, 0xd1000000UL, 0x25000000UL, 0x72000000UL, 
+ 0xf8000000UL, 0xf6000000UL, 0x64000000UL, 0x86000000UL, 0x68000000UL, 
+ 0x98000000UL, 0x16000000UL, 0xd4000000UL, 0xa4000000UL, 0x5c000000UL, 
+ 0xcc000000UL, 0x5d000000UL, 0x65000000UL, 0xb6000000UL, 0x92000000UL, 
+ 0x6c000000UL, 0x70000000UL, 0x48000000UL, 0x50000000UL, 0xfd000000UL, 
+ 0xed000000UL, 0xb9000000UL, 0xda000000UL, 0x5e000000UL, 0x15000000UL, 
+ 0x46000000UL, 0x57000000UL, 0xa7000000UL, 0x8d000000UL, 0x9d000000UL, 
+ 0x84000000UL, 0x90000000UL, 0xd8000000UL, 0xab000000UL, 0x00000000UL, 
+ 0x8c000000UL, 0xbc000000UL, 0xd3000000UL, 0x0a000000UL, 0xf7000000UL, 
+ 0xe4000000UL, 0x58000000UL, 0x05000000UL, 0xb8000000UL, 0xb3000000UL, 
+ 0x45000000UL, 0x06000000UL, 0xd0000000UL, 0x2c000000UL, 0x1e000000UL, 
+ 0x8f000000UL, 0xca000000UL, 0x3f000000UL, 0x0f000000UL, 0x02000000UL, 
+ 0xc1000000UL, 0xaf000000UL, 0xbd000000UL, 0x03000000UL, 0x01000000UL, 
+ 0x13000000UL, 0x8a000000UL, 0x6b000000UL, 0x3a000000UL, 0x91000000UL, 
+ 0x11000000UL, 0x41000000UL, 0x4f000000UL, 0x67000000UL, 0xdc000000UL, 
+ 0xea000000UL, 0x97000000UL, 0xf2000000UL, 0xcf000000UL, 0xce000000UL, 
+ 0xf0000000UL, 0xb4000000UL, 0xe6000000UL, 0x73000000UL, 0x96000000UL, 
+ 0xac000000UL, 0x74000000UL, 0x22000000UL, 0xe7000000UL, 0xad000000UL, 
+ 0x35000000UL, 0x85000000UL, 0xe2000000UL, 0xf9000000UL, 0x37000000UL, 
+ 0xe8000000UL, 0x1c000000UL, 0x75000000UL, 0xdf000000UL, 0x6e000000UL, 
+ 0x47000000UL, 0xf1000000UL, 0x1a000000UL, 0x71000000UL, 0x1d000000UL, 
+ 0x29000000UL, 0xc5000000UL, 0x89000000UL, 0x6f000000UL, 0xb7000000UL, 
+ 0x62000000UL, 0x0e000000UL, 0xaa000000UL, 0x18000000UL, 0xbe000000UL, 
+ 0x1b000000UL, 0xfc000000UL, 0x56000000UL, 0x3e000000UL, 0x4b000000UL, 
+ 0xc6000000UL, 0xd2000000UL, 0x79000000UL, 0x20000000UL, 0x9a000000UL, 
+ 0xdb000000UL, 0xc0000000UL, 0xfe000000UL, 0x78000000UL, 0xcd000000UL, 
+ 0x5a000000UL, 0xf4000000UL, 0x1f000000UL, 0xdd000000UL, 0xa8000000UL, 
+ 0x33000000UL, 0x88000000UL, 0x07000000UL, 0xc7000000UL, 0x31000000UL, 
+ 0xb1000000UL, 0x12000000UL, 0x10000000UL, 0x59000000UL, 0x27000000UL, 
+ 0x80000000UL, 0xec000000UL, 0x5f000000UL, 0x60000000UL, 0x51000000UL, 
+ 0x7f000000UL, 0xa9000000UL, 0x19000000UL, 0xb5000000UL, 0x4a000000UL, 
+ 0x0d000000UL, 0x2d000000UL, 0xe5000000UL, 0x7a000000UL, 0x9f000000UL, 
+ 0x93000000UL, 0xc9000000UL, 0x9c000000UL, 0xef000000UL, 0xa0000000UL, 
+ 0xe0000000UL, 0x3b000000UL, 0x4d000000UL, 0xae000000UL, 0x2a000000UL, 
+ 0xf5000000UL, 0xb0000000UL, 0xc8000000UL, 0xeb000000UL, 0xbb000000UL, 
+ 0x3c000000UL, 0x83000000UL, 0x53000000UL, 0x99000000UL, 0x61000000UL, 
+ 0x17000000UL, 0x2b000000UL, 0x04000000UL, 0x7e000000UL, 0xba000000UL, 
+ 0x77000000UL, 0xd6000000UL, 0x26000000UL, 0xe1000000UL, 0x69000000UL, 
+ 0x14000000UL, 0x63000000UL, 0x55000000UL, 0x21000000UL, 0x0c000000UL, 
+ 0x7d000000UL}
+ };
+
+static const unsigned long rco_tab[10] = {
+ 0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL, 0x00000010UL, 
+ 0x00000020UL, 0x00000040UL, 0x00000080UL, 0x0000001bUL, 0x00000036UL
+ };
+

+ 55 - 0
ampi.c

@@ -0,0 +1,55 @@
+/* Code submitted by Svante Seleborg, cleaned up by Tom St Denis */
+
+#include "mycrypt.h"
+#include <stdarg.h>
+
+#ifdef MPI
+
+mp_err mp_init_multi(mp_int *mp, ...) 
+{
+    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
+    int n = 0;                 /* Number of ok inits */
+    mp_int* cur_arg = mp;
+    va_list args;
+
+    va_start(args, mp);        /* init args to next argument from caller */
+    while (cur_arg != NULL) {
+        if (mp_init(cur_arg) != MP_OKAY) {
+            /* Oops - error! Back-track and mp_clear what we already
+               succeeded in init-ing, then return error.
+            */
+            va_list clean_args;
+            cur_arg = mp;
+            va_start(clean_args, mp);
+            while (n--) {
+                mp_clear(cur_arg);
+                cur_arg = va_arg(clean_args, mp_int*);
+            }
+            va_end(clean_args);
+            res = MP_MEM;
+            break;
+        }
+        n++;
+        cur_arg = va_arg(args, mp_int*);
+    }
+    va_end(args);
+    return res;                /* Assumed ok, if error flagged above. */
+}
+
+/*
+    Clear all arguments given, ended by a NULL marker.
+*/
+void mp_clear_multi(mp_int *mp, ...) 
+{
+    mp_int* next_mp = mp;
+    va_list args;
+    va_start(args, mp);
+    while (next_mp != NULL) {
+        mp_clear(next_mp);
+        next_mp = va_arg(args, mp_int*);
+    }
+    va_end(args);
+}
+
+#endif
+

+ 48 - 0
authors

@@ -0,0 +1,48 @@
+This is a list of people who have contributed [directly or indirectly] to the project
+[in no partcular order].  If you have helped and your name is not here email me at
[email protected].
+
+
+1) [email protected]
+
+   Gave help porting the lib to MSVC particularly pointed out various warnings and errors.
+
+2) Richard Heathfield
+
+   Gave a lot of help concerning valid C portable code.  
+
+3) Ajay K. Agrawal
+
+   Helped port the library to MSVC and spotted a few bugs and errors.
+
+4) Brian Gladman
+
+   Wrote the AES and Serpent code used.  Found a bug in the hash code for certain types of inputs.
+
+5) Svante Seleborg
+
+   Submitted the "ampi.c" code as well as many suggestions on improving the readability of the source code.
+
+6) Clay Culver
+
+   Submitted a fix for "rsa.c" which cleaned up some code.
+
+7) Jason Klapste
+
+   Submitted fixes to the yarrow, hash, make process and test code as well as other subtle bug fixes.  The 
+yarrow code can now default to any cipher/hash that is left after you remove them from a build.
+
+8) Dobes Vandermeer <[email protected]>
+
+   Submitted HMAC code that worked flawlessly out of the box... good job!  Also submitted a MD4 routine.
+   Submitted some modified DES code that was merged into the code base [using the libtomcrypt API]
+
+9) Wayne Scott ([email protected])
+  
+   Submitted base64 that complies with the RFC standards.
+   
+10) Sky Schulz ([email protected])
+
+   Has submitted a set of ideas to improve the library and make it more attractive for professional users.
+   
+   

+ 111 - 0
base64.c

@@ -0,0 +1,111 @@
+/* compliant base64 code donated by Wayne Scott ([email protected]) */
+#include "mycrypt.h"
+
+#ifdef BASE64
+
+static const char *codes = 
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const unsigned char map[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
+ 19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
+255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+ 49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255 };
+
+int base64_encode(const unsigned char *in,  unsigned long len, 
+                        unsigned char *out, unsigned long *outlen)
+{
+   unsigned long i, len2, leven;
+   unsigned char *p;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* valid output size ? */
+   len2 = 4 * ((len + 2) / 3);
+   if (*outlen < len2 + 1) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   p = out;
+   leven = 3*(len / 3);
+   for (i = 0; i < leven; i += 3) {
+       *p++ = codes[in[0] >> 2];
+       *p++ = codes[((in[0] & 3) << 4) + (in[1] >> 4)];
+       *p++ = codes[((in[1] & 0xf) << 2) + (in[2] >> 6)];
+       *p++ = codes[in[2] & 0x3f];
+       in += 3;
+   }
+   /* Pad it if necessary...  */
+   if (i < len) {
+       unsigned a = in[0];
+       unsigned b = (i+1 < len) ? in[1] : 0;
+       unsigned c = 0;
+
+       *p++ = codes[a >> 2];
+       *p++ = codes[((a & 3) << 4) + (b >> 4)];
+       *p++ = (i+1 < len) ? codes[((b & 0xf) << 2) + (c >> 6)] : '=';
+       *p++ = '=';
+   }
+
+   /* append a NULL byte */
+   *p = '\0';
+
+   /* return ok */
+   *outlen = p - out;
+   return CRYPT_OK;
+}
+
+int base64_decode(const unsigned char *in,  unsigned long len, 
+                        unsigned char *out, unsigned long *outlen)
+{
+   unsigned long t, x, y, z;
+   unsigned char c;
+   int	g = 3;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   for (x = y = z = t = 0; x < len; x++) {
+       c = map[in[x]];
+       if (c == 255) continue;
+       if (c == 254) { c = 0; g--; }
+       t = (t<<6)|c;
+       if (++y == 4) {
+	  if (z + g > *outlen) goto error;
+          out[z++] = (unsigned char)((t>>16)&255);
+          if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
+          if (g > 2) out[z++] = (unsigned char)(t&255);
+          y = t = 0;
+       }
+   }
+   if (y != 0) {
+       return CRYPT_INVALID_PACKET;
+   }
+   *outlen = z;
+   return CRYPT_OK;
+error:
+   return CRYPT_BUFFER_OVERFLOW;
+}
+
+#endif
+

+ 193 - 0
bits.c

@@ -0,0 +1,193 @@
+/* portable way to get secure random bits to feed a PRNG */
+#include "mycrypt.h"
+
+#ifdef DEVRANDOM
+/* on *NIX read /dev/random */
+static unsigned long rng_nix(unsigned char *buf, unsigned long len, 
+                             void (*callback)(void))
+{
+#ifdef NO_FILE
+    return 0;
+#else
+    FILE *f;
+    int x;
+#ifdef TRY_URANDOM_FIRST
+    f = fopen("/dev/urandom", "rb");
+    if (f == NULL)
+#endif /* TRY_URANDOM_FIRST */
+       f = fopen("/dev/random", "rb");
+
+    if (f == NULL) {
+       return 0;
+    }
+ 
+    x = fread(buf, 1, len, f);
+    fclose(f);
+    return x;
+#endif /* NO_FILE */
+}
+
+#endif /* DEVRANDOM */
+
+#ifdef SONY_PS2
+#include <eetypes.h>
+#include <eeregs.h>
+#define min(a,b) ((a) < (b) ? (a) : (b))
+// Very simple/stupid MD5-based RNG that samples "entropy" from various PS2 control registers
+static unsigned long rng_ps2(unsigned char *buf, unsigned long len, 
+                             void (*callback)(void))
+{
+  static unsigned long lastx[2] = { 0xaab7cb4b2fd3b2b9, 0xcec58aff72afe49f }; // md5sum of bits.c
+  unsigned long j;
+  unsigned int samples[10];  // number of sample data sources
+  int l;
+  hash_state md;
+
+  for (j = 0; j < len; j += sizeof(lastx)) {
+    md5_init(&md);
+    samples[0] = *T2_COUNT;
+    samples[1] = *T3_COUNT;
+    samples[2] = *IPU_TOP;
+    samples[3] = *GIF_TAG0;
+    samples[4] = *GIF_TAG1;
+    samples[5] = *GIF_TAG2;
+    samples[6] = *VIF1_CODE;
+    samples[7] = *VIF0_CODE;
+    samples[8] = *D0_MADR;
+    samples[9] = *D1_MADR;
+    md5_process(&md, (unsigned char *)(&samples[0]), sizeof(samples));
+    // include previous round
+    md5_process(&md, (unsigned char *)(&lastx[0]), sizeof(lastx));
+    md5_done(&md, (unsigned char *)(&lastx[0]));
+    l = min(sizeof(lastx), len-j);
+    memcpy(buf+j, &lastx[0], l); //min(sizeof(lastx), len-j));
+  }
+  return len;
+}
+#endif /* SONY_PS2 */
+
+/* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
+#if !defined(SONY_PS2) && defined(CLOCKS_PER_SEC)
+
+#define ANSI_RNG
+
+static unsigned long rng_ansic(unsigned char *buf, unsigned long len, 
+                               void (*callback)(void))
+{
+   clock_t t1;
+   int l, acc, bits, a, b;
+
+   if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) {
+      return 0;
+   }
+
+   l = len;
+   bits = 8;
+   acc  = a = b = 0;
+   while (len--) {
+       if (callback != NULL) callback();
+       while (bits--) {
+          do {
+             t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1;
+             t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1;
+          } while (a == b);
+          acc = (acc << 1) | a;
+       }
+       *buf++ = acc; 
+       acc  = 0;
+       bits = 8;
+   }
+   acc = bits = a = b = 0;
+   return l;
+}
+
+#endif 
+
+/* Try the Microsoft CSP */
+#ifdef WIN32
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#include <wincrypt.h>
+
+static unsigned long rng_win32(unsigned char *buf, unsigned long len, 
+                               void (*callback)(void))
+{
+   HCRYPTPROV hProv = 0;
+   if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 
+                            (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && 
+       !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 
+                            CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
+      return 0;
+
+   if (CryptGenRandom(hProv, len, buf) == TRUE) {
+      CryptReleaseContext(hProv, 0);
+      return len;
+   } else {
+      CryptReleaseContext(hProv, 0);
+      return 0;
+   }
+}
+
+#endif /* WIN32 */
+
+unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, 
+                            void (*callback)(void))
+{
+   int x;
+
+   _ARGCHK(buf != NULL);
+
+#ifdef SONY_PS2
+   x = rng_ps2(buf, len, callback);   if (x) { return x; }
+#elif defined(DEVRANDOM)
+   x = rng_nix(buf, len, callback);   if (x) { return x; }
+#endif
+#ifdef WIN32
+   x = rng_win32(buf, len, callback); if (x) { return x; }
+#endif
+#ifdef ANSI_RNG
+   x = rng_ansic(buf, len, callback); if (x) { return x; }
+#endif
+   return 0;
+}
+
+int rng_make_prng(int bits, int wprng, prng_state *prng, 
+                  void (*callback)(void))
+{
+   unsigned char buf[256];
+   int errno;
+   
+   _ARGCHK(prng != NULL);
+
+   /* check parameter */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if (bits < 64 || bits > 1024) {
+      return CRYPT_INVALID_PRNGSIZE;
+   }
+
+   if ((errno = prng_descriptor[wprng].start(prng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   bits = ((bits/8)+(bits&7?1:0)) * 2;
+   if (rng_get_bytes(buf, bits, callback) != (unsigned long)bits) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   if ((errno = prng_descriptor[wprng].add_entropy(buf, bits, prng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((errno = prng_descriptor[wprng].ready(prng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   #ifdef CLEAN_STACK
+      zeromem(buf, sizeof(buf));
+   #endif
+   return CRYPT_OK;
+}
+

+ 691 - 0
blowfish.c

@@ -0,0 +1,691 @@
+#include "mycrypt.h"
+
+#ifdef BLOWFISH
+
+const struct _cipher_descriptor blowfish_desc =
+{
+    "blowfish",
+    0,
+    8, 56, 8, 16,
+    &blowfish_setup,
+    &blowfish_ecb_encrypt,
+    &blowfish_ecb_decrypt,
+    &blowfish_test,
+    &blowfish_keysize
+};
+
+static const unsigned long ORIG_P[16 + 2] = {
+        0x243F6A88UL, 0x85A308D3UL, 0x13198A2EUL, 0x03707344UL,
+        0xA4093822UL, 0x299F31D0UL, 0x082EFA98UL, 0xEC4E6C89UL,
+        0x452821E6UL, 0x38D01377UL, 0xBE5466CFUL, 0x34E90C6CUL,
+        0xC0AC29B7UL, 0xC97C50DDUL, 0x3F84D5B5UL, 0xB5470917UL,
+        0x9216D5D9UL, 0x8979FB1BUL
+};
+
+static const unsigned long ORIG_S[4][256] = {
+    {   0xD1310BA6UL, 0x98DFB5ACUL, 0x2FFD72DBUL, 0xD01ADFB7UL,
+        0xB8E1AFEDUL, 0x6A267E96UL, 0xBA7C9045UL, 0xF12C7F99UL,
+        0x24A19947UL, 0xB3916CF7UL, 0x0801F2E2UL, 0x858EFC16UL,
+        0x636920D8UL, 0x71574E69UL, 0xA458FEA3UL, 0xF4933D7EUL,
+        0x0D95748FUL, 0x728EB658UL, 0x718BCD58UL, 0x82154AEEUL,
+        0x7B54A41DUL, 0xC25A59B5UL, 0x9C30D539UL, 0x2AF26013UL,
+        0xC5D1B023UL, 0x286085F0UL, 0xCA417918UL, 0xB8DB38EFUL,
+        0x8E79DCB0UL, 0x603A180EUL, 0x6C9E0E8BUL, 0xB01E8A3EUL,
+        0xD71577C1UL, 0xBD314B27UL, 0x78AF2FDAUL, 0x55605C60UL,
+        0xE65525F3UL, 0xAA55AB94UL, 0x57489862UL, 0x63E81440UL,
+        0x55CA396AUL, 0x2AAB10B6UL, 0xB4CC5C34UL, 0x1141E8CEUL,
+        0xA15486AFUL, 0x7C72E993UL, 0xB3EE1411UL, 0x636FBC2AUL,
+        0x2BA9C55DUL, 0x741831F6UL, 0xCE5C3E16UL, 0x9B87931EUL,
+        0xAFD6BA33UL, 0x6C24CF5CUL, 0x7A325381UL, 0x28958677UL,
+        0x3B8F4898UL, 0x6B4BB9AFUL, 0xC4BFE81BUL, 0x66282193UL,
+        0x61D809CCUL, 0xFB21A991UL, 0x487CAC60UL, 0x5DEC8032UL,
+        0xEF845D5DUL, 0xE98575B1UL, 0xDC262302UL, 0xEB651B88UL,
+        0x23893E81UL, 0xD396ACC5UL, 0x0F6D6FF3UL, 0x83F44239UL,
+        0x2E0B4482UL, 0xA4842004UL, 0x69C8F04AUL, 0x9E1F9B5EUL,
+        0x21C66842UL, 0xF6E96C9AUL, 0x670C9C61UL, 0xABD388F0UL,
+        0x6A51A0D2UL, 0xD8542F68UL, 0x960FA728UL, 0xAB5133A3UL,
+        0x6EEF0B6CUL, 0x137A3BE4UL, 0xBA3BF050UL, 0x7EFB2A98UL,
+        0xA1F1651DUL, 0x39AF0176UL, 0x66CA593EUL, 0x82430E88UL,
+        0x8CEE8619UL, 0x456F9FB4UL, 0x7D84A5C3UL, 0x3B8B5EBEUL,
+        0xE06F75D8UL, 0x85C12073UL, 0x401A449FUL, 0x56C16AA6UL,
+        0x4ED3AA62UL, 0x363F7706UL, 0x1BFEDF72UL, 0x429B023DUL,
+        0x37D0D724UL, 0xD00A1248UL, 0xDB0FEAD3UL, 0x49F1C09BUL,
+        0x075372C9UL, 0x80991B7BUL, 0x25D479D8UL, 0xF6E8DEF7UL,
+        0xE3FE501AUL, 0xB6794C3BUL, 0x976CE0BDUL, 0x04C006BAUL,
+        0xC1A94FB6UL, 0x409F60C4UL, 0x5E5C9EC2UL, 0x196A2463UL,
+        0x68FB6FAFUL, 0x3E6C53B5UL, 0x1339B2EBUL, 0x3B52EC6FUL,
+        0x6DFC511FUL, 0x9B30952CUL, 0xCC814544UL, 0xAF5EBD09UL,
+        0xBEE3D004UL, 0xDE334AFDUL, 0x660F2807UL, 0x192E4BB3UL,
+        0xC0CBA857UL, 0x45C8740FUL, 0xD20B5F39UL, 0xB9D3FBDBUL,
+        0x5579C0BDUL, 0x1A60320AUL, 0xD6A100C6UL, 0x402C7279UL,
+        0x679F25FEUL, 0xFB1FA3CCUL, 0x8EA5E9F8UL, 0xDB3222F8UL,
+        0x3C7516DFUL, 0xFD616B15UL, 0x2F501EC8UL, 0xAD0552ABUL,
+        0x323DB5FAUL, 0xFD238760UL, 0x53317B48UL, 0x3E00DF82UL,
+        0x9E5C57BBUL, 0xCA6F8CA0UL, 0x1A87562EUL, 0xDF1769DBUL,
+        0xD542A8F6UL, 0x287EFFC3UL, 0xAC6732C6UL, 0x8C4F5573UL,
+        0x695B27B0UL, 0xBBCA58C8UL, 0xE1FFA35DUL, 0xB8F011A0UL,
+        0x10FA3D98UL, 0xFD2183B8UL, 0x4AFCB56CUL, 0x2DD1D35BUL,
+        0x9A53E479UL, 0xB6F84565UL, 0xD28E49BCUL, 0x4BFB9790UL,
+        0xE1DDF2DAUL, 0xA4CB7E33UL, 0x62FB1341UL, 0xCEE4C6E8UL,
+        0xEF20CADAUL, 0x36774C01UL, 0xD07E9EFEUL, 0x2BF11FB4UL,
+        0x95DBDA4DUL, 0xAE909198UL, 0xEAAD8E71UL, 0x6B93D5A0UL,
+        0xD08ED1D0UL, 0xAFC725E0UL, 0x8E3C5B2FUL, 0x8E7594B7UL,
+        0x8FF6E2FBUL, 0xF2122B64UL, 0x8888B812UL, 0x900DF01CUL,
+        0x4FAD5EA0UL, 0x688FC31CUL, 0xD1CFF191UL, 0xB3A8C1ADUL,
+        0x2F2F2218UL, 0xBE0E1777UL, 0xEA752DFEUL, 0x8B021FA1UL,
+        0xE5A0CC0FUL, 0xB56F74E8UL, 0x18ACF3D6UL, 0xCE89E299UL,
+        0xB4A84FE0UL, 0xFD13E0B7UL, 0x7CC43B81UL, 0xD2ADA8D9UL,
+        0x165FA266UL, 0x80957705UL, 0x93CC7314UL, 0x211A1477UL,
+        0xE6AD2065UL, 0x77B5FA86UL, 0xC75442F5UL, 0xFB9D35CFUL,
+        0xEBCDAF0CUL, 0x7B3E89A0UL, 0xD6411BD3UL, 0xAE1E7E49UL,
+        0x00250E2DUL, 0x2071B35EUL, 0x226800BBUL, 0x57B8E0AFUL,
+        0x2464369BUL, 0xF009B91EUL, 0x5563911DUL, 0x59DFA6AAUL,
+        0x78C14389UL, 0xD95A537FUL, 0x207D5BA2UL, 0x02E5B9C5UL,
+        0x83260376UL, 0x6295CFA9UL, 0x11C81968UL, 0x4E734A41UL,
+        0xB3472DCAUL, 0x7B14A94AUL, 0x1B510052UL, 0x9A532915UL,
+        0xD60F573FUL, 0xBC9BC6E4UL, 0x2B60A476UL, 0x81E67400UL,
+        0x08BA6FB5UL, 0x571BE91FUL, 0xF296EC6BUL, 0x2A0DD915UL,
+        0xB6636521UL, 0xE7B9F9B6UL, 0xFF34052EUL, 0xC5855664UL,
+        0x53B02D5DUL, 0xA99F8FA1UL, 0x08BA4799UL, 0x6E85076AUL   },
+    {   0x4B7A70E9UL, 0xB5B32944UL, 0xDB75092EUL, 0xC4192623UL,
+        0xAD6EA6B0UL, 0x49A7DF7DUL, 0x9CEE60B8UL, 0x8FEDB266UL,
+        0xECAA8C71UL, 0x699A17FFUL, 0x5664526CUL, 0xC2B19EE1UL,
+        0x193602A5UL, 0x75094C29UL, 0xA0591340UL, 0xE4183A3EUL,
+        0x3F54989AUL, 0x5B429D65UL, 0x6B8FE4D6UL, 0x99F73FD6UL,
+        0xA1D29C07UL, 0xEFE830F5UL, 0x4D2D38E6UL, 0xF0255DC1UL,
+        0x4CDD2086UL, 0x8470EB26UL, 0x6382E9C6UL, 0x021ECC5EUL,
+        0x09686B3FUL, 0x3EBAEFC9UL, 0x3C971814UL, 0x6B6A70A1UL,
+        0x687F3584UL, 0x52A0E286UL, 0xB79C5305UL, 0xAA500737UL,
+        0x3E07841CUL, 0x7FDEAE5CUL, 0x8E7D44ECUL, 0x5716F2B8UL,
+        0xB03ADA37UL, 0xF0500C0DUL, 0xF01C1F04UL, 0x0200B3FFUL,
+        0xAE0CF51AUL, 0x3CB574B2UL, 0x25837A58UL, 0xDC0921BDUL,
+        0xD19113F9UL, 0x7CA92FF6UL, 0x94324773UL, 0x22F54701UL,
+        0x3AE5E581UL, 0x37C2DADCUL, 0xC8B57634UL, 0x9AF3DDA7UL,
+        0xA9446146UL, 0x0FD0030EUL, 0xECC8C73EUL, 0xA4751E41UL,
+        0xE238CD99UL, 0x3BEA0E2FUL, 0x3280BBA1UL, 0x183EB331UL,
+        0x4E548B38UL, 0x4F6DB908UL, 0x6F420D03UL, 0xF60A04BFUL,
+        0x2CB81290UL, 0x24977C79UL, 0x5679B072UL, 0xBCAF89AFUL,
+        0xDE9A771FUL, 0xD9930810UL, 0xB38BAE12UL, 0xDCCF3F2EUL,
+        0x5512721FUL, 0x2E6B7124UL, 0x501ADDE6UL, 0x9F84CD87UL,
+        0x7A584718UL, 0x7408DA17UL, 0xBC9F9ABCUL, 0xE94B7D8CUL,
+        0xEC7AEC3AUL, 0xDB851DFAUL, 0x63094366UL, 0xC464C3D2UL,
+        0xEF1C1847UL, 0x3215D908UL, 0xDD433B37UL, 0x24C2BA16UL,
+        0x12A14D43UL, 0x2A65C451UL, 0x50940002UL, 0x133AE4DDUL,
+        0x71DFF89EUL, 0x10314E55UL, 0x81AC77D6UL, 0x5F11199BUL,
+        0x043556F1UL, 0xD7A3C76BUL, 0x3C11183BUL, 0x5924A509UL,
+        0xF28FE6EDUL, 0x97F1FBFAUL, 0x9EBABF2CUL, 0x1E153C6EUL,
+        0x86E34570UL, 0xEAE96FB1UL, 0x860E5E0AUL, 0x5A3E2AB3UL,
+        0x771FE71CUL, 0x4E3D06FAUL, 0x2965DCB9UL, 0x99E71D0FUL,
+        0x803E89D6UL, 0x5266C825UL, 0x2E4CC978UL, 0x9C10B36AUL,
+        0xC6150EBAUL, 0x94E2EA78UL, 0xA5FC3C53UL, 0x1E0A2DF4UL,
+        0xF2F74EA7UL, 0x361D2B3DUL, 0x1939260FUL, 0x19C27960UL,
+        0x5223A708UL, 0xF71312B6UL, 0xEBADFE6EUL, 0xEAC31F66UL,
+        0xE3BC4595UL, 0xA67BC883UL, 0xB17F37D1UL, 0x018CFF28UL,
+        0xC332DDEFUL, 0xBE6C5AA5UL, 0x65582185UL, 0x68AB9802UL,
+        0xEECEA50FUL, 0xDB2F953BUL, 0x2AEF7DADUL, 0x5B6E2F84UL,
+        0x1521B628UL, 0x29076170UL, 0xECDD4775UL, 0x619F1510UL,
+        0x13CCA830UL, 0xEB61BD96UL, 0x0334FE1EUL, 0xAA0363CFUL,
+        0xB5735C90UL, 0x4C70A239UL, 0xD59E9E0BUL, 0xCBAADE14UL,
+        0xEECC86BCUL, 0x60622CA7UL, 0x9CAB5CABUL, 0xB2F3846EUL,
+        0x648B1EAFUL, 0x19BDF0CAUL, 0xA02369B9UL, 0x655ABB50UL,
+        0x40685A32UL, 0x3C2AB4B3UL, 0x319EE9D5UL, 0xC021B8F7UL,
+        0x9B540B19UL, 0x875FA099UL, 0x95F7997EUL, 0x623D7DA8UL,
+        0xF837889AUL, 0x97E32D77UL, 0x11ED935FUL, 0x16681281UL,
+        0x0E358829UL, 0xC7E61FD6UL, 0x96DEDFA1UL, 0x7858BA99UL,
+        0x57F584A5UL, 0x1B227263UL, 0x9B83C3FFUL, 0x1AC24696UL,
+        0xCDB30AEBUL, 0x532E3054UL, 0x8FD948E4UL, 0x6DBC3128UL,
+        0x58EBF2EFUL, 0x34C6FFEAUL, 0xFE28ED61UL, 0xEE7C3C73UL,
+        0x5D4A14D9UL, 0xE864B7E3UL, 0x42105D14UL, 0x203E13E0UL,
+        0x45EEE2B6UL, 0xA3AAABEAUL, 0xDB6C4F15UL, 0xFACB4FD0UL,
+        0xC742F442UL, 0xEF6ABBB5UL, 0x654F3B1DUL, 0x41CD2105UL,
+        0xD81E799EUL, 0x86854DC7UL, 0xE44B476AUL, 0x3D816250UL,
+        0xCF62A1F2UL, 0x5B8D2646UL, 0xFC8883A0UL, 0xC1C7B6A3UL,
+        0x7F1524C3UL, 0x69CB7492UL, 0x47848A0BUL, 0x5692B285UL,
+        0x095BBF00UL, 0xAD19489DUL, 0x1462B174UL, 0x23820E00UL,
+        0x58428D2AUL, 0x0C55F5EAUL, 0x1DADF43EUL, 0x233F7061UL,
+        0x3372F092UL, 0x8D937E41UL, 0xD65FECF1UL, 0x6C223BDBUL,
+        0x7CDE3759UL, 0xCBEE7460UL, 0x4085F2A7UL, 0xCE77326EUL,
+        0xA6078084UL, 0x19F8509EUL, 0xE8EFD855UL, 0x61D99735UL,
+        0xA969A7AAUL, 0xC50C06C2UL, 0x5A04ABFCUL, 0x800BCADCUL,
+        0x9E447A2EUL, 0xC3453484UL, 0xFDD56705UL, 0x0E1E9EC9UL,
+        0xDB73DBD3UL, 0x105588CDUL, 0x675FDA79UL, 0xE3674340UL,
+        0xC5C43465UL, 0x713E38D8UL, 0x3D28F89EUL, 0xF16DFF20UL,
+        0x153E21E7UL, 0x8FB03D4AUL, 0xE6E39F2BUL, 0xDB83ADF7UL   },
+    {   0xE93D5A68UL, 0x948140F7UL, 0xF64C261CUL, 0x94692934UL,
+        0x411520F7UL, 0x7602D4F7UL, 0xBCF46B2EUL, 0xD4A20068UL,
+        0xD4082471UL, 0x3320F46AUL, 0x43B7D4B7UL, 0x500061AFUL,
+        0x1E39F62EUL, 0x97244546UL, 0x14214F74UL, 0xBF8B8840UL,
+        0x4D95FC1DUL, 0x96B591AFUL, 0x70F4DDD3UL, 0x66A02F45UL,
+        0xBFBC09ECUL, 0x03BD9785UL, 0x7FAC6DD0UL, 0x31CB8504UL,
+        0x96EB27B3UL, 0x55FD3941UL, 0xDA2547E6UL, 0xABCA0A9AUL,
+        0x28507825UL, 0x530429F4UL, 0x0A2C86DAUL, 0xE9B66DFBUL,
+        0x68DC1462UL, 0xD7486900UL, 0x680EC0A4UL, 0x27A18DEEUL,
+        0x4F3FFEA2UL, 0xE887AD8CUL, 0xB58CE006UL, 0x7AF4D6B6UL,
+        0xAACE1E7CUL, 0xD3375FECUL, 0xCE78A399UL, 0x406B2A42UL,
+        0x20FE9E35UL, 0xD9F385B9UL, 0xEE39D7ABUL, 0x3B124E8BUL,
+        0x1DC9FAF7UL, 0x4B6D1856UL, 0x26A36631UL, 0xEAE397B2UL,
+        0x3A6EFA74UL, 0xDD5B4332UL, 0x6841E7F7UL, 0xCA7820FBUL,
+        0xFB0AF54EUL, 0xD8FEB397UL, 0x454056ACUL, 0xBA489527UL,
+        0x55533A3AUL, 0x20838D87UL, 0xFE6BA9B7UL, 0xD096954BUL,
+        0x55A867BCUL, 0xA1159A58UL, 0xCCA92963UL, 0x99E1DB33UL,
+        0xA62A4A56UL, 0x3F3125F9UL, 0x5EF47E1CUL, 0x9029317CUL,
+        0xFDF8E802UL, 0x04272F70UL, 0x80BB155CUL, 0x05282CE3UL,
+        0x95C11548UL, 0xE4C66D22UL, 0x48C1133FUL, 0xC70F86DCUL,
+        0x07F9C9EEUL, 0x41041F0FUL, 0x404779A4UL, 0x5D886E17UL,
+        0x325F51EBUL, 0xD59BC0D1UL, 0xF2BCC18FUL, 0x41113564UL,
+        0x257B7834UL, 0x602A9C60UL, 0xDFF8E8A3UL, 0x1F636C1BUL,
+        0x0E12B4C2UL, 0x02E1329EUL, 0xAF664FD1UL, 0xCAD18115UL,
+        0x6B2395E0UL, 0x333E92E1UL, 0x3B240B62UL, 0xEEBEB922UL,
+        0x85B2A20EUL, 0xE6BA0D99UL, 0xDE720C8CUL, 0x2DA2F728UL,
+        0xD0127845UL, 0x95B794FDUL, 0x647D0862UL, 0xE7CCF5F0UL,
+        0x5449A36FUL, 0x877D48FAUL, 0xC39DFD27UL, 0xF33E8D1EUL,
+        0x0A476341UL, 0x992EFF74UL, 0x3A6F6EABUL, 0xF4F8FD37UL,
+        0xA812DC60UL, 0xA1EBDDF8UL, 0x991BE14CUL, 0xDB6E6B0DUL,
+        0xC67B5510UL, 0x6D672C37UL, 0x2765D43BUL, 0xDCD0E804UL,
+        0xF1290DC7UL, 0xCC00FFA3UL, 0xB5390F92UL, 0x690FED0BUL,
+        0x667B9FFBUL, 0xCEDB7D9CUL, 0xA091CF0BUL, 0xD9155EA3UL,
+        0xBB132F88UL, 0x515BAD24UL, 0x7B9479BFUL, 0x763BD6EBUL,
+        0x37392EB3UL, 0xCC115979UL, 0x8026E297UL, 0xF42E312DUL,
+        0x6842ADA7UL, 0xC66A2B3BUL, 0x12754CCCUL, 0x782EF11CUL,
+        0x6A124237UL, 0xB79251E7UL, 0x06A1BBE6UL, 0x4BFB6350UL,
+        0x1A6B1018UL, 0x11CAEDFAUL, 0x3D25BDD8UL, 0xE2E1C3C9UL,
+        0x44421659UL, 0x0A121386UL, 0xD90CEC6EUL, 0xD5ABEA2AUL,
+        0x64AF674EUL, 0xDA86A85FUL, 0xBEBFE988UL, 0x64E4C3FEUL,
+        0x9DBC8057UL, 0xF0F7C086UL, 0x60787BF8UL, 0x6003604DUL,
+        0xD1FD8346UL, 0xF6381FB0UL, 0x7745AE04UL, 0xD736FCCCUL,
+        0x83426B33UL, 0xF01EAB71UL, 0xB0804187UL, 0x3C005E5FUL,
+        0x77A057BEUL, 0xBDE8AE24UL, 0x55464299UL, 0xBF582E61UL,
+        0x4E58F48FUL, 0xF2DDFDA2UL, 0xF474EF38UL, 0x8789BDC2UL,
+        0x5366F9C3UL, 0xC8B38E74UL, 0xB475F255UL, 0x46FCD9B9UL,
+        0x7AEB2661UL, 0x8B1DDF84UL, 0x846A0E79UL, 0x915F95E2UL,
+        0x466E598EUL, 0x20B45770UL, 0x8CD55591UL, 0xC902DE4CUL,
+        0xB90BACE1UL, 0xBB8205D0UL, 0x11A86248UL, 0x7574A99EUL,
+        0xB77F19B6UL, 0xE0A9DC09UL, 0x662D09A1UL, 0xC4324633UL,
+        0xE85A1F02UL, 0x09F0BE8CUL, 0x4A99A025UL, 0x1D6EFE10UL,
+        0x1AB93D1DUL, 0x0BA5A4DFUL, 0xA186F20FUL, 0x2868F169UL,
+        0xDCB7DA83UL, 0x573906FEUL, 0xA1E2CE9BUL, 0x4FCD7F52UL,
+        0x50115E01UL, 0xA70683FAUL, 0xA002B5C4UL, 0x0DE6D027UL,
+        0x9AF88C27UL, 0x773F8641UL, 0xC3604C06UL, 0x61A806B5UL,
+        0xF0177A28UL, 0xC0F586E0UL, 0x006058AAUL, 0x30DC7D62UL,
+        0x11E69ED7UL, 0x2338EA63UL, 0x53C2DD94UL, 0xC2C21634UL,
+        0xBBCBEE56UL, 0x90BCB6DEUL, 0xEBFC7DA1UL, 0xCE591D76UL,
+        0x6F05E409UL, 0x4B7C0188UL, 0x39720A3DUL, 0x7C927C24UL,
+        0x86E3725FUL, 0x724D9DB9UL, 0x1AC15BB4UL, 0xD39EB8FCUL,
+        0xED545578UL, 0x08FCA5B5UL, 0xD83D7CD3UL, 0x4DAD0FC4UL,
+        0x1E50EF5EUL, 0xB161E6F8UL, 0xA28514D9UL, 0x6C51133CUL,
+        0x6FD5C7E7UL, 0x56E14EC4UL, 0x362ABFCEUL, 0xDDC6C837UL,
+        0xD79A3234UL, 0x92638212UL, 0x670EFA8EUL, 0x406000E0UL  },
+    {   0x3A39CE37UL, 0xD3FAF5CFUL, 0xABC27737UL, 0x5AC52D1BUL,
+        0x5CB0679EUL, 0x4FA33742UL, 0xD3822740UL, 0x99BC9BBEUL,
+        0xD5118E9DUL, 0xBF0F7315UL, 0xD62D1C7EUL, 0xC700C47BUL,
+        0xB78C1B6BUL, 0x21A19045UL, 0xB26EB1BEUL, 0x6A366EB4UL,
+        0x5748AB2FUL, 0xBC946E79UL, 0xC6A376D2UL, 0x6549C2C8UL,
+        0x530FF8EEUL, 0x468DDE7DUL, 0xD5730A1DUL, 0x4CD04DC6UL,
+        0x2939BBDBUL, 0xA9BA4650UL, 0xAC9526E8UL, 0xBE5EE304UL,
+        0xA1FAD5F0UL, 0x6A2D519AUL, 0x63EF8CE2UL, 0x9A86EE22UL,
+        0xC089C2B8UL, 0x43242EF6UL, 0xA51E03AAUL, 0x9CF2D0A4UL,
+        0x83C061BAUL, 0x9BE96A4DUL, 0x8FE51550UL, 0xBA645BD6UL,
+        0x2826A2F9UL, 0xA73A3AE1UL, 0x4BA99586UL, 0xEF5562E9UL,
+        0xC72FEFD3UL, 0xF752F7DAUL, 0x3F046F69UL, 0x77FA0A59UL,
+        0x80E4A915UL, 0x87B08601UL, 0x9B09E6ADUL, 0x3B3EE593UL,
+        0xE990FD5AUL, 0x9E34D797UL, 0x2CF0B7D9UL, 0x022B8B51UL,
+        0x96D5AC3AUL, 0x017DA67DUL, 0xD1CF3ED6UL, 0x7C7D2D28UL,
+        0x1F9F25CFUL, 0xADF2B89BUL, 0x5AD6B472UL, 0x5A88F54CUL,
+        0xE029AC71UL, 0xE019A5E6UL, 0x47B0ACFDUL, 0xED93FA9BUL,
+        0xE8D3C48DUL, 0x283B57CCUL, 0xF8D56629UL, 0x79132E28UL,
+        0x785F0191UL, 0xED756055UL, 0xF7960E44UL, 0xE3D35E8CUL,
+        0x15056DD4UL, 0x88F46DBAUL, 0x03A16125UL, 0x0564F0BDUL,
+        0xC3EB9E15UL, 0x3C9057A2UL, 0x97271AECUL, 0xA93A072AUL,
+        0x1B3F6D9BUL, 0x1E6321F5UL, 0xF59C66FBUL, 0x26DCF319UL,
+        0x7533D928UL, 0xB155FDF5UL, 0x03563482UL, 0x8ABA3CBBUL,
+        0x28517711UL, 0xC20AD9F8UL, 0xABCC5167UL, 0xCCAD925FUL,
+        0x4DE81751UL, 0x3830DC8EUL, 0x379D5862UL, 0x9320F991UL,
+        0xEA7A90C2UL, 0xFB3E7BCEUL, 0x5121CE64UL, 0x774FBE32UL,
+        0xA8B6E37EUL, 0xC3293D46UL, 0x48DE5369UL, 0x6413E680UL,
+        0xA2AE0810UL, 0xDD6DB224UL, 0x69852DFDUL, 0x09072166UL,
+        0xB39A460AUL, 0x6445C0DDUL, 0x586CDECFUL, 0x1C20C8AEUL,
+        0x5BBEF7DDUL, 0x1B588D40UL, 0xCCD2017FUL, 0x6BB4E3BBUL,
+        0xDDA26A7EUL, 0x3A59FF45UL, 0x3E350A44UL, 0xBCB4CDD5UL,
+        0x72EACEA8UL, 0xFA6484BBUL, 0x8D6612AEUL, 0xBF3C6F47UL,
+        0xD29BE463UL, 0x542F5D9EUL, 0xAEC2771BUL, 0xF64E6370UL,
+        0x740E0D8DUL, 0xE75B1357UL, 0xF8721671UL, 0xAF537D5DUL,
+        0x4040CB08UL, 0x4EB4E2CCUL, 0x34D2466AUL, 0x0115AF84UL,
+        0xE1B00428UL, 0x95983A1DUL, 0x06B89FB4UL, 0xCE6EA048UL,
+        0x6F3F3B82UL, 0x3520AB82UL, 0x011A1D4BUL, 0x277227F8UL,
+        0x611560B1UL, 0xE7933FDCUL, 0xBB3A792BUL, 0x344525BDUL,
+        0xA08839E1UL, 0x51CE794BUL, 0x2F32C9B7UL, 0xA01FBAC9UL,
+        0xE01CC87EUL, 0xBCC7D1F6UL, 0xCF0111C3UL, 0xA1E8AAC7UL,
+        0x1A908749UL, 0xD44FBD9AUL, 0xD0DADECBUL, 0xD50ADA38UL,
+        0x0339C32AUL, 0xC6913667UL, 0x8DF9317CUL, 0xE0B12B4FUL,
+        0xF79E59B7UL, 0x43F5BB3AUL, 0xF2D519FFUL, 0x27D9459CUL,
+        0xBF97222CUL, 0x15E6FC2AUL, 0x0F91FC71UL, 0x9B941525UL,
+        0xFAE59361UL, 0xCEB69CEBUL, 0xC2A86459UL, 0x12BAA8D1UL,
+        0xB6C1075EUL, 0xE3056A0CUL, 0x10D25065UL, 0xCB03A442UL,
+        0xE0EC6E0EUL, 0x1698DB3BUL, 0x4C98A0BEUL, 0x3278E964UL,
+        0x9F1F9532UL, 0xE0D392DFUL, 0xD3A0342BUL, 0x8971F21EUL,
+        0x1B0A7441UL, 0x4BA3348CUL, 0xC5BE7120UL, 0xC37632D8UL,
+        0xDF359F8DUL, 0x9B992F2EUL, 0xE60B6F47UL, 0x0FE3F11DUL,
+        0xE54CDA54UL, 0x1EDAD891UL, 0xCE6279CFUL, 0xCD3E7E6FUL,
+        0x1618B166UL, 0xFD2C1D05UL, 0x848FD2C5UL, 0xF6FB2299UL,
+        0xF523F357UL, 0xA6327623UL, 0x93A83531UL, 0x56CCCD02UL,
+        0xACF08162UL, 0x5A75EBB5UL, 0x6E163697UL, 0x88D273CCUL,
+        0xDE966292UL, 0x81B949D0UL, 0x4C50901BUL, 0x71C65614UL,
+        0xE6C6C7BDUL, 0x327A140AUL, 0x45E1D006UL, 0xC3F27B9AUL,
+        0xC9AA53FDUL, 0x62A80F00UL, 0xBB25BFE2UL, 0x35BDD2F6UL,
+        0x71126905UL, 0xB2040222UL, 0xB6CBCF7CUL, 0xCD769C2BUL,
+        0x53113EC0UL, 0x1640E3D3UL, 0x38ABBD60UL, 0x2547ADF0UL,
+        0xBA38209CUL, 0xF746CE76UL, 0x77AFA1C5UL, 0x20756060UL,
+        0x85CBFE4EUL, 0x8AE88DD8UL, 0x7AAAF9B0UL, 0x4CF9AA7EUL,
+        0x1948C25CUL, 0x02FB8A8CUL, 0x01C36AE4UL, 0xD6EBE1F9UL,
+        0x90D4F869UL, 0xA65CDEA0UL, 0x3F09252DUL, 0xC208E69FUL,
+        0xB74E6132UL, 0xCE77E25BUL, 0x578FDFE3UL, 0x3AC372E6UL  }
+};
+
+static unsigned long F(unsigned long x, symmetric_key *key)
+{
+   return (((key->blowfish.S[0][(x>>24)&255] +
+            key->blowfish.S[1][(x>>16)&255]) ^
+            key->blowfish.S[2][(x>>8)&255]) +
+            key->blowfish.S[3][(x>>0)&255]);
+}
+
+int blowfish_setup(const unsigned char *key, int keylen, int num_rounds,
+                   symmetric_key *skey)
+{
+   unsigned long x, y, z, A;
+   unsigned char B[8];
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* check key length */
+   if (keylen < 8 || keylen > 56) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* check rounds */
+   if (num_rounds != 0 && num_rounds != 16) {
+      return CRYPT_INVALID_ROUNDS;
+   }   
+
+   /* load in key bytes (Supplied by David Hopwood) */
+   for (x = y = 0; x < 18; x++) {
+       A = 0;
+       for (z = 0; z < 4; z++) {
+           A = (A << 8) | (unsigned long) key[y++ % keylen];
+       }
+       skey->blowfish.K[x] = ORIG_P[x] ^ A;
+   }
+
+   /* copy sboxes */
+   for (x = 0; x < 4; x++) {
+       for (y = 0; y < 256; y++) {
+           skey->blowfish.S[x][y] = ORIG_S[x][y];
+       }
+   }
+
+   /* encrypt K array */
+   zeromem(B, 8);
+   for (x = 0; x < 18; x += 2) {
+       /* encrypt it */
+       blowfish_ecb_encrypt(B, B, skey);
+       /* copy it */
+       LOAD32H(skey->blowfish.K[x], &B[0]);
+       LOAD32H(skey->blowfish.K[x+1], &B[4]);
+   }
+
+   /* encrypt S array */
+   for (x = 0; x < 4; x++) {
+       for (y = 0; y < 256; y += 2) {
+          /* encrypt it */
+          blowfish_ecb_encrypt(B, B, skey);
+          /* copy it */
+          LOAD32H(skey->blowfish.S[x][y], &B[0]);
+          LOAD32H(skey->blowfish.S[x][y+1], &B[4]);
+       }
+   }
+
+#ifdef CLEAN_STACK
+   zeromem(B, sizeof(B));
+#endif
+
+   return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+static void _blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#else
+void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#endif
+{
+   unsigned long L, R;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   /* load it */
+   LOAD32H(L, &pt[0]);
+   LOAD32H(R, &pt[4]);
+
+   /* do 16 rounds */
+   L ^= key->blowfish.K[0];  R ^= F(L, key);
+   R ^= key->blowfish.K[1];  L ^= F(R, key);
+   L ^= key->blowfish.K[2];  R ^= F(L, key);
+   R ^= key->blowfish.K[3];  L ^= F(R, key);
+   L ^= key->blowfish.K[4];  R ^= F(L, key);
+   R ^= key->blowfish.K[5];  L ^= F(R, key);
+   L ^= key->blowfish.K[6];  R ^= F(L, key);
+   R ^= key->blowfish.K[7];  L ^= F(R, key);
+   L ^= key->blowfish.K[8];  R ^= F(L, key);
+   R ^= key->blowfish.K[9];  L ^= F(R, key);
+   L ^= key->blowfish.K[10]; R ^= F(L, key);
+   R ^= key->blowfish.K[11]; L ^= F(R, key);
+   L ^= key->blowfish.K[12]; R ^= F(L, key);
+   R ^= key->blowfish.K[13]; L ^= F(R, key);
+   L ^= key->blowfish.K[14]; R ^= F(L, key);
+   R ^= key->blowfish.K[15]; L ^= F(R, key);
+
+   /* last keying */
+   R ^= key->blowfish.K[17];
+   L ^= key->blowfish.K[16];
+
+   /* store */
+   STORE32H(R, &ct[0]);
+   STORE32H(L, &ct[4]);
+}
+
+#ifdef CLEAN_STACK
+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);
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#else
+void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#endif
+{
+   unsigned long L, R;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   /* load it */
+   LOAD32H(R, &ct[0]);
+   LOAD32H(L, &ct[4]);
+
+   /* undo last keying */
+   R ^= key->blowfish.K[17];
+   L ^= key->blowfish.K[16];
+
+   /* do 16 rounds */
+   L ^= F(R, key); R ^= key->blowfish.K[15];
+   R ^= F(L, key); L ^= key->blowfish.K[14];
+   L ^= F(R, key); R ^= key->blowfish.K[13];
+   R ^= F(L, key); L ^= key->blowfish.K[12];
+   L ^= F(R, key); R ^= key->blowfish.K[11];
+   R ^= F(L, key); L ^= key->blowfish.K[10];
+   L ^= F(R, key); R ^= key->blowfish.K[9];
+   R ^= F(L, key); L ^= key->blowfish.K[8];
+   L ^= F(R, key); R ^= key->blowfish.K[7];
+   R ^= F(L, key); L ^= key->blowfish.K[6];
+   L ^= F(R, key); R ^= key->blowfish.K[5];
+   R ^= F(L, key); L ^= key->blowfish.K[4];
+   L ^= F(R, key); R ^= key->blowfish.K[3];
+   R ^= F(L, key); L ^= key->blowfish.K[2];
+   L ^= F(R, key); R ^= key->blowfish.K[1];
+   R ^= F(L, key); L ^= key->blowfish.K[0];
+
+   /* store */
+   STORE32H(L, &pt[0]);
+   STORE32H(R, &pt[4]);
+}
+
+#ifdef CLEAN_STACK
+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);
+}
+#endif
+
+
+int blowfish_test(void)
+{
+   int errno;
+   symmetric_key key;
+   static const struct {
+          unsigned char key[8], pt[8], ct[8];
+   } tests[] = {
+       {
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}
+       },
+       {
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}
+       },
+       {
+           { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+           { 0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}
+       },
+       {
+           { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+           { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+           { 0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}
+       },
+       {
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+           { 0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}
+       },
+       {
+           { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}
+       },
+       {
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}
+       },
+       {
+           { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}
+       },
+       {
+           { 0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+           { 0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+           { 0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}
+       },
+       {
+           { 0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+           { 0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+           { 0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}
+       },
+       {
+           { 0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+           { 0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+           { 0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}
+       },
+       {
+           { 0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+           { 0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+           { 0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}
+       },
+       {
+           { 0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+           { 0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+           { 0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}
+       },
+       {
+           { 0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+           { 0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+           { 0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}
+       },
+       {
+           { 0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+           { 0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+           { 0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}
+       },
+       {
+           { 0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+           { 0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+           { 0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}
+       },
+       {
+           { 0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+           { 0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+           { 0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}
+       },
+       {
+           { 0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+           { 0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+           { 0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}
+       },
+       {
+           { 0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+           { 0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+           { 0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}
+       },
+       {
+           { 0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+           { 0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+           { 0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}
+       },
+       {
+           { 0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+           { 0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+           { 0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}
+       },
+       {
+           { 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+           { 0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+           { 0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}
+       },
+       {
+           { 0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+           { 0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+           { 0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}
+       },
+       {
+           { 0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+           { 0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+           { 0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}
+       },
+       {
+           { 0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+           { 0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+           { 0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}
+       },
+       {
+           { 0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+           { 0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+           { 0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}
+       },
+       {
+           { 0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+           { 0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+           { 0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}
+       },
+       {
+           { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}
+       },
+       {
+           { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}
+       },
+       {
+           { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}
+       },
+       {
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}
+       },
+       {
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}
+       },
+       {
+           { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}
+       },
+       {
+           { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}
+       }
+   };
+   unsigned char buf[2][8];
+   int x, failed;
+
+   for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((errno = blowfish_setup(tests[x].key, 8, 16, &key)) != CRYPT_OK) {
+         return errno;
+      }
+
+      /* encrypt and decrypt */
+      blowfish_ecb_encrypt(tests[x].pt, buf[0], &key);
+      blowfish_ecb_decrypt(buf[0], buf[1], &key);
+
+      /* compare */
+      if (memcmp(buf[0], tests[x].ct, 8)) {
+#if 0
+         int y;
+         printf("\nEncrypt test %d failed\n", x);
+         for (y = 0; y < 8; y++) printf("%02x ", buf[0][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+
+      if (memcmp(buf[1], tests[x].pt, 8)) {
+#if 0
+         int y;
+         printf("\nDecrypt test %d failed\n", x);
+         for (y = 0; y < 8; y++) printf("%02x ", buf[1][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+   }
+
+   if (failed == 1) {
+      return CRYPT_FAIL_TESTVECTOR;
+   } else {
+      return CRYPT_OK;
+   }
+}
+
+int blowfish_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+
+   if (*desired_keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*desired_keysize > 56) {
+      *desired_keysize = 56;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+

+ 622 - 0
cast5.c

@@ -0,0 +1,622 @@
+/* Implementation of CAST5 (RFC 2144) by Tom St Denis */
+#include "mycrypt.h"
+
+#ifdef CAST5
+
+const struct _cipher_descriptor cast5_desc = {
+   "cast5",
+   15,
+   5, 16, 8, 16,
+   &cast5_setup,
+   &cast5_ecb_encrypt,
+   &cast5_ecb_decrypt,
+   &cast5_test,
+   &cast5_keysize
+};
+
+static const unsigned long S1[256] = {
+0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 
+0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 
+0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, 
+0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, 
+0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 
+0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 
+0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, 
+0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, 
+0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 
+0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 
+0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38, 
+0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, 
+0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 
+0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 
+0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, 
+0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, 
+0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 
+0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 
+0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8, 
+0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, 
+0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 
+0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 
+0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, 
+0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, 
+0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 
+0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 
+0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad, 
+0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, 
+0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 
+0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 
+0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153, 
+0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, 
+0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 
+0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 
+0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1, 
+0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, 
+0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 
+0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 
+0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, 0x474d6ad7, 0x7c0c5e5c, 
+0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, 
+0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 
+0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 
+0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf};
+
+static const unsigned long S2[256] = {
+0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 
+0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 
+0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, 
+0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, 
+0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 
+0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 
+0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, 
+0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, 
+0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 
+0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 
+0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, 
+0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, 
+0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 
+0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 
+0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, 
+0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, 
+0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 
+0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 
+0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, 
+0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, 
+0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 
+0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 
+0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, 
+0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, 
+0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 
+0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 
+0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, 
+0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, 
+0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 
+0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 
+0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, 
+0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, 
+0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 
+0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 
+0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, 
+0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, 
+0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 
+0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 
+0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, 
+0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, 
+0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 
+0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 
+0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1};
+
+static const unsigned long S3[256] = {
+0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 
+0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 
+0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9, 
+0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, 
+0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 
+0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 
+0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264, 
+0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, 
+0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 
+0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 
+0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, 
+0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, 
+0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 
+0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 
+0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, 
+0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, 
+0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 
+0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 
+0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, 
+0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, 
+0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 
+0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 
+0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, 
+0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, 
+0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 
+0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 
+0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, 
+0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, 
+0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 
+0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 
+0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, 
+0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, 
+0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 
+0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 
+0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, 
+0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, 
+0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 
+0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 
+0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, 
+0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, 
+0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 
+0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 
+0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783};
+
+static const unsigned long S4[256] = {
+0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 
+0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 
+0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, 
+0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, 
+0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 
+0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 
+0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, 
+0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, 
+0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 
+0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 
+0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, 
+0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, 
+0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 
+0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 
+0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, 
+0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, 
+0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 
+0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 
+0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, 
+0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, 
+0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 
+0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 
+0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, 
+0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, 
+0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 
+0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 
+0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, 
+0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, 
+0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 
+0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 
+0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6, 
+0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, 
+0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 
+0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 
+0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, 
+0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, 
+0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 
+0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 
+0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda, 
+0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, 
+0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 
+0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 
+0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2};
+
+static const unsigned long S5[256] = {
+0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 
+0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 
+0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd, 
+0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, 
+0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 
+0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 
+0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040, 
+0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, 
+0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 
+0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 
+0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399, 
+0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, 
+0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 
+0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 
+0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9, 
+0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, 
+0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 
+0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 
+0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419, 
+0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, 
+0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 
+0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 
+0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c, 
+0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, 
+0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 
+0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 
+0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d, 
+0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, 
+0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 
+0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 
+0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4, 
+0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, 
+0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 
+0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 
+0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87, 
+0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, 
+0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 
+0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 
+0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3, 
+0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, 
+0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 
+0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 
+0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4};
+
+static const unsigned long S6[256] = {
+0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 
+0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 
+0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd, 
+0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, 
+0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 
+0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 
+0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0, 
+0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, 
+0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 
+0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 
+0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223, 
+0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, 
+0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 
+0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 
+0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7, 
+0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, 
+0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 
+0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 
+0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0, 
+0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, 
+0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 
+0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 
+0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87, 
+0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, 
+0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 
+0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 
+0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75, 
+0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, 
+0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 
+0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 
+0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef, 
+0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, 
+0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 
+0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 
+0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200, 
+0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, 
+0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 
+0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 
+0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869, 
+0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, 
+0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 
+0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 
+0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f};
+
+static const unsigned long S7[256] = {
+0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 
+0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 
+0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9, 
+0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, 
+0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 
+0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 
+0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce, 
+0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, 
+0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 
+0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 
+0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e, 
+0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, 
+0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 
+0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 
+0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3, 
+0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, 
+0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 
+0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 
+0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778, 
+0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, 
+0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 
+0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 
+0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310, 
+0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, 
+0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 
+0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 
+0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70, 
+0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, 
+0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 
+0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 
+0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c, 
+0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, 
+0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 
+0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 
+0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e, 
+0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, 
+0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 
+0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 
+0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4, 
+0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, 
+0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 
+0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 
+0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3};
+
+static const unsigned long S8[256] = {
+0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 
+0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 
+0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c, 
+0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, 
+0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 
+0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 
+0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d, 
+0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, 
+0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 
+0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 
+0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04, 
+0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, 
+0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 
+0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 
+0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354, 
+0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, 
+0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 
+0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 
+0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2, 
+0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, 
+0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 
+0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 
+0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4, 
+0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, 
+0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 
+0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 
+0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5, 
+0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, 
+0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 
+0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 
+0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084, 
+0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, 
+0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 
+0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 
+0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77, 
+0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, 
+0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 
+0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 
+0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3, 
+0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, 
+0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 
+0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 
+0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e};
+
+/* returns the i'th byte of a variable */
+#define GB(x, i) (((x[(15-i)>>2])>>(8*((15-i)&3)))&255)
+
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   unsigned long x[4], z[4];
+   unsigned char buf[16];
+   int y, i;
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (num_rounds != 12 && num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS; 
+   }
+ 
+   if (num_rounds == 12 && keylen > 10) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen < 5 || keylen > 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* extend the key as required */
+   zeromem(buf, sizeof(buf));
+   memcpy(buf, key, keylen);
+
+   /* load and start the awful looking network */
+   for (y = 0; y < 4; y++) {
+       LOAD32H(x[3-y],buf+4*y);
+   }
+
+   for (i = y = 0; y < 2; y++) {
+        z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)];
+        z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)];
+        z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)];
+        z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)];
+        skey->cast5.K[i++] = S5[GB(z, 0x8)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0x7)] ^ S8[GB(z, 0x6)] ^ S5[GB(z, 0x2)];
+        skey->cast5.K[i++] = S5[GB(z, 0xA)] ^ S6[GB(z, 0xB)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S6[GB(z, 0x6)];
+        skey->cast5.K[i++] = S5[GB(z, 0xC)] ^ S6[GB(z, 0xd)] ^ S7[GB(z, 0x3)] ^ S8[GB(z, 0x2)] ^ S7[GB(z, 0x9)];
+        skey->cast5.K[i++] = S5[GB(z, 0xE)] ^ S6[GB(z, 0xF)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x0)] ^ S8[GB(z, 0xc)];
+
+        x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)];
+        x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)];
+        x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)];
+        x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x3)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0xc)] ^ S8[GB(x, 0xd)] ^ S5[GB(x, 0x8)];
+        skey->cast5.K[i++] = S5[GB(x, 0x1)] ^ S6[GB(x, 0x0)] ^ S7[GB(x, 0xe)] ^ S8[GB(x, 0xf)] ^ S6[GB(x, 0xd)];
+        skey->cast5.K[i++] = S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x8)] ^ S8[GB(x, 0x9)] ^ S7[GB(x, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x5)] ^ S6[GB(x, 0x4)] ^ S7[GB(x, 0xa)] ^ S8[GB(x, 0xb)] ^ S8[GB(x, 0x7)];
+
+        /* second half */
+
+        z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)];
+        z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)];
+        z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)];
+        z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)];
+        skey->cast5.K[i++] = S5[GB(z, 0x3)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0xc)] ^ S8[GB(z, 0xd)] ^ S5[GB(z, 0x9)];
+        skey->cast5.K[i++] = S5[GB(z, 0x1)] ^ S6[GB(z, 0x0)] ^ S7[GB(z, 0xe)] ^ S8[GB(z, 0xf)] ^ S6[GB(z, 0xc)];
+        skey->cast5.K[i++] = S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x8)] ^ S8[GB(z, 0x9)] ^ S7[GB(z, 0x2)];
+        skey->cast5.K[i++] = S5[GB(z, 0x5)] ^ S6[GB(z, 0x4)] ^ S7[GB(z, 0xa)] ^ S8[GB(z, 0xb)] ^ S8[GB(z, 0x6)];
+
+        x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)];
+        x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)];
+        x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)];
+        x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x8)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0x7)] ^ S8[GB(x, 0x6)] ^ S5[GB(x, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0xa)] ^ S6[GB(x, 0xb)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S6[GB(x, 0x7)];
+        skey->cast5.K[i++] = S5[GB(x, 0xc)] ^ S6[GB(x, 0xd)] ^ S7[GB(x, 0x3)] ^ S8[GB(x, 0x2)] ^ S7[GB(x, 0x8)];
+        skey->cast5.K[i++] = S5[GB(x, 0xe)] ^ S6[GB(x, 0xf)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x0)] ^ S8[GB(x, 0xd)];
+   }
+
+   skey->cast5.keylen = keylen;
+
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+   zeromem(x, sizeof(x));
+   zeromem(z, sizeof(z));
+#endif  
+
+   return CRYPT_OK;
+}
+
+static unsigned long FI(unsigned long R, unsigned long Km, unsigned long Kr)
+{
+   unsigned long I;
+   I = (Km + R);
+   I = ROL(I, Kr);
+   return ((S1[(I>>24)&255] ^ S2[(I>>16)&255]) - S3[(I>>8)&255]) + S4[I&255];
+}
+   
+static unsigned long FII(unsigned long R, unsigned long Km, unsigned long Kr)
+{
+   unsigned long I;
+   I = (Km ^ R);
+   I = ROL(I, Kr);
+   return ((S1[(I>>24)&255] - S2[(I>>16)&255]) + S3[(I>>8)&255]) ^ S4[I&255];
+}
+
+static unsigned long FIII(unsigned long R, unsigned long Km, unsigned long Kr)
+{
+   unsigned long I;
+   I = (Km - R);
+   I = ROL(I, Kr);
+   return ((S1[(I>>24)&255] + S2[(I>>16)&255]) ^ S3[(I>>8)&255]) - S4[I&255];
+}
+
+void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+{
+   unsigned long R, L;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   LOAD32H(L,&pt[0]); 
+   LOAD32H(R,&pt[4]);
+
+   L ^= FI(R, key->cast5.K[0], key->cast5.K[16]);
+   R ^= FII(L, key->cast5.K[1], key->cast5.K[17]);
+   L ^= FIII(R, key->cast5.K[2], key->cast5.K[18]);
+   R ^= FI(L, key->cast5.K[3], key->cast5.K[19]);
+   L ^= FII(R, key->cast5.K[4], key->cast5.K[20]);
+   R ^= FIII(L, key->cast5.K[5], key->cast5.K[21]);
+   L ^= FI(R, key->cast5.K[6], key->cast5.K[22]);
+   R ^= FII(L, key->cast5.K[7], key->cast5.K[23]);
+   L ^= FIII(R, key->cast5.K[8], key->cast5.K[24]);
+   R ^= FI(L, key->cast5.K[9], key->cast5.K[25]);
+   L ^= FII(R, key->cast5.K[10], key->cast5.K[26]);
+   R ^= FIII(L, key->cast5.K[11], key->cast5.K[27]);
+   if (key->cast5.keylen > 10) {
+      L ^= FI(R, key->cast5.K[12], key->cast5.K[28]);
+      R ^= FII(L, key->cast5.K[13], key->cast5.K[29]);
+      L ^= FIII(R, key->cast5.K[14], key->cast5.K[30]);
+      R ^= FI(L, key->cast5.K[15], key->cast5.K[31]);
+   }
+   STORE32H(R,&ct[0]);
+   STORE32H(L,&ct[4]);
+}
+
+void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+{
+   unsigned long R, L;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   LOAD32H(R,&ct[0]); 
+   LOAD32H(L,&ct[4]);
+
+   if (key->cast5.keylen > 10) {
+      R ^= FI(L, key->cast5.K[15], key->cast5.K[31]);
+      L ^= FIII(R, key->cast5.K[14], key->cast5.K[30]);
+      R ^= FII(L, key->cast5.K[13], key->cast5.K[29]);
+      L ^= FI(R, key->cast5.K[12], key->cast5.K[28]);
+   }
+
+   R ^= FIII(L, key->cast5.K[11], key->cast5.K[27]);
+   L ^= FII(R, key->cast5.K[10], key->cast5.K[26]);
+   R ^= FI(L, key->cast5.K[9], key->cast5.K[25]);
+   L ^= FIII(R, key->cast5.K[8], key->cast5.K[24]);
+   R ^= FII(L, key->cast5.K[7], key->cast5.K[23]);
+   L ^= FI(R, key->cast5.K[6], key->cast5.K[22]);
+   R ^= FIII(L, key->cast5.K[5], key->cast5.K[21]);
+   L ^= FII(R, key->cast5.K[4], key->cast5.K[20]);
+   R ^= FI(L, key->cast5.K[3], key->cast5.K[19]);
+   L ^= FIII(R, key->cast5.K[2], key->cast5.K[18]);
+   R ^= FII(L, key->cast5.K[1], key->cast5.K[17]);
+   L ^= FI(R, key->cast5.K[0], key->cast5.K[16]);
+
+   STORE32H(L,&pt[0]);
+   STORE32H(R,&pt[4]);
+}
+
+int cast5_test(void)
+{
+   static const struct {
+       int keylen;
+       unsigned char key[16];
+       unsigned char pt[8];
+       unsigned char ct[8];
+   } tests[] = {
+     { 16,
+       {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2}
+     },
+     { 10,
+       {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B},
+     },
+     { 5,
+       {0x01, 0x23, 0x45, 0x67, 0x12},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E}
+     }
+   };
+   int i, errno;
+   symmetric_key key;
+   unsigned char buf[8], buf2[8];
+
+   for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+       if ((errno = cast5_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
+          return errno;
+       }
+       cast5_ecb_encrypt(tests[i].pt, buf, &key);
+       if (memcmp(buf, tests[i].ct, 8)) {
+#if 0
+          int j;
+          printf("\n\n\nFailed encrypt test: %d\n", i);
+          for (j = 0; j < 8; j++) printf("%02x ", buf[j]);
+          printf("\n");
+#endif
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+       cast5_ecb_decrypt(buf, buf2, &key);
+       if (memcmp(buf2, tests[i].pt, 8)) {
+#if 0
+          int j;
+          printf("\n\n\nFailed decrypt test: %d\n", i);
+          for (j = 0; j < 8; j++) printf("%02x ", buf2[j]);
+          printf("\n");
+#endif
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   
+   }
+   return CRYPT_OK;
+}
+
+int cast5_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+   if (*desired_keysize < 5) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*desired_keysize > 16) {
+      *desired_keysize = 16;
+   }
+   return CRYPT_OK;
+} 
+
+#endif
+

+ 101 - 0
cbc.c

@@ -0,0 +1,101 @@
+#include "mycrypt.h"
+
+#ifdef CBC
+
+int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+              int keylen, int num_rounds, symmetric_CBC *cbc)
+{
+   int x, errno;
+ 
+   _ARGCHK(IV != NULL);
+   _ARGCHK(key != NULL);
+   _ARGCHK(cbc != NULL);
+
+   /* bad param? */
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* setup cipher */
+   if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cbc->key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* copy IV */
+   cbc->blocklen = cipher_descriptor[cipher].block_length;
+   cbc->cipher   = cipher;
+   for (x = 0; x < cbc->blocklen; x++) {
+       cbc->IV[x] = IV[x];
+   }
+   return CRYPT_OK;
+}
+
+int cbc_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_CBC *cbc)
+{
+   int x, errno;
+   unsigned char tmp[MAXBLOCKSIZE];
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(cbc != NULL);
+
+   if ((errno = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+
+   /* xor IV against plaintext */
+   for (x = 0; x < cbc->blocklen; x++) {
+       tmp[x] = pt[x] ^ cbc->IV[x];
+   }
+
+   /* encrypt */
+   cipher_descriptor[cbc->cipher].ecb_encrypt(tmp, ct, &cbc->key);
+
+   /* store IV [ciphertext] for a future block */
+   for (x = 0; x < cbc->blocklen; x++) {
+       cbc->IV[x] = ct[x];
+   }
+
+   #ifdef CLEAN_STACK
+      zeromem(tmp, sizeof(tmp));
+   #endif
+   return CRYPT_OK;
+}
+
+int cbc_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_CBC *cbc)
+{
+   int x, errno;
+   unsigned char tmp[MAXBLOCKSIZE], tmp2[MAXBLOCKSIZE];
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(cbc != NULL);
+
+   /* decrypt the block from ct into tmp */
+   if ((errno = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   cipher_descriptor[cbc->cipher].ecb_decrypt(ct, tmp, &cbc->key);
+
+   /* xor IV against the plaintext of the previous step */
+   for (x = 0; x < cbc->blocklen; x++) { 
+       /* copy CT in case ct == pt */
+       tmp2[x] = ct[x]; 
+
+       /* actually decrypt the byte */
+       pt[x] = tmp[x] ^ cbc->IV[x]; 
+   }
+
+   /* replace IV with this current ciphertext */ 
+   for (x = 0; x < cbc->blocklen; x++) {
+       cbc->IV[x] = tmp2[x];
+   }
+   #ifdef CLEAN_STACK
+      zeromem(tmp, sizeof(tmp));
+      zeromem(tmp2, sizeof(tmp2));
+   #endif
+   return CRYPT_OK;
+}
+
+#endif
+

+ 86 - 0
cfb.c

@@ -0,0 +1,86 @@
+#include "mycrypt.h"
+
+#ifdef CFB
+
+int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+              int keylen, int num_rounds, symmetric_CFB *cfb)
+{
+   int x, errno;
+
+   _ARGCHK(IV != NULL);
+   _ARGCHK(key != NULL);
+   _ARGCHK(cfb != NULL);
+
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* copy data */
+   cfb->cipher = cipher;
+   cfb->blocklen = cipher_descriptor[cipher].block_length;
+   for (x = 0; x < cfb->blocklen; x++)
+       cfb->IV[x] = IV[x];
+
+   /* init the cipher */
+   if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cfb->key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* encrypt the IV */
+   cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->IV, cfb->IV, &cfb->key);
+   cfb->padlen = 0;
+
+   return CRYPT_OK;
+}
+
+int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb)
+{
+   int errno;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(cfb != NULL);
+
+   if ((errno = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   while (len--) {
+       if (cfb->padlen == cfb->blocklen) {
+          cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key);
+          cfb->padlen = 0;
+       }
+       cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]);
+       ++pt; 
+       ++ct;
+       ++cfb->padlen;
+   }
+   return CRYPT_OK;
+}
+
+int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb)
+{
+   int errno;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(cfb != NULL);
+
+   if ((errno = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   while (len--) {
+       if (cfb->padlen == cfb->blocklen) {
+          cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key);
+          cfb->padlen = 0;
+       }
+       cfb->pad[cfb->padlen] = *ct;
+       *pt = *ct ^ cfb->IV[cfb->padlen];
+       ++pt; 
+       ++ct;
+       ++cfb->padlen;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+

+ 622 - 0
changes

@@ -0,0 +1,622 @@
+Nov 24th, 2002
+v0.75  -- Fixed a flaw in hash_filehandle, it should ARGCHK that the filehandle is not NULL
+       -- Fixed a bug where in hash_file if the call to hash_filehandle failed the open file would 
+          not be closed.
+       -- Added more strict rules to build process, starting to weed out "oh this works in GCC" style code
+          In the next release "-Wconversion" will be enabled which will deal with all implicit casts.
+
+Nov 22nd, 2002 [later in the day]
+v0.74  -- Wrote a small variant of SAFER+ which shaved 50KB off the size of the library on x86 platforms
+       -- Wrote a build option to remove the PK packet functions [keeps the encrypt_key/sign_hash functions]
+       -- Wrote a small variant of Rijndael (trimmed 13KB)
+       -- Trimmed the TIGER/192 hash function a bit
+       -- Overall the entire lib compiled is 295KB [down from 400KB before]
+       -- Fixed a few minor oversights in the MSVC makefile
+
+Nov 22nd, 2002
+v0.73  -- Fixed bug in RC4 code where it could only use 255 byte keys.
+       -- Fixed bug in yarrow code where it would allow cast5 or md2 to be used with it...
+       -- Removed the ecc compress/expand points from the global scope.  Reduces namespace polution
+       -- Fixed bug where if you used the SPRNG you couldn't pass NULL as your prng_state which you should be
+          able todo since the SPRNG has no state...
+       -- Corrected some oversights in the manual and the examples...
+       -- By default the GF(2^W) math library is excluded from the build.  The source is maintained because I wrote it
+          and like it :-).  This way the built library is a tad smaller
+       -- the MSVC makefile will now build for a SPACE optimized library rather than TIME optimized.
+
+Nov 21th, 2002
+v0.72  -- Fixed bug in the prime testing.  In the Miller-Rabin test I was raising the base to "N-1" not "r".
+          The math still worked out fine because in effect it was performing a Fermat test.  Tested the new code and it 
+          works properly
+       -- Fixed some of the code where it was still using the old error syntax
+       -- Sped up the RSA decrypt/sign routines
+       -- Optimized the ecc_shared_secret routine to not use so much stack
+       -- Fixed up the makefile to make releases where the version # is in the file name and directory it will unzip
+          to
+
+Nov 19th, 2002
+v0.71  -- HELP TOM.  I need tuition for the January semester.  Now I don't want to force donations [nor will I ever]
+          but I really need the help!  See my website http://tom.iahu.ca/help_tom.html for more details.  Please help
+          if you can! 
+       --------------------------------------------------------------------------------------------------------------
+       -- Officially the library is no longer supported in GCC 3.2 in windows [cygwin].
+          In windows you can either use GCC 2.95.3 or try your luck with 3.2  It seems that
+          "-fomit-frame-pointer" is broken in the windows build [but not the linux x86 build???]
+          If you simply must use 3.2 then I suggest you limit the optimizations to simply "-O2"
+       -- Started new error handling API.  Similar to the previous except there are more error codes than just
+          CRYPT_ERROR
+       -- Added my implementation of the MD2 hash function [despite the errors in the RFC I managed to get it right!]
+       -- Merged in more changes from Sky Schulz.  I have to make mention here that he has been a tremendous help in 
+          getting me motivated to make some much needed updates to the library!
+       -- Fixed one of the many mistakes in the manual as pointed out by Daniel Richards
+       -- Fixed a bug in the RC4 code [wasn't setting up the key correctly]
+       -- Added my implementation of the CAST5 [aka CAST-128] block cipher (conforms...)
+       -- Fixed numerous bugs in the PK code.  Essentially I was "freeing" keys when the import failed.  This is neither
+          required nor a good a idea [double free].  
+       -- Tom needs a job.
+       -- Fixed up the test harness as requested by Sky Schulz.  Also modifed the timing routines to run for X seconds
+          and count # of ops performed.  This is more suitable than say encrypting 10 million blocks on a slow processor
+          where it could take minutes!
+       -- Modified test programs hashsum/encrypt to use the new algorithms and error handling syntax
+       -- Removed the PKCS code since it was incomplete.  In the future I plan on writing a "add-on" library that
+          provides PKCS support... 
+       -- updated the config system so the #defines are in the makefiles instead of mycrypt_cfg.h  
+       -- Willing to work on an hourly basis for 15$ CDN per hour.
+       -- updated the test program to not test ciphers not included
+       -- updated the makefile to make "rsa_sys.c" a dependency of rsa.o [helps develop the code...]
+       -- fixed numerous failures to detect buffer overflows [minor] in the PK code.
+       -- fixed the safer [64-bit block version] test routines which didn't check the returns of the setup
+          function
+       -- check out my CV at http://tom.iahu.ca/cv.html
+       -- removed the GBA makefile and code from demos/test.c [not a particularly useful demo...]
+       -- merged in rudimentary [for testing] PS2 RNG from Sky Schulz
+       -- merged in PS2 timer code [only shell included due to NDA reasons...]
+       -- updated HMAC code to return errors where possible
+       -- Thanks go to Sky Schulz who bought me a RegCode for TextPad [the official editor of libtomcrypt]
+
+Nov 12th, 2002
+v0.70  -- Updated so you can swap out the default malloc/calloc/free routines at build time with others. (Sky Schulz)
+       -- Sky Schulz contributed some code towards autodetecting the PS2 in mycrypt_cfg.h
+       -- Added PS2 makefile contributed by Sky Schulz [see a pattern forming?]
+       -- Added ability to have no FILE I/O functions at all (see makefile), Sky Schulz....
+       -- Added support for substituting out the clock() function (Sky Schulz)
+       -- Fixed up makefile to include new headers in the HEADERS variable
+       -- Removed "coin.c" as its not really useful anyways
+       -- Removed many "debug" printfs that would show up on failures.  Basically I wanted to ensure the only output
+          would be from the developer themselves.
+       -- Added "rc4.c" a RC4 implementation with a PRNG interface.  Since RC4 isn't a block cipher it wouldn't work
+          too well as a block cipher.
+       -- Fixed ARGCHK macro usage when ARGTYPE=1 throughout the code
+       -- updated makefile to make subdirectory properly (Sku Schulz)
+       -- Started towards new API setup.  Instead of checking for "== CRYPT_ERROR" you should check "!= CRYPT_OK"
+          In future releases functions will return things other than CRYPT_ERROR on error to give more useful
+          thread safe error reporting.  The manual will be updated to reflect this.  For this release all
+          errors are returned as CRYPT_ERROR (except as noted) but in future releases this will change.         
+       -- Removed the zlib branch since its not really required anyways.  Makes the package smaller
+
+Nov 11th, 2002
+v0.69  -- Added ARGCHK (see mycrypt_argchk.h) "arguement checking" to all functions that accept pointers
+       -- Note I forgot to change the CRYPT version tag in v0.68... fixed now.
+
+Nov 8th, 2002
+v0.68  -- Fixed flaw in kr_import/kr_export that wasted 4 bytes.  Source but not binary compatible with v0.67
+       -- Fixed bug in kr_find_name that used memcmp to match strings.  Uses strncmp now.
+       -- kr_clear now sets the pointer to NULL to facilate debugging [e.g. using the keyring after clearing]
+       -- static functions in _write/_read in keyring.c now check the return of ctr_encrypt/ctr_decrypt.
+       -- Updated blowfish/rc2/rc5/rc6 keysize() function to not reject keys larger than the biggest key the
+          respective ciphers can use.  
+       -- Fixed a bug in hashsum demo that would report the hash for files that don't exist!
+
+Oct 16th, 2002
+v0.67  -- Moved the function prototypes into files mycrypt_*.h.  To "install" the lib just copy all the 
+          header files "*.h" from the base of this project into your global include path.
+       -- Made the OFB/CFB/CTR functions use "unsigned long" for the length instead of "int"
+       -- Added keyring support for the PK functions
+       -- ***API CHANGE*** changed the ecc_make_key and dh_make_key to act more like rsa_make_key.  Basically
+          move the first argument to the next to last.
+       -- Fixed bug in dh_test() that wouldn't test the primality of the order of the sub-group
+       -- replaced the primes in the DH code with new ones that are larger than the size they are 
+          associated with.  That is a 1024-bit DH key will have a 1025-bit prime as the modulus
+       -- cleaned up all the PK code, changed a bit of the API around [not source compatible with v0.66]
+       -- major editing of the manual, started Docer program
+       -- added 160 and 224 bit key settings for ECC.  This makes the DH and ECC binary wise incompatible with v0.66
+       -- Added an additional check for memory errors in is_prime() and cleaned up prime.c a bit
+       -- Removed ID_TAG from all files [meh, not a big fan...]
+       -- Removed unused variable from yarrow state and made AES/SHA256 the default cipher/hash combo
+       -- Fixed a bug in the Yarrow code that called prng_is_valid instead of cipher_is_valid from yarrow_start()
+       -- The ECB/CBC/OFB/CFB/CTR wrappers now check that the cipher is valid in the encrypt/decrypt calls
+          Returns int now instead of void.
+
+Sept 24th, 2002
+v0.66  -- Updated the /demos/test.c program to time the hashes correctly.  Also it uses the yarrow PRNG for all of the 
+          tests meaning its possible to run on RNG less platforms 
+       -- Updated the /demos/hashsum.c program to hash from the standard input
+       -- Updated the RSA code to make keys a bit quicker [update by Wayne Scott] by not making both primes at the same
+          time.
+       -- Dan Kaminsky suggested some cleanups for the code and the MPI config
+          Code ships in unix LF format by default now too... will still build in MSVC and all... but if you want
+          to read the stuff you'll have to convert it 
+       -- Changes to the manual to reflect new API [e.g. hash_memory/file have v0.65 prototypes]and some typos fixed
+
+Sept 20th, 2002
+v0.65  -- Wayne Scott ([email protected]) made a few of suggestions to improve the library.  Most 
+          importantly he pointed out the math lib is not really required.  He's also tested the lib on 18 
+          different platforms.  According to him with only a few troubles [lack of /dev/random, etc] the 
+          library worked as it was supposed to.  You can find the list at 
+          http://www.bitkeeper.com/Products.BitKeeper.Platforms.html
+       -- Updated the hash_file and hash_memory functions to keep track of the size of the output
+       -- Wayne Scott updated the demos/test.c file to use the SPRNG less and Yarrow more
+       -- Modified the mycrypt_cfg.h to autodetect x86-32 machines
+
+Sept 19th, 2002
+v0.64  -- wrote makefile for the GBA device [and hacked the demos/test.c file to support it conditionally]
+       -- Fixed error in PK (e.g. ECC, RSA, DH) import functions where I was clobbering the packet error messages
+       -- fixed more typos in the manual
+       -- removed all unused variables from the core library (ignore the ID_TAG stuff)
+       -- added "const char *crypt_build_settings" string which is a build time constant that gives a listing
+          of all the build time options.  Useful for debugging since you can send that to me and I will know what 
+          exactly you had set for the mycrypt_cfg.h file.
+       -- Added control over endianess.  Out of the box it defaults to endianess neutral but you can trivially 
+          configure the library for your platform.  Using this I boosted RC5 from 660Mbit/sec to 785Mbit/sec on my 
+          Athlon box.  See "mycrypt_cfg.h" for more information.
+
+Sept 11th, 2002
+v0.63  -- Made hashsum demo output like the original md5sum program 
+       -- Made additions to the examples in the manual (fixed them up a bunch)
+       -- Merged in the base64 code from Wayne Scott ([email protected])
+
+Aug 29th, 2002
+v0.62  -- Added the CLEAN_STACK functionality to several of the hashes I forgot to update.
+
+Aug 9th, 2002
+v0.61  -- Fixed a bug in the DES code [oops I read something wrong].
+
+Aug 8th, 2002
+v0.60  -- Merged in DES code [and wrote 3DES-EDE code based on it] from Dobes V.
+
+Aug 7th, 2002
+v0.59  -- Fixed a "unsigned long long" bug that caused v0.58 not to build in MSVC.
+       -- Cleaned up a little in the makefile
+       -- added code that times the hash functions too in the test program
+
+Aug 3rd, 2002
+v0.58  -- Added more stack cleaning conditionals throughout the code.  
+       -- corrected some CLEAR_STACK conditionals... should have been CLEAN_STACK
+       -- Simplified the RSA, DH and ECC encrypt() routines where they use CTR to encode the message
+          now they only make one call to ctr_encrypt()/ctr_decrypt().
+
+Aug 2nd, 2002
+v0.57  -- Fixed a few errors messages in the SAFER code to actually report the correct cipher name.
+       -- rsa_encrypt() uses the "keysize()" method of the cipher being used to more accurately pick a
+          key size.  By default rsa_encrypt() will choose to use a 256-bit key but the cipher can turn that 
+          down if required.
+       -- The rsa_exptmod() function will now more reliably detect invalid inputs (e.g. greater than the modulus).
+       -- The padding method for RSA is more clearly documented.  Namely if you want to encrypt/sign something of length
+          N then your modulus must be of length 1+3N.  So to sign a message with say SHA-384 [48 bytes] you need a 
+          145 byte (1160 bits) modulus.  This is all in the manual now.
+       -- Added build option CLEAN_STACK which will allow you to choose whether you want to clean the stack or not after every
+          cipher/hash call
+       -- Sped up the hash "process()" functions by not copying one byte at a time.
+       ++ (added just after I uploaded...)
+          MD4 process() now handles input buffers > 64 bytes
+
+Aug 1st, 2002
+v0.56  -- Cleaned up the comments in the Blowfish code.
+       -- Oh yeah, in v0.55 I made all of the descriptor elements constant.  I just forgot to mention it.
+       -- fixed a couple of places where descriptor indexes were tested wrong.  Not a huge bug but now its harder
+          to mess up.
+       -- Added the SAFER [64-bit block] ciphers K64, SK64, K128 and SK128 to the library.
+       -- Added the RC2 block cipher to the library.
+       -- Changed the SAFER define for the SAFER+ cipher to SAFERP so that the new SAFER [64-bit] ciphers
+          can use them with less confusion.
+
+July 29th, 2002
+v0.55  -- My god stupid Blowfish has yet again been fixed.  I swear I hate that cipher.  Next bug in it and boom its out of the
+          library.  Use AES or something else cuz I really hate Blowfish at this stage....
+       -- Partial PKCS support [hint DONT USE IT YET CUZ ITS UNTESTED!]
+
+July 19th, 2002
+v0.54  -- Blowfish now conforms to known test vectors.  Silly bad coding tom!
+       -- RC5/RC6/Serpent all have more test vectors now [and they seemed to have been working before]
+
+July 18th, 2002
+v0.53  -- Added more test vectors to the blowfish code just for kicks [and they are const now too :-)]
+       -- added prng/hash/cipher is_valid functions and used them in all of the PK code so you can't enter the code
+          with an invalid index ever now.
+       -- Simplified the Yarrow code once again :-)
+
+July 12th, 2002
+v0.52  -- Fixed a bug in MD4 where the hash descriptor ID was the same as SHA-512.  Now MD4 will work with
+          all the routines...
+       -- Fixed the comments in SHA-512 to be a bit more meaningful
+       -- In md4 I made the PADDING array const [again to store it in ROM]
+       -- in hash_file I switched the constant "512" to "sizeof(buf)" to be a bit safer
+       -- in SHA-1's test routine I fixed the string literal to say SHA-1 not sha1
+       -- Fixed a logical error in the CTR code which would make it skip the first IV value.  This means
+          the CTR code from v0.52 will be incompatible [binary wise] with previous releases but it makes more
+          sense this way.
+       -- Added {} braces for as many if/for/blocks of code I could find.  My rule is that every for/if/while/do block
+          must have {} braces around it.
+       -- made the rounds table in saferp_setup const [again for the ROM think about the ROM!]
+       -- fixed RC5 since it no longer requires rc5 to be registered in the lib.  It used to since the descriptors used to 
+          be part of the table...
+       -- the packet.c code now makes crypt_error literal string errors when an error occurs
+       -- cleaned up the SAFER+ key schedule to be a bit easier to read.
+       -- fixed a huge bug in Twofish with the TWOFISH_SMALL define.  Because I clean the stack now I had
+          changed the "g_func()" to be called indirectly.  I forgot to actually return the return of the Twofish
+          g_func() function which caused it not to work... [does now :-)]
+
+July 11th, 2002
+v0.51  -- Fixed a bug in SHA512/384 code for multi-block messages.
+       -- Added more test vectors to the SHA384/512 and TIGER hash functions
+       -- cleaned up the hash done routines to make more sense
+ 
+July 10th, 2002
+v0.50  -- Fixed yarrow.c so that the cipher/hash used would be registered.  Also fixed
+          a bug where the SAFER+ name was "safer" but should have been "safer+".
+       -- Added an element to the hash descriptors that gives the size of a block [sent into the compressor]
+       -- Cleaned up the support for HMAC's
+       -- Cleaned up the test vector routines to make the test vector data const.  This means on some platforms it will be
+          placed in ROM not RAM now.
+       -- Added MD4 code submited by Dobes Vandermeer ([email protected])
+       -- Added "burn_stack" function [idea taken from another source of crypto code].  The idea is if a function has
+          alot of variables it will clean up better.  Functions like the ecb serpent and twofish code will now have their
+          stacks cleaned and the rest of the code is getting much more straightforward.
+       -- Added a hashing demo by Daniel Richards ([email protected])
+       -- I (Tom) modified some of the test vector routines to use more vectors ala Dobes style.
+          For example, the MD5/SHA1 code now uses all of the test vectors from the RFC/FIPS spec.
+       -- Fixed the register/unregister functions to properly report errors in crypt_error
+       -- Correctly updated yarrow code to remove a few unused variables.
+       -- Updated manual to fix a few erroneous examples.
+       -- Added section on Hash based Message Authentication Codes (HMAC) to the manual
+
+June 19th, 2002
+v0.46  -- Added in HMAC code from Dobes Vandermeer ([email protected])
+
+June 8th, 2002
+v0.45  -- Fixed bug in rc5.c where if you called rc5_setup() before registering RC5 it would cause
+          undefined behaviour.
+       -- Fixed mycrypt_cfg.h to eliminate the 224 bit ECC key.
+       -- made the "default" makefile target have depends on mycrypt.h and mycrypt_cfg.h
+
+Apr 4th, 2002
+v0.44  -- Fixed bug in ecc.c::new_point() where if the initial malloc fails it would not catch it.
+
+Mar 22nd, 2002
+v0.43  -- Changed the ZLIB code over to the 1.1.4 code base to avoid the "double free" bug.  
+       -- Updated the GCC makefile not to use -O3 or -funroll-loops
+       -- Version tag in mycrypt.h has been updated :-)
+
+Mar 10th, 2002
+v0.42  -- The RNG code can now use /dev/urandom before trying /dev/random (J. Klapste)
+
+Mar 3rd, 2002
+v0.41  -- Added support to link and use ciphers at compile time.  This can greatly reduce the code size!
+       -- Added a demo to show off how small an application can get... 46kb!
+       -- Disastry pointed out that Blowfish is supposed to be high endian.
+       -- Made registry code for the PRNGs as well [now the smallest useable link is 43kb]
+
+Feb 11th, 2002
+v0.40  -- RSA signatures use [and check for] fixed padding scheme.
+       -- I'm developing in Linux now :-)
+       -- No more warnings from GCC 2.96
+
+Feb 5th, 2002
+v0.39  -- Updated the XTEA code to work in accordance with the XTEA design
+
+January 24th, 2002
+v0.38  -- CFB and OFB modes can now handle blocks of variable size like the CTR code
+       -- Wrote a wrapper around the memory compress functions in Zlib that act like the functions
+          in the rest of my crypto lib
+
+January 23rd, 2002
+v0.37  -- Added support code so that if a hash size and key size for a cipher don't match up they will
+          use the next lower key supported.  (mainly for the PK code).  So you can now use SHA-1 with
+          Twofish, etc...
+       -- Added more options for Twofish.  You can now tell it to use precomputed sboxes and MDS multiplications
+          This will speed up the TWOFISH_SMALL implementation by increasing the code size by 1024 bytes.
+       -- Fixed a bug in prime.c that would not use the correct table if you undefined SMALL_PRIME_TAB
+       -- Fixed all of the PK packet code to use the same header format [see packet.c].  This makes the PK code
+          binary wise incompatible with previous releases while the API has not changed at all.
+
+January 22nd, 2002
+v0.36  -- Corrections to the manual
+       -- Made a modification to Twofish which lets you build a "small ram" variant.  It requires
+          about 190 bytes of ram for the key storage compared to the 4,200 bytes the normal 
+          variant requires.
+       -- Reduced the stack space used in all of the PK routines.
+
+January 19th, 2002
+v0.35  -- If you removed the first hash or cipher from the library it wouldn't return an error if 
+          you used an ID=0 [i.e blowfish or sha256] in any routine.  Now it checks for that and will
+          return an error like it should
+       -- Merged in new routines from Clay Culver.  These routines are for the PK code so you can easily 
+          encode a symmetric key for multiple recipients.
+       -- Made the ecc and DH make_key() routines make secret keys of the same size as the keysize listed.
+          Originally I wanted to ensure that the keys were smaller than the order of the field used
+          However, the bias is so insignifcant using full sizes.  For example, with a ECC-192 key the order
+          is about 2^191.99, so instead I rounded down and used a 184-bit secret key.  Now I simply use a full 192-bit
+          key the code will work just the same except that some 192-bit keys will be duplicates which is not a big
+          deal since 1/2^192 is a very small bias!
+       -- Made the configuration a bit simpler and more exacting.  You can for example now select which DH or ECC
+          key settings you wish to support without including the data for all other key settings.  I put the #defines
+          in a new file called "mycrypt_cfg.h"
+       -- Configured "mpi-config.h" so its a bit more conservative with the memory required and code space used
+       -- Jason Klapste submitted bug fixes to the yarrow, hash and various other issues.  The yarrow code will now
+          use what ever remaining hash/cipher combo is left [after you #undef them] at build time.   He also suggested
+          a fix to remove unused structures from the symmetric_key and hash_state unions.
+       -- Made the CTR code handle variable length blocks better. It will buffer the encryption pad so you can
+          encrypt messages any size block at a time.
+       -- Simplified the yarrow code to take advantage of the new CTR code.
+       -- Added a 4096-bit DH key setting.  That took me about 36 hours to find!
+       -- Changed the base64 routines to use a real base64 encoding scheme.
+       -- Added in DH and ECC "encrypt_key()" functions.  They are still rather "beta"ish.
+       -- Added **Twofish** to the list of ciphers!
+
+January 18th, 2002
+v0.34  -- Added "sha512" to the list of hashes.  Produces a 512-bit message digest.  Note that with the current
+          padding with the rsa_sign() function you cannot use sha512 with a key less than 1536 bits for signatures.
+       -- Cleaned up the other hash functions to use the LOAD and STORE macros...
+
+January 17th, 2002
+v0.33  -- Made the lower limit on keysizes for RSA 1024 bits again because I realized that 768 bit keys wouldn't
+          work with the padding scheme and large symmetric keys.
+       -- Added information concerning the Zlib license to the manual
+       -- Added a 3072-bit key setting for the DH code.
+       -- Made the "find_xyz()" routines take "const char *" as per Clay Culver's suggestion.
+       -- Fixed an embarassing typo in the manual concerning the hashes.  Thank's Clay for finding it!
+       -- Fixed rand_prime() so that it makes primes bigger than the setting you give.  For example,
+          if you want a 1024-bit prime it would make a 1023-bit one.  Now it ensures that the prime
+          it makes is always greater than 2^(8n) (n == bytes in prime).  This doesn't have a huge
+          impact on security but I corrected it just the same.
+       -- Fixed the CTR routine to work on platforms where char != 8-bits 
+       -- Fixed sha1/sha256/md5/blowfish to not assume "unsigned long == 32-bits", Basically any operation with carries
+          I "AND" with 0xFFFFFFFF.  That forces only the lower 32-bits to have information in it.  On x86 platforms
+          most compilers optimize out the AND operation since its a nop.
+
+January 16th, 2002
+v0.32  -- Made Rijndael's setup function fully static so it is thread safe
+       -- Svante Seleborg suggested a cosmetic style fixup for aes.c, 
+          basically to remove some of the #defines to clean it up
+       -- Made the PK routines not export the ASCII version of the names of ciphers/hashes which makes
+          the PK message formats *incompatible* with previous releases.
+       -- Merge in Zlib :-)
+ 
+  
+January 15th, 2002
+v0.31  -- The RSA routines can now use CRT to speed up decryption/signatures.  The routines are backwards 
+          compatible with previous releases.
+       -- Fixed another bug that Svante Seleborg found.  Basically you could buffer-overrun the 
+          rsa_exptmod() function itself if you're not careful.  That's fixed now.  Fixed another bug in
+          rsa_exptmod() where if it knows the buffer you passed is too small it wouldn't free all used 
+          memory.       
+       -- improved the readability of the PK import/export functions
+       -- Added a fix to RSA.C by Clay Culver
+       -- Changed the CONST64 macro for MSVC to use the "unsigned __int64" type, e.g. "ui64" instead of "i64".
+
+January 14th, 2002
+v0.30  -- Major change to the Yarrow PRNG code, fixed a bug that Eugene Starokoltsev found.
+          Basically if you added entropy to the pool in small increments it could in fact
+          cancel out.  Now I hash the pool with the new data which is way smarter.
+
+January 12th, 2002
+v0.29  -- Added MPI code written by Svante Seleborg to the library.  This will make the PK code much
+          easier to follow and debug.  Actually I've already fixed a memory leak in dh_shared_secret().
+       -- Memory leaks found and correct in all three PK routines.  The leaks would occur when a bignum
+          operation fails so it wouldn't normally turn up in the course of a program
+       -- Fixed bugs in dh_key_size and ecc_key_size which would return garbage for invalid key idx'es
+
+January 11th, 2002
+v0.28  -- Cleaned up some code so that it doesn't assume "char == 8bits".  Mainly SAFER+ has been 
+          changed.
+       -- ***HUGE*** changes in the PK code.  I check all return values in the bignum code so if there
+          are errors [insufficient memory, etc..] it will be reported.  This makes the code fairly more
+          robust and likely to catch any errors.
+       -- Updated the is_prime() function to use a new prototype [it can return errors now] and it also
+          does trial divisions against more primes before the Rabin Miller steps
+       -- Added OFB, CFB and ECB generic wrappers for the symmetric ciphers to round out the implementations.
+       -- Added Xtea to the list of ciphers, to the best of my ability I have verified this implementation.
+          I should note that there is not alot of concrete information about the cipher.  "Ansi C" versions
+          I found did not address endianess and were not even portable!.  This code is portable and to the
+          best of my knowledge implements the Xtea algorithm as per the [short] X-Tea paper.
+       -- Reformated the manual to include the **FULL** source code optimized to be pritable.
+
+January 9th, 2002
+v0.27  -- Changed the char constants to numerical values.  It is backwards compatible and should work on
+          platforms where 'd' != 100 [for example].
+       -- Made a change to rand_prime() which takes the input length as a signed type so you can pass
+          a negative len to get a "3 mod 4" style prime... oops
+       -- changed the MSVC makefile to build with a warning level of three, no warnings!
+
+January 8th, 2002
+v0.26  -- updated SHA-256 to use ROR() for a rotate so 64-bit machines won't corrupt
+          the output
+       -- Changed #include <> to #include "" for local .h files as per Richard Heathfields' suggestions.
+       -- Fixed bug in MPI [well bug in MSVC] that compiled code incorrectly in mp_set_int()
+          I added a work around that catches the error and continues normally.
+
+January 8th, 2002
+v0.25  -- Added a stupid define so MSVC 6.00 can build the library.
+       -- Big thanks to sci.crypt and "Ajay K. Agrawal" for helping me port this to MSVC
+
+January 7th, 2002
+v0.24  -- Sped up Blowfish by unrolling and removing the swaps.
+       -- Made the code comply with more traditional ANSI C standards
+          Should compile with MSVC with less errors
+       -- moved the demos and documentation into their own directories
+          so you can easily build the library with other tool chains
+          by compiling the files in the root
+       -- converted functions with length of outputs to use 
+          "unsigned long" so 16-bit platforms will like this library more.
+
+January 5th, 2002
+v0.23  -- Fixed a small error in the MPI config it should build fine anywhere.
+
+January 4th, 2002
+v0.22  -- faster gf_mul() code
+       -- gf_shl() and gf_shr() are safe on 64-bit platforms now
+       -- Fixed an error in the hashes that Brian Gladman found.  
+          Basically if the message has exactly 56 bytes left to be 
+          compressed I handled them incorrectly.
+
+January 4th, 2002
+v0.21  -- sped up the ECC code by removing redundant divisions in the 
+          point add and double routines.  I also extract the bits more
+          efficiently in "ecc_mulmod()" now.
+       -- sped up [and documented] the rand_prime() function.  Now it just
+          makes a random integer and increments by two until a prime is found
+          This is faster since it doesn't require alot of calls to the PRNG and
+          it doesn't require loading huge integers over and over.  rand_prime()
+          can also make primes congruent to 3 mod 4 [i.e for a blum integer]
+       -- added a gf_sqrt() function that finds square roots in a GF(2^w) field
+       -- fixed a bug in gf_div() that would return the wrong results if the divisor had a greator
+          divisor than the dividend.
+
+January 4th, 2002
+v0.20  -- Added the fixed MPI back in so RSA and DH are much faster again
+
+v0.19  -- Updated the manual to reflect the fact that Brian Gladman wrote the AES and Serpent code.
+       -- DH, ECC and RSA signature/decryption functions check if the key is private
+       -- new DH signature/verification code works just like the RSA/ECC versions
+
+January 3rd, 2002
+v0.18  -- Added way more comments to each .C file 
+       -- fixed a bug in cbc_decrypt(pt, ct, key) where pt == ct [i.e same buffer]
+       -- fixed RC5 so it reads the default rounds out of the cipher_descriptor table
+       -- cleaned up ecc_export()
+       -- Cleaned up dh_import() and ecc_import() which also perform more 
+          error checking now
+       -- Fixed a serious flaw in rsa_import() with private keys.
+
+January 2nd, 2002
+v0.17  -- Fixed a bug in the random prime generator that fixes the wrong bits to one
+       -- ECC and DH code verify that the moduli and orders are in fact prime.  That 
+          slows down the test routines alot but what are you gonna do? 
+       -- Fixed a huge bug in the mp_exptmod() function which incorrectly calculates g^x mod p for some
+          values of p.  I replaced it with a slow function.  Once the author of MPI fixes his faster routine
+          I will switch back.
+  
+January 1st, 2002 [whoa new year!]
+v0.16  -- Improved GF division code that is faster.
+       -- documented the GF code
+
+December 31st, 2001
+v0.15  -- A 1792-bit and 2048-bit DH setting was added.  Took me all night to 
+          find a 1792 and 2048-bit strong prime but what the heck
+       -- Library now has polynomial-basis GF(2^w) routines I wrote myself.  Can be used to perform
+          ECC over GF(2^w) later on....
+       -- Fixed a bug with the defines that allows it to build in windows
+       
+December 30th, 2001
+v0.14  -- Fixed the xxx_encrypt() packet routines to make an IV of appropriate size 
+          for the cipher used.  It was defaulting to making a 256-bit IV...
+       -- base64_encode() now appends a NULL byte, um "duh" stupid mistake now fixed...
+       -- spell checked the manual again... :-)
+
+December 30th, 2001
+v0.13  -- Switching back to older copy of MPI since it works! arrg..
+       -- Added sign/verify functions for ECC
+       -- all signature verification routines default to invalid signatures.
+       -- Changed all calls to memset to zeromem.  Fixed up some buffer problems 
+          in other routines.  All calls to zeromem let the compiler determine the size
+          of the data to wipe.
+
+December 29th, 2001
+v0.12  -- Imported a new version of MPI [the bignum library] that should
+          be a bit more stable [if you want to write your own bignum
+          routines with the library that is...]
+       -- Manual has way more info
+       -- hash_file() clears stack now [like it should]
+       -- The artificial cap on the hash input size of 2^32 bits has been
+          removed.  Basically I was too lazy todo 64-bit math before
+          [don't ask why... I can't remember].  Anyways the hashes
+          support the size of 2^64 bits [if you ever use that many bits in a message
+          that's just wierd...]
+       -- The hashes now wipe the "hash_state" after the digest is computed.  This helps
+          prevent the internal state of the hash being leaked accidently [i.e stack problems]
+
+December 29th, 2001
+v0.11  -- Made #define's so you can trim the library down by removing
+          ciphers, hashs, modes of operation, prngs, and even PK algorithms
+          For example, the library with rijndael+ctr+sha1+ECC is 91KB compared
+          to the 246kb the full library takes.
+       -- Added ECC packet routines for encrypt/decrypt/sign/verify much akin to
+          the RSA packet routines.
+       -- ECC now compresses the public key, a ECC-192 public key takes 33 bytes 
+          for example....
+
+December 28th, 2001
+v0.10  -- going to restart the manual from scratch to make it more 
+          clear and professional
+       -- Added ECC over Z/pZ.  Basically provides as much as DH
+          except its faster since the numbers are smaller.  For example,
+          A comparable 256-bit ECC key provides as much security as expected
+          from a DH key over 1024-bits.
+       -- Cleaned up the DH code to not export the symbol "sets[]"
+       -- Fixed a bug in the DH code that would not make the correct size 
+          random string if you made the key short.  For instance if you wanted 
+          a 512-bit DH key it would make a 768-bit one but only make up 512-bits 
+          for the exponent... now it makes the full 768 bits [or whatever the case 
+          is]
+       -- Fixed another ***SERIOUS*** bug in the DH code that would default to 768-bit
+          keys by mistake.
+
+December 25th, 2001
+v0.09  -- Includes a demo program called file_crypt which shows off
+          how to use the library to make a command line tool which
+          allows the user to encode/decode a file with any
+          hash (on the passphrase) and cipher in CTR mode.
+       -- Switched everything to use typedef's now to clear up the code.
+       -- Added AES (128/192 and 256 bit key modes)
+
+December 24th, 2001
+v0.08  -- fixed a typo in the manual. MPI stores its bignums in
+          BIG endian not little.
+       -- Started adding a RNG to the library.  Right now it tries
+          to open /dev/random and if that fails it uses either the 
+          MS CSP or the clock drift RNG.  It also allows callbacks 
+          since the drift RNG is slow (about 3.5 bytes/sec)
+       -- the RNG can also automatically setup a PRNG as well now
+
+v0.07  -- Added basic DH routines sufficient to 
+          negotiate shared secrets 
+          [see the manual for a complete example!]
+       -- Fixed rsa_import to detect when the input
+          could be corrupt.  
+       -- added more to the manual.
+
+December 22nd, 2001
+v0.06  -- Fixed some formatting errors in 
+          the hash functions [just source code cleaning]
+       -- Fixed a typo in the error message for sha256 :-)
+       -- Fixed an error in base64_encode() that 
+          would fail to catch all buffer overruns
+       -- Test program times the RSA and symmetric cipher 
+          routines for kicks...
+       -- Added the "const" modifier to alot of routines to 
+          clear up the purpose of each function.
+       -- Changed the name of the library to "TomCrypt" 
+          following a suggestion from a sci.crypt reader....
+
+v0.05  -- Fixed the ROL/ROR macro to be safe on platforms 
+          where unsigned long is not 32-bits
+       -- I have added a bit more to the documentation 
+          manual "crypt.pdf" provided.
+       -- I have added a makefile for LCC-Win32.  It should be 
+          easy to port to other LCC platforms by changing a few lines.
+       -- Ran a spell checker over the manual.
+       -- Changed the header and library from "crypt" to "mycrypt" to not
+          clash with the *nix package "crypt".
+
+v0.04  -- Fixed a bug in the RC5,RC6,Blowfish key schedules
+          where if the key was not a multiple of 4 bytes it would
+          not get loaded correctly.
+
+December 21st, 2001
+
+v0.03  -- Added Serpent to the list of ciphers.
+
+v0.02  -- Changed RC5 to only allow 12 to 24 rounds
+       -- Added more to the manual.
+
+v0.01  -- We will call this the first version.

+ 507 - 0
crypt.c

@@ -0,0 +1,507 @@
+#include "mycrypt.h"
+#include <signal.h>
+
+struct _cipher_descriptor cipher_descriptor[32] = {
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } };
+
+struct _hash_descriptor hash_descriptor[32] = {
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL },
+{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL } };
+
+struct _prng_descriptor prng_descriptor[32] = {
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL },
+{ NULL, NULL, NULL, NULL, NULL } };
+
+int find_cipher(const char *name)
+{
+   int x;
+   _ARGCHK(name != NULL);
+   for (x = 0; x < 32; x++) {
+       if (cipher_descriptor[x].name != NULL && !strcmp(cipher_descriptor[x].name, name)) {
+          return x;
+       }
+   }
+   return -1;
+}
+
+int find_hash(const char *name)
+{
+   int x;
+   _ARGCHK(name != NULL);
+   for (x = 0; x < 32; x++) {
+       if (hash_descriptor[x].name != NULL && !strcmp(hash_descriptor[x].name, name)) {
+          return x;
+       }
+   }
+   return -1;
+}
+
+int find_prng(const char *name)
+{
+   int x;
+   _ARGCHK(name != NULL);
+   for (x = 0; x < 32; x++) {
+       if ((prng_descriptor[x].name != NULL) && !strcmp(prng_descriptor[x].name, name)) {
+          return x;
+       }
+   }
+   return -1;
+}
+
+int find_cipher_id(unsigned char ID)
+{
+   int x;
+   for (x = 0; x < 32; x++) {
+       if (cipher_descriptor[x].ID == ID) {
+          return (cipher_descriptor[x].name == NULL) ? -1 : x;
+       }
+   }
+   return -1;
+}
+
+int find_hash_id(unsigned char ID)
+{
+   int x;
+   for (x = 0; x < 32; x++) {
+       if (hash_descriptor[x].ID == ID) {
+          return (hash_descriptor[x].name == NULL) ? -1 : x;
+       }
+   }
+   return -1;
+}
+
+/* idea from Wayne Scott */
+int find_cipher_any(const char *name, int blocklen, int keylen)
+{
+   int x;
+
+   _ARGCHK(name != NULL);
+
+   x = find_cipher(name);
+   if (x != -1) return x;
+
+   for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+       if (blocklen <= (int)cipher_descriptor[x].block_length && keylen <= (int)cipher_descriptor[x].max_key_length) {
+          return x;
+       }
+   }
+   return -1;
+}
+
+int register_cipher(const struct _cipher_descriptor *cipher)
+{
+   int x;
+
+   _ARGCHK(cipher != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) {
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < 32; x++) {
+       if (cipher_descriptor[x].name == NULL) {
+          memcpy(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor));
+          return x;
+       }
+   }
+
+   /* no spot */
+   return -1;
+}
+
+int unregister_cipher(const struct _cipher_descriptor *cipher)
+{
+   int x;
+
+   _ARGCHK(cipher != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) {
+          cipher_descriptor[x].name = NULL;
+          return CRYPT_OK;
+       }
+   }
+   return CRYPT_ERROR;
+}
+
+int register_hash(const struct _hash_descriptor *hash)
+{
+   int x;
+
+   _ARGCHK(hash != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor))) {
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < 32; x++) {
+       if (hash_descriptor[x].name == NULL) {
+          memcpy(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor));
+          return x;
+       }
+   }
+
+   /* no spot */
+   return -1;
+}
+
+int unregister_hash(const struct _hash_descriptor *hash)
+{
+   int x;
+
+   _ARGCHK(hash != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor))) {
+          hash_descriptor[x].name = NULL;
+          return CRYPT_OK;
+       }
+   }
+   return CRYPT_ERROR;
+}
+
+int register_prng(const struct _prng_descriptor *prng)
+{
+   int x;
+
+   _ARGCHK(prng != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor))) {
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < 32; x++) {
+       if (prng_descriptor[x].name == NULL) {
+          memcpy(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor));
+          return x;
+       }
+   }
+
+   /* no spot */
+   return -1;
+}
+
+int unregister_prng(const struct _prng_descriptor *prng)
+{
+   int x;
+
+   _ARGCHK(prng != NULL);
+
+   /* is it already registered? */
+   for (x = 0; x < 32; x++) {
+       if (!memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor))) {
+          prng_descriptor[x].name = NULL;
+          return CRYPT_OK;
+       }
+   }
+   return CRYPT_ERROR;
+}
+
+int cipher_is_valid(int idx)
+{
+   if (idx < 0 || idx > 32 || cipher_descriptor[idx].name == NULL) {
+      return CRYPT_INVALID_CIPHER;
+   }
+   return CRYPT_OK;
+}
+
+int hash_is_valid(int idx)
+{
+   if (idx < 0 || idx > 32 || hash_descriptor[idx].name == NULL) {
+      return CRYPT_INVALID_HASH;
+   }
+   return CRYPT_OK;
+}
+
+int prng_is_valid(int idx)
+{
+   if (idx < 0 || idx > 32 || prng_descriptor[idx].name == NULL) {
+      return CRYPT_INVALID_PRNG;
+   }
+   return CRYPT_OK;
+}
+
+const char *crypt_build_settings = 
+   "LibTomCrypt " SCRYPT "\n\n"
+   "Endianess: "
+#if defined(ENDIAN_NEUTRAL)
+   "neutral\n"
+#elif defined(ENDIAN_LITTLE)
+   "little"
+   #if defined(ENDIAN_32BITWORD)
+   " (32-bit words)\n"
+   #else
+   " (64-bit words)\n"
+   #endif
+#elif defined(ENDIAN_BIG)
+   "big"
+   #if defined(ENDIAN_32BITWORD)
+   " (32-bit words)\n"
+   #else
+   " (64-bit words)\n"
+   #endif
+#endif
+   "Clean stack: "
+#if defined(CLEAN_STACK)
+   "enabled\n"
+#else
+   "disabled\n"
+#endif
+   "Ciphers built-in:\n"
+#if defined(BLOWFISH)
+   "   Blowfish\n"
+#endif
+#if defined(RC2)
+   "   RC2\n"
+#endif
+#if defined(RC5)
+   "   RC5\n"
+#endif
+#if defined(RC6)
+   "   RC6\n"
+#endif
+#if defined(SERPENT)
+   "   Serpent\n"
+#endif
+#if defined(SAFERP)
+   "   Safer+\n"
+#endif
+#if defined(SAFER)
+   "   Safer\n"
+#endif
+#if defined(RIJNDAEL)
+   "   Rijndael\n"
+#endif
+#if defined(XTEA)
+   "   XTEA\n"
+#endif
+#if defined(TWOFISH)
+   "   Twofish "
+   #if defined(TWOFISH_SMALL) && defined(TWOFISH_TABLES)
+       "(small, tables)\n"
+   #elif defined(TWOFISH_SMALL) 
+       "(small)\n"
+   #elif defined(TWOFISH_TABLES)
+       "(tables)\n"
+   #else
+       "\n"
+   #endif
+#endif
+#if defined(DES)
+   "   DES\n"
+#endif
+#if defined(CAST5)
+   "   CAST5\n"
+#endif
+
+    "\nHashes built-in:\n"
+#if defined(SHA512)
+   "   SHA-512\n"
+#endif
+#if defined(SHA384)
+   "   SHA-384\n"
+#endif
+#if defined(SHA256)
+   "   SHA-256\n"
+#endif
+#if defined(TIGER)
+   "   TIGER\n"
+#endif
+#if defined(SHA1)
+   "   SHA1\n"
+#endif
+#if defined(MD5)
+   "   MD5\n"
+#endif
+#if defined(MD4)
+   "   MD4\n"
+#endif
+#if defined(MD2)
+   "   MD2\n"
+#endif
+
+    "\nBlock Chaining Modes:\n"
+#if defined(CFB)
+    "   CFB\n"
+#endif
+#if defined(OFB)
+    "   OFB\n"
+#endif
+#if defined(ECB)
+    "   ECB\n"
+#endif
+#if defined(CBC)
+    "   CBC\n"
+#endif
+#if defined(CTR)
+    "   CTR\n"
+#endif
+
+    "\nPRNG:\n"
+#if defined(YARROW)
+    "   Yarrow\n"
+#endif
+#if defined(SPRNG)
+    "   SPRNG\n"
+#endif
+#if defined(RC4)
+    "   RC4\n"
+#endif
+
+    "\nPK Algs:\n"
+#if defined(MRSA)
+    "   RSA\n"
+#endif
+#if defined(MDH)
+    "   DH\n"
+#endif
+#if defined(MECC)
+    "   ECC\n"
+#endif
+
+    "\nCompiler:\n"
+#if defined(WIN32)
+    "   WIN32 platform detected.\n"
+#endif
+#if defined(__CYGWIN__)
+    "   CYGWIN Detected.\n"
+#endif
+#if defined(__DJGPP__)
+    "   DJGPP Detected.\n"
+#endif
+#if defined(_MSC_VER)
+    "   MSVC compiler detected.\n"
+#endif
+#if defined(__GNUC__)
+    "   GCC compiler detected.\n"
+#endif
+
+    "\nVarious others: "
+#if defined(GF)
+    " GF "
+#endif
+#if defined(BASE64)
+    " BASE64 "
+#endif
+#if defined(MPI)
+    " MPI "
+#endif
+#if defined(HMAC)
+    " HMAC "
+#endif
+#if defined(TRY_UNRANDOM_FIRST)
+    " TRY_UNRANDOM_FIRST "
+#endif
+#if defined(SMALL_PRIME_TAB)
+    " SMALL_PRIME_TAB "
+#endif
+    "\n"
+
+    "\n\n\n"
+    ;
+

BIN
crypt.pdf


+ 2412 - 0
crypt.tex

@@ -0,0 +1,2412 @@
+\documentclass{book}
+\usepackage{makeidx}
+\usepackage{amssymb}
+\def\union{\cup}
+\def\intersect{\cap}
+\def\getsrandom{\stackrel{\rm R}{\gets}}
+\def\cross{\times}
+\def\cat{\hspace{0.5em} \| \hspace{0.5em}}
+\def\catn{$\|$}
+\def\divides{\hspace{0.3em} | \hspace{0.3em}}
+\def\nequiv{\not\equiv}
+\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}}
+\def\lcm{{\rm lcm}}
+\def\gcd{{\rm gcd}}
+\def\log{{\rm log}}
+\def\ord{{\rm ord}}
+\def\abs{{\mathit abs}}
+\def\rep{{\mathit rep}}
+\def\mod{{\mathit\ mod\ }}
+\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})}
+\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor}
+\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil}
+\def\Or{{\rm\ or\ }}
+\def\And{{\rm\ and\ }}
+\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}}
+\def\implies{\Rightarrow}
+\def\undefined{{\rm ``undefined"}}
+\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}}
+\let\oldphi\phi
+\def\phi{\varphi}
+\def\Pr{{\rm Pr}}
+\newcommand{\str}[1]{{\mathbf{#1}}}
+\def\F{{\mathbb F}}
+\def\N{{\mathbb N}}
+\def\Z{{\mathbb Z}}
+\def\R{{\mathbb R}}
+\def\C{{\mathbb C}}
+\def\Q{{\mathbb Q}}
+
+\newcommand{\url}[1]{\mbox{$<${#1}$>$}}
+\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}}
+\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}}
+
+\def\gap{\vspace{0.5ex}}
+\makeindex
+\begin{document}
+\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.75}
+\author{Tom St Denis \\
+Algonquin College \\
+\\
[email protected] \\
+http://libtomcrypt.iahu.ca \\ \\
+Phone: 1-613-836-3160\\
+111 Banning Rd \\
+Kanata, Ontario \\
+K2L 1C3 \\
+Canada 
+}
+\maketitle
+\newpage
+\tableofcontents
+\chapter{Introduction}
+\section{What is the Libtomcrypt?}
+Libtomcrypt is a portable ANSI C cryptographic library that supports symmetric ciphers, one-way hashes, 
+pseudo-random number generators, public key cryptography (via RSA,DH or ECC/DH) and a plethora of support 
+routines.  It is designed to compile out of the box with the GNU C Compiler (GCC) version 2.95.3 (and higher) 
+and with MSVC version 6 in win32.
+
+The library is designed so new ciphers/hashes/PRNGs can be added at runtime and the existing API (and helper API functions) will 
+be able to use the new designs automatically.  There exist self-check functions for each cipher and hash to ensure that
+they compile and execute to the published design specifications.  The library also performs extensive parameter error checking
+and will give verbose error messages.
+
+Essentially the library saves the time of having to implement the ciphers, hashes, prngs yourself.  Typically implementing
+useful cryptography is an error prone business which means anything that can save considerable time and effort is a good
+thing.
+
+\subsection{What the library IS for?}
+
+The library typically serves as a basis for other protocols and message formats.  For example, it should be possible to 
+take the RSA routines out of this library, apply the appropriate message padding and get PKCS compliant RSA routines.  
+Similarly SSL protocols could be formed on top  of the low-level symmetric cipher functions.  The goal of this package is 
+to provide these low level core functions in a robust and easy to use fashion.
+
+The library also serves well as a toolkit for applications where they don't need to be OpenPGP, PKCS, etc. compliant.
+Included are fully operational public key routines for encryption, decryption, signature generation and verification.  
+These routines are fully portable but are not conformant to any known set of standards.  They are all based on established
+number theory and cryptography.  
+
+\subsection{What the library IS NOT for?}
+
+The library is not designed to be in anyway an implementation of the SSL, PKCS or OpenPGP standards.  The library is not 
+designed  to be compliant with any known form of API or programming hierarchy.  It is not a port of any other 
+library and it is not platform specific (like the MS CSP).  So if you're looking to drop in some buzzword 
+compliant crypto this library is not for you.  The library has been written from scratch to provide basic 
+functions as well as non-standard higher level functions.  
+
+This is not to say that the library is a ``homebrew'' project.  All of the symmetric ciphers and one-way hash functions
+conform to published test vectors.  The public key functions are derived from publicly available material and the majority
+of the code has been reviewed by a growing community of developers.
+
+\subsubsection{Why not?}
+You may be asking why I didn't choose to go all out and support standards like P1363, PKCS and the whole lot.  The reason
+is quite simple too much money gets in the way.  I just recently tried to access the P1363 draft documents and was denied (it 
+requires a password).  If people are supposed to support these standards they had better make them more accessible.
+
+\section{Why did I write it?}
+You may be wondering, ``Tom, why did you write a crypto library.  I already have one.''.  Well the reason falls into
+two categories:
+\begin{enumerate}
+    \item I am too lazy to figure out someone else's API.  I'd rather invent my own simpler API and use that.
+    \item It was (still is) good coding practice.
+\end{enumerate}
+
+The idea is that I am not striving to replace OpenSSL or Crypto++ or Cryptlib or etc.  I'm trying to write my 
+{\bf own} crypto library and hopefully along the way others will appreciate the work.
+
+With this library all core functions (ciphers, hashes, prngs) have the {\bf exact} same prototype definition.  They all load
+and store data in a format independent of the platform.  This means if you encrypt with Blowfish on a PPC it should decrypt
+on an x86 with zero problems.  The consistent API also means that if you learn how to use blowfish with my library you 
+know how to use Safer+ or RC6 or Serpent or ... as well.  With all of the core functions there are central descriptor tables 
+that can be used to make a program automatically pick between ciphers, hashes and PRNGs at runtime.  That means your 
+application can support all ciphers/hashes/prngs without changing the source code.
+
+\section{License}
+
+All of the source code except for the following files have been written by the author or donated to the project
+under the TDCAL license:
+
+\begin{enumerate}
+   \item aes.c
+   \item mpi.c
+   \item rc2.c
+   \item serpent.c
+   \item safer.c
+\end{enumerate}
+
+``aes.c'' and ``serpent.c'' were written by Brian Gladman ([email protected]).  They are copyrighted works
+but were both granted unrestricted usage in any project (commercial or otherwise).  ``mpi.c'' was written by Michael 
+Fromberger ([email protected]).  Similarly it is copyrighted work but is free for all purposes.  
+``rc2.c'' is based on publicly available code that is not attributed to a person from the given source.  ``safer.c'' 
+was written by Richard De Moliner ([email protected]) and is public domain.
+
+The rest of the code was written either by Tom St Denis or contributed to the project under the ``Tom Doesn't Care
+About Licenses'' (TDCAL) license.  Essentially this license grants the user unlimited distribution and usage (including
+commercial usage).  I assume no risk from usage of the code nor do I guarantee it works as desired or stated.  
+
+\section{Patent Disclosure}
+
+The author (Tom St Denis) is not a patent lawyer so this section is not to be treated as legal advice.  To the best
+of the authors knowledge the only patent related issues within the library are the RC5 and RC6 symmetric block ciphers.  
+They can be removed from a build by simply commenting out the two appropriate lines in the makefile script.  The rest
+of the ciphers and hashes are patent free or under patents that have since expired.
+
+The RC2 and RC4 symmetric ciphers are not under patents but are under trademark regulations.  This means you can use 
+the ciphers you just can't advertise that you are doing so.  
+
+\section{Building the library}
+
+To build the library on a GCC equipped platform simply type ``make'' at your command prompt.  It will build the library
+file ``libtomcrypt.a''.  
+
+To install the library copy all of the ``.h'' files into your ``\#include'' path and the single libtomcrypt.a file into 
+your library path.
+
+With MSVC you can build the library with ``make -f makefile.vc''.  You must use GNU make to build it even with MSVC
+due to the limitations of the MS MAKE.
+
+\section{Building against the library}
+
+To build an application against the library you obviously must first compile the library.  However, an important 
+step is that the build options you use to build the library must be present when you build your application.  For 
+instance if ``RC5'' is defined in the makefile when you built the library then you must ensure ``RC5'' is defined when
+you build your application.
+
+The simplest way to work with this library is to take the makefile provided and simply add on your project to it as a 
+target (dependent on the library).  That way you can be assured that the library and your application are in sync with
+the build options you provide.
+
+\section{Thanks}
+I would like to give thanks to the following people (in no particular order) for helping me develop this project:
+\begin{enumerate}
+   \item Richard van de Laarschot
+   \item Richard Heathfield
+   \item Ajay K. Agrawal
+   \item Brian Gladman
+   \item Svante Seleborg
+   \item Clay Culver
+   \item Jason Klapste
+   \item Dobes Vandermeer
+   \item Daniel Richards
+   \item Wayne Scott
+   \item Andrew Tyler
+   \item Sky Schulz
+\end{enumerate}
+
+\chapter{The Application Programming Interface (API)}
+\section{Introduction}
+\index{CRYPT\_ERROR} \index{CRYPT\_OK}
+
+In general the API is very simple to memorize and use.  Most of the functions return either {\bf void} or {\bf int}.  Functions
+that return {\bf int} will return {\bf CRYPT\_OK} if the function was successful or one of the many error codes 
+if it failed.  Certain functions that return int will return $-1$ to indicate an error.  These functions will be explicitly
+commented upon.  When a function does return a CRYPT error code it can be translated into a string with
+
+\begin{verbatim}
+const char *error_to_string(int errno);
+\end{verbatim}
+
+An example of handling an error is:
+\begin{verbatim}
+void somefunc(void)
+{
+   int errno;
+   
+   /* call a cryptographic function */
+   if ((errno = some_crypto_function(...)) != CRYPT_OK) {
+      printf("A crypto error occured, %s\n", error_to_string(errno));
+      /* perform error handling */
+   }
+   /* continue on if no error occured */
+}
+\end{verbatim}
+
+There is no initialization routine for the library and for the most part the code is thread safe.  The only thread
+related issue is if you use the same symmetric cipher, hash or public key state data in multiple threads.  Normally
+that is not an issue.
+
+To include the prototypes for ``LibTomCrypt.a'' into your own program simply include ``mycrypt.h'' like so:
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void) {
+    return 0;
+}
+\end{verbatim}
+
+The header file ``mycrypt.h'' also includes ``stdio.h'', ``string.h'', ``stdlib.h'', ``time.h'', ``ctype.h'' and ``mpi.h''
+(the bignum library routines).
+
+\section{Macros}
+
+There are a few helper macros to make the coding process a bit easier.  The first set are related to loading and storing
+32/64-bit words in little/big endian format.  The macros are:
+
+\index{STORE32L} \index{STORE64L} \index{LOAD32L} \index{LOAD64L}
+\index{STORE32H} \index{STORE64H} \index{LOAD32H} \index{LOAD64H} \index{BSWAP}
+\begin{small}
+\begin{center}
+\begin{tabular}{|c|c|c|}
+     \hline STORE32L(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $x \to y[0 \ldots 3]$ \\
+     \hline STORE64L(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $x \to y[0 \ldots 7]$ \\
+     \hline LOAD32L(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $y[0 \ldots 3] \to x$ \\
+     \hline LOAD64L(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $y[0 \ldots 7] \to x$ \\
+     \hline STORE32H(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $x \to y[3 \ldots 0]$ \\
+     \hline STORE64H(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $x \to y[7 \ldots 0]$ \\
+     \hline LOAD32H(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $y[3 \ldots 0] \to x$ \\
+     \hline LOAD64H(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $y[7 \ldots 0] \to x$ \\
+     \hline BSWAP(x) & {\bf unsigned long} x & Swaps the byte order of x. \\
+     \hline
+\end{tabular}
+\end{center}
+\end{small}
+
+There are 32-bit cyclic rotations as well:
+\index{ROL} \index{ROR}
+\begin{center}
+\begin{tabular}{|c|c|c|}
+     \hline ROL(x, y) & {\bf unsigned long} x, {\bf unsigned long} y & $x << y$ \\
+     \hline ROR(x, y) & {\bf unsigned long} x, {\bf unsigned long} y & $x >> y$ \\
+     \hline
+\end{tabular}
+\end{center}
+
+\section{Functions with Variable Length Output}
+Certain functions such as (for example) ``rsa\_export()'' give an output that is variable length.  To prevent buffer overflows you
+must pass it the length of the buffer\footnote{Extensive error checking is not in place but it will be in future releases so it is a good idea to follow through with these guidelines.} where
+the output will be stored.  For example:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void) {
+    rsa_key key;
+    unsigned char buffer[1024];
+    unsigned long x;
+    int errno;
+
+    /* ... Make up the RSA key somehow */
+
+    /* lets export the key, set x to the size of the output buffer */
+    x = sizeof(buffer);
+    if ((errno = rsa_export(buffer, &x, PK_PUBLIC, &key)) != CRYPT_OK) {
+       printf("Export error: %s\n", error_to_string(errno));
+       return -1;
+    }
+    
+    /* if rsa_export() was successful then x will have the size of the output */
+    printf("RSA exported key takes %d bytes\n", x);
+
+    /* ... do something with the buffer */
+
+    return 0;
+}
+\end{verbatim}
+\end{small}
+In the above example if the size of the RSA public key was more than 1024 bytes this function would not store anything in
+either ``buffer'' or ``x'' and simply return an error code.  If the function suceeds it stores the length of the output
+back into ``x'' so that the calling application will know how many bytes used.
+
+\section{Functions that need a PRNG}
+Certain functions such as ``rsa\_make\_key()'' require a PRNG.  These functions do not setup the PRNG themselves so it is 
+the responsibility of the calling function to initialize the PRNG before calling them.
+
+\section{Functions that use Arrays of Octets}
+Most functions require inputs that are arrays of the data type ``unsigned char''.  Whether it is a symmetric key, IV
+for a chaining mode or public key packet it is assumed that regardless of the actual size of ``unsigned char'' only the
+lower eight bits contain data.  For example, if you want to pass a 256 bit key to a symmetric ciphers setup routine
+you must pass it in (a pointer to) an array of 32 ``unsigned char'' variables.  Certain routines 
+(such as SAFER+) take special care to work properly on platforms where an ``unsigned char'' is not eight bits.
+
+For the purposes of this library the term ``byte'' will refer to an octet or eight bit word.  Typically an array of
+type ``byte'' will be synonymous with an array of type ``unsigned char''.
+
+\chapter{Symmetric Block Ciphers}
+\section{Core Functions}
+
+Libtomcrypt provides several block ciphers all in a plain vanilla ECB block mode.  Its important to first note that you 
+should never use the ECB modes directly to encrypt data.  Instead you should use the ECB functions to make a chaining mode
+or use one of the provided chaining modes.  All of the ciphers are written as ECB interfaces since it allows the rest of
+the API to grow in a modular fashion.
+
+All ciphers store their scheduled keys in a single data type called ``symmetric\_key''.  This allows all ciphers to 
+have the same prototype and store their keys as  naturally as possible.  All ciphers provide five visible functions which
+are (given that XXX is the name of the cipher):
+\index{Cipher Setup}
+\begin{verbatim}
+int XXX_setup(const unsigned char *key, int keylen, int rounds, 
+              symmetric_key *skey);
+\end{verbatim}
+
+The XXX\_setup() routine will setup the cipher to be used with a given number of rounds and a given key length (in bytes).
+The number of rounds can be set to zero to use the default, which is generally a good idea.
+
+If the function returns successfully the variable ``skey'' will have a scheduled key stored in it.  Its important to note
+that you should only used this scheduled key with the intended cipher.  For example, if you call 
+``blowfish\_setup()'' do not pass the scheduled key onto ``rc5\_ecb\_encrypt()''.  All setup functions do not allocate 
+memory off the heap so when you are done with a key you can simply discard it (e.g. they can be on the stack).
+
+To encrypt or decrypt a block in ECB mode there are these two functions:
+\index{Cipher Encrypt} \index{Cipher Decrypt}
+\begin{verbatim}
+void XXX_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+                     symmetric_key *skey);
+
+void XXX_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+                     symmetric_key *skey);
+\end{verbatim}
+These two functions will encrypt or decrypt (respectively) a single block of text\footnote{The size of which depends on
+which cipher you are using.} and store the result where you want it.  It is possible that the input and output buffer are 
+the same buffer.  For the encrypt function ``pt''\footnote{pt stands for plaintext.} is the input and ``ct'' is the output.
+For the decryption function its the opposite.  To test a particular cipher against test vectors\footnote{As published in their design papers.} call: \index{Cipher Testing}
+\begin{verbatim}
+int XXX_test(void);
+\end{verbatim}
+This function will return {\bf CRYPT\_OK} if the cipher matches the test vectors from the design publication it is 
+based upon.  Finally for each cipher there is a function which will help find a desired key size:
+\begin{verbatim}
+int XXX_keysize(int *keysize);
+\end{verbatim}
+Essentially it will round the input keysize in ``keysize'' down to the next appropriate key size.  This function
+return {\bf CRYPT\_OK} if the key size specified is acceptable.  For example:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   int keysize, errno;
+
+   /* now given a 20 byte key what keysize does Twofish want to use? */
+   keysize = 20;
+   if ((errno = twofish_keysize(&keysize)) != CRYPT_OK) {
+      printf("Error getting key size: %s\n", error_to_string(errno));
+      return -1;
+   }
+   printf("Twofish suggested a key size of %d\n", keysize);
+   return 0;
+}
+\end{verbatim}
+\end{small}
+This should indicate a keysize of sixteen bytes is suggested.  An example snippet that encodes a block with 
+Blowfish in ECB mode is below.
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{ 
+   unsigned char pt[8], ct[8], key[8];
+   symmetric_key skey;
+   int errno;
+
+   /* first register Blowfish */
+   if (register_cipher(&blowfish_desc) == -1) {
+      printf("Error registering Blowfish.\n");
+      return -1;
+   }
+
+   /* ... key is loaded appropriately in ``key'' ... */
+   /* ... load a block of plaintext in ``pt'' ... */
+
+   /* schedule the key */
+   if ((errno = blowfish_setup(key, 8, 0, &skey)) != CRYPT_OK) {
+      printf("Setup error: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* encrypt the block */
+   blowfish_ecb_encrypt(pt, ct, &skey);
+
+   /* decrypt the block */
+   blowfish_ecb_decrypt(ct, pt, &skey);
+
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+\section{Key Sizes and Number of Rounds}
+\index{Symmetric Keys}
+As a general rule of thumb do not use symmetric keys under 80 bits if you can.  Only a few of the ciphers support smaller
+keys (mainly for test vectors anyways).  Ideally your application should be making at least 256 bit keys.  This is not
+because you're supposed to be paranoid.  Its because if your PRNG has a bias of any sort the more bits the better.  For
+example, if you have $\mbox{Pr}\left[X = 1\right] = {1 \over 2} \pm \gamma$ where $\vert \gamma \vert > 0$ then the
+total amount of entropy in N bits is $N \cdot -log_2\left ({1 \over 2} + \vert \gamma \vert \right)$.  So if $\gamma$
+were $0.25$ (a severe bias) a 256-bit string would have about 106 bits of entropy whereas a 128-bit string would have
+only 53 bits of entropy.
+
+The number of rounds of most ciphers is not an option you can change.  Only RC5 allows you to change the number of
+rounds.  By passing zero as the number of rounds all ciphers will use their default number of rounds.  Generally the
+ciphers are configured such that the default number of rounds provide adequate security for the given block size.
+
+\section{The Cipher Descriptors}
+\index{Cipher Descriptor}
+To facilitate automatic routines an array of cipher descriptors is provided in the array ``cipher\_descriptor''.  An element
+of this array has the following format:
+
+\begin{verbatim}
+struct _cipher_descriptor {
+   char *name;
+   unsigned long min_key_length, max_key_length, 
+                 block_length, default_rounds;
+   int  (*setup)      (const unsigned char *key, int keylength, 
+                       int num_rounds, symmetric_key *skey);
+   void (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, 
+                       symmetric_key *key);
+   void (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt,
+                       symmetric_key *key);
+   int  (*test)       (void);
+   int  (*keysize)    (int *desired_keysize);
+};
+\end{verbatim}
+
+Where ``name'' is the lower case ASCII version of the name.  The fields ``min\_key\_length'', ``max\_key\_length'' and
+``block\_length'' are all the number of bytes not bits.  As a good rule of thumb it is assumed that the cipher supports
+the min and max key lengths but not always everything in between.  The ``default\_rounds'' field is the default number
+of rounds that will be used.
+
+The remaining fields are all pointers to the core functions for each cipher.  The end of the cipher\_descriptor array is
+marked when ``name'' equals {\bf NULL}.
+
+As of this release the current cipher\_descriptors elements are
+
+\begin{small}
+\begin{center}
+\begin{tabular}{|c|c|c|c|c|c|}
+     \hline Name & Descriptor Name & Block Size (bytes) & Key Range (bytes) & Rounds \\
+     \hline Blowfish & blowfish\_desc & 8 & 8 ... 56 & 16 \\
+     \hline X-Tea & xtea\_desc & 8 & 16 & 32 \\
+     \hline RC2 & rc2\_desc & 8 & 8 .. 128 & 16 \\
+     \hline RC5-32/12/b & rc5\_desc & 8 & 8 ... 128 & 12 ... 24 \\
+     \hline RC6-32/20/b & rc6\_desc & 16 & 8 ... 128 & 20 \\
+     \hline SAFER+ & saferp\_desc &16 & 16, 24, 32 & 8, 12, 16 \\
+     \hline Safer K64   & safer\_k64\_desc & 8 & 8 & 6 .. 13 \\
+     \hline Safer SK64  & safer\_sk64\_desc & 8 & 8 & 6 .. 13 \\
+     \hline Safer K128  & safer\_k128\_desc & 8 & 16 & 6 .. 13 \\
+     \hline Safer SK128 & safer\_sk128\_desc & 8 & 16 & 6 .. 13 \\
+     \hline Serpent & serpent\_desc & 16 & 16 .. 32 & 32 \\
+     \hline Rijndael (AES) & rijndael\_desc & 16 & 16, 24, 32 & 10, 12, 14 \\
+     \hline Twofish & twofish\_desc & 16 & 16, 24, 32 & 16 \\
+     \hline DES & des\_desc & 8 & 7 & 16 \\
+     \hline 3DES (EDE mode) & des3\_desc & 8 & 21 & 16 \\
+     \hline CAST5 (CAST-128) & cast5\_desc & 8 & 5 .. 16 & 12, 16 \\
+     \hline
+\end{tabular}
+\end{center}
+\end{small}
+
+\subsection{Notes}
+For the 64-bit SAFER famliy of ciphers (e.g K64, SK64, K128, SK128) the ecb\_encrypt() and ecb\_decrypt()
+functions are the same.  So if you want to use those functions directly just call safer\_ecb\_encrypt()
+or safer\_ecb\_decrypt() respectively.
+
+Note that for ``DES'' and ``3DES'' they use 8 and 24 byte keys but only 7 and 21 [respectively] bytes of the keys are in
+fact used for the purposes of encryption.  My suggestion is just to use random 8/24 byte keys instead of trying to make a 8/24
+byte string from the real 7/21 byte key.
+
+Note that ``Twofish'' has additional configuration options that take place at build time.  These options are found in
+the file ``mycrypt\_cfg.h''.  The first option is ``TWOFISH\_SMALL'' which when defined will force the Twofish code
+to not pre-compute the Twofish ``$g(X)$'' function as a set of four $8 \times 32$ s-boxes.  This means that a scheduled
+key will require less ram but the resulting cipher will be slower.  The second option is ``TWOFISH\_TABLES'' which when
+defined will force the Twofish code to use pre-computed tables for the two s-boxes $q_0, q_1$ as well as the multiplication
+by the polynomials 5B and EF used in the MDS multiplication.  As a result the code is faster and slightly larger.  The
+speed increase is useful when ``TWOFISH\_SMALL'' is defined since the s-boxes and MDS multiply form the heart of the
+Twofish round function.
+
+\begin{small}
+\begin{center}
+\begin{tabular}{|l|l|l|}
+\hline TWOFISH\_SMALL & TWOFISH\_TABLES & Speed and Memory (per key) \\
+\hline undefined & undefined & Very fast, 4.2KB of ram. \\
+\hline undefined & defined & As above, faster keysetup, larger code (1KB more). \\
+\hline defined & undefined & Very slow, 0.2KB of ram. \\
+\hline defined & defined & Somewhat faster, 0.2KB of ram, larger code. \\
+\hline
+\end{tabular}
+\end{center}
+\end{small}
+
+To work with the cipher\_descriptor array there is a function:
+\begin{verbatim}
+int find_cipher(char *name)
+\end{verbatim}
+Which will search for a given name in the array.  It returns negative one if the cipher is not found, otherwise it returns
+the location in the array where the cipher was found.  For example, to indirectly setup Blowfish you can also use:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   unsigned char key[8];
+   symmetric_key skey;
+   int errno;
+
+   /* you must register a cipher before you use it */
+   if (register_cipher(&blowfish_desc)) == -1) {
+      printf("Unable to register Blowfish cipher.");
+      return -1;
+   }
+
+   /* generic call to function (assuming the key in key[] was already setup) */
+   if ((errno = cipher_descriptor[find_cipher("blowfish")].setup(key, 8, 0, &skey)) != CRYPT_OK) {
+      printf("Error setting up Blowfish: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* ... use cipher ... */
+}
+\end{verbatim}
+\end{small}
+
+A good safety would be to check the return value of ``find\_cipher()'' before accessing the desired function.  In order
+to use a cipher with the descriptor table you must register it first using:
+\begin{verbatim}
+int register_cipher(const struct _cipher_descriptor *cipher);
+\end{verbatim}
+Which accepts a pointer to a descriptor and returns the index into the global descriptor table.  If an error occurs such
+as there is no more room (it can have 32 ciphers at most) it will return {\bf{-1}}.  If you try to add the same cipher more
+than once it will just return the index of the first copy.  To remove a cipher call:
+\begin{verbatim}
+int unregister_cipher(const struct _cipher_descriptor *cipher);
+\end{verbatim}
+Which returns {\bf CRYPT\_OK} if it removes it otherwise it returns {\bf CRYPT\_ERROR}.  Consider:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   int errno;
+   
+   /* register the cipher */
+   if (register_cipher(&rijndael_desc) == -1) {
+      printf("Error registering Rijndael\n");
+      return -1;
+   }
+
+   /* use Rijndael */
+
+   /* remove it */
+   if ((errno = unregister_cipher(&rijndael_desc)) != CRYPT_OK) {
+      printf("Error removing Rijndael: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   return 0;
+}
+\end{verbatim}
+\end{small}
+This snippet is a small program that registers only Rijndael only.  Note you must register ciphers before
+using the PK code since all of the PK code (RSA, DH and ECC) rely heavily on the descriptor tables.
+
+\section{Symmetric Modes of Operations}
+\subsection{Background}
+A typical symmetric block cipher can be used in chaining modes to effectively encrypt messages larger than the block
+size of the cipher.  Given a key $k$, a plaintext $P$ and a cipher $E$ we shall denote the encryption of the block
+$P$ under the key $k$ as $E_k(P)$.  In some modes there exists an initial vector denoted as $C_{-1}$.
+
+\subsubsection{ECB Mode}
+ECB or Electronic Codebook Mode is the simplest method to use.  It is given as:
+\begin{equation}
+C_i = E_k(P_i)
+\end{equation}
+This mode is very weak since it allows people to swap blocks and perform replay attacks if the same key is used more
+than once.
+
+\subsubsection{CBC Mode}
+CBC or Cipher Block Chaining mode is a simple mode designed to prevent trivial forms of replay and swap attacks on ciphers.
+It is given as:
+\begin{equation}
+C_i = E_k(P_i \oplus C_{i - 1})
+\end{equation}
+It is important that the initial vector be unique and preferably random for each message encrypted under the same key.
+
+\subsubsection{CTR Mode}
+CTR or Counter Mode is a mode which only uses the encryption function of the cipher.  Given a initial vector which is
+treated as a large binary counter the CTR mode is given as:
+\begin{eqnarray}
+C_{-1} = C_{-1} + 1\mbox{ }(\mbox{mod }2^W) \nonumber \\
+C_i = P_i \oplus E_k(C_{-1})
+\end{eqnarray}
+Where $W$ is the size of a block in bits (e.g. 64 for Blowfish).  As long as the initial vector is random for each message
+encrypted under the same key replay and swap attacks are infeasible.  CTR mode may look simple but it is as secure
+as the block cipher is under a chosen plaintext attack (provided the initial vector is unique).
+
+\subsubsection{CFB Mode}
+CFB or Ciphertext Feedback Mode is a mode akin to CBC.  It is given as:
+\begin{eqnarray}
+C_i = P_i \oplus C_{-1} \nonumber \\
+C_{-1} = E_k(C_i)
+\end{eqnarray}
+Note that in this library the output feedback width is equal to the size of the block cipher.  That is this mode is used
+to encrypt whole blocks at a time.  However, the library will buffer data allowing the user to encrypt or decrypt partial
+blocks without a delay.  When this mode is first setup it will initially encrypt the initial vector as required.
+
+\subsubsection{OFB Mode}
+OFB or Output Feedback Mode is a mode akin to CBC as well.  It is given as:
+\begin{eqnarray}
+C_{-1} = E_k(C_{-1}) \nonumber \\
+C_i = P_i \oplus C_{-1}
+\end{eqnarray}
+Like the CFB mode the output width in CFB mode is the same as the width of the block cipher.  OFB mode will also
+buffer the output which will allow you to encrypt or decrypt partial blocks without delay.
+
+\subsection{Choice of Mode}
+My personal preference is for the CTR mode since it has several key benefits:
+\begin{enumerate}
+   \item No short cycles which is possible in the OFB and CFB modes.
+   \item Provably as secure as the block cipher being used under a chosen plaintext attack.
+   \item Technically does not require the decryption routine of the cipher.
+   \item Allows random access to the plaintext.
+   \item Allows the encryption of block sizes that are not equal to the size of the block cipher.
+\end{enumerate}
+The CTR, CFB and OFB routines provided allow you to encrypt block sizes that differ from the ciphers block size.  They 
+accomplish this by buffering the data required to complete a block.  This allows you to encrypt or decrypt any size 
+block of memory with either of the three modes.
+
+The ECB and CBC modes process blocks of the same size as the cipher at a time.  Therefore they are less flexible than the
+other modes.
+
+\subsection{Implementation}
+\index{CBC Mode} \index{CTR Mode}
+\index{OFB Mode} \index{CFB Mode}
+The library provides simple support routines for handling CBC, CTR, CFB, OFB and ECB encoded messages.  Assuming the mode 
+you want is XXX there is a structure called ``symmetric\_XXX'' that will contain the information required to
+use that mode.  They have identical setup routines (except ECB mode for obvious reasons):
+\begin{verbatim}
+int XXX_start(int cipher, const unsigned char *IV, 
+              const unsigned char *key, int keylen, 
+              int num_rounds, symmetric_XXX *XXX);
+
+int ecb_start(int cipher, const unsigned char *key, int keylen, 
+              int num_rounds, symmetric_ECB *ecb);
+\end{verbatim}
+
+In each case ``cipher'' is the index into the cipher\_descriptor array of the cipher you want to use.  The ``IV'' value is 
+the initialization vector to be used with the cipher.  You must fill the IV yourself and it is assumed they are the same 
+length as the block size\footnote{In otherwords the size of a block of plaintext for the cipher, e.g. 8 for DES, 16 for AES, etc.} 
+of the cipher you choose.  It is important that the IV  be random for each unique message you want to encrypt.  The 
+parameters ``key'', ``keylen'' and ``num\_rounds'' are the same as in the XXX\_setup() function call.  The final parameter 
+is a pointer to the structure you want to hold the information for the mode of operation.
+
+Both routines return {\bf CRYPT\_OK} if the cipher initialized correctly, otherwise they return an error code.  To 
+actually encrypt or decrypt the following routines are provided:
+\begin{verbatim}
+int XXX_encrypt(const unsigned char *pt, unsigned char *ct, 
+                symmetric_XXX *XXX);
+int XXX_decrypt(const unsigned char *ct, unsigned char *pt,
+                symmetric_XXX *XXX);
+
+int YYY_encrypt(const unsigned char *pt, unsigned char *ct, 
+                unsigned long len, symmetric_YYY *YYY);
+int YYY_decrypt(const unsigned char *ct, unsigned char *pt, 
+                unsigned long len, symmetric_YYY *YYY);
+\end{verbatim}
+Where ``XXX'' is one of (ecb, cbc) and ``YYY'' is one of (ctr, ofb, cfb).  In the CTR, OFB and CFB cases ``len'' is the
+size of the buffer (as number of chars) to encrypt or decrypt.  The CTR, OFB and CFB modes are order sensitive but not
+chunk sensitive.  That is you can encrypt ``ABCDEF'' in three calls like ``AB'', ``CD'', ``EF'' or two like ``ABCDE'' and ``F''
+and end up with the same ciphertext.  However, encrypting ``ABC'' and ``DABC'' will result in different ciphertexts.  All
+four of the functions return {\bf CRYPT\_OK} on success.
+
+To decrypt in either mode you simply perform the setup like before (recall you have to fetch the IV value you used)
+and use the decrypt routine on all of the blocks.  When you are done working with either mode you should wipe the 
+memory (using ``zeromem()'') to help prevent the key from leaking.  For example:
+\newpage
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   unsigned char key[16], IV[16], buffer[512];
+   symmetric_CTR ctr;
+   int x, errno;
+
+   /* register twofish first */
+   if (register_cipher(&twofish_desc) == -1) {
+      printf("Error registering cipher.\n");
+      return -1;
+   }
+
+   /* somehow fill out key and IV */
+
+   /* start up CTR mode */
+   if ((errno = ctr_start(find_cipher("twofish"), IV, key, 16, 0, &ctr)) != CRYPT_OK) {
+      printf("ctr_start error: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* somehow fill buffer than encrypt it */
+   if ((errno = ctr_encrypt(buffer, buffer, sizeof(buffer), &ctr)) != CRYPT_OK) {
+      printf("ctr_encrypt error: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* make use of ciphertext... */
+
+   /* clear up and return */
+   zeromem(key, sizeof(key));
+   zeromem(&ctr, sizeof(ctr));
+
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+\chapter{One-Way Cryptographic Hash Functions}
+\section{Core Functions}
+
+Like the ciphers there are hash core functions and a universal data type to hold the hash state called ``hash\_state''.  
+To initialize hash XXX (where XXX is the name) call:
+\index{Hash Functions}
+\begin{verbatim}
+void XXX_init(hash_state *md);
+\end{verbatim}
+
+This simply sets up the hash to the default state governed by the specifications of the hash.  To add data to the 
+message being hashed call:
+\begin{verbatim}
+void XXX_process(hash_state *md, const unsigned char *in, unsigned long len);
+\end{verbatim}
+
+Essentially all hash messages are virtually infinitely\footnote{Most hashes are limited to $2^{64}$ bits or 2,305,843,009,213,693,952 bytes.} long message which 
+are buffered.  The data can be passed in any sized chunks as long as the order of the bytes are the same the message digest
+(hash output) will be the same.  For example, this means that:
+\begin{verbatim}
+md5_process(&md, "hello ", 6);
+md5_process(&md, "world", 5);
+\end{verbatim}
+Will produce the same message digest as the single call:
+\index{Message Digest}
+\begin{verbatim}
+md5_process(&md, "hello world", 11);
+\end{verbatim}
+
+To finally get the message digest (the hash) call:
+\begin{verbatim}
+void XXX_done(hash_state *md, 
+              unsigned char *out);
+\end{verbatim}
+
+This function will finish up the hash and store the result in the ``out'' array.  You must ensure that ``out'' is long
+enough for the hash in question.  Often hashes are used to get keys for symmetric ciphers so the ``XXX\_done()'' functions
+will wipe the ``md'' variable before returning automatically.
+
+To test a hash function call:
+\begin{verbatim}
+int XXX_test(void);
+\end{verbatim}
+
+This will return {\bf CRYPTO\_OK} if the hash matches the test vectors, otherwise it returns an error code.  An
+example snippet that hashes a message with md5 is given below.
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+    hash_state md;
+    unsigned char *in = "hello world", out[16];
+
+    /* setup the hash */
+    md5_init(&md);
+
+    /* add the message */
+    md5_process(&md, in, strlen(in));
+
+    /* get the hash */
+    md5_done(&md, out);
+
+    return 0;
+}
+\end{verbatim}
+\end{small}
+
+\section{Hash Descriptors}
+\index{Hash Descriptors}
+Like the set of ciphers the set of hashes have descriptors too.  They are stored in an array called ``hash\_descriptor'' and
+are defined by:
+\begin{verbatim}
+struct _hash_descriptor {
+    char *name;
+    unsigned long hashsize;    /* digest output size in bytes  */
+    unsigned long blocksize;   /* the block size the hash uses */
+    void (*init)   (hash_state *);
+    void (*process)(hash_state *, const unsigned char *, unsigned long);
+    void (*done)   (hash_state *, unsigned char *);
+    int  (*test)   (void);
+};
+\end{verbatim}
+
+Similarly ``name'' is the name of the hash function in ASCII (all lowercase).  ``hashsize'' is the size of the digest output
+in bytes.  The remaining fields are pointers to the functions that do the respective tasks.  There is a function to
+search the array as well called ``int find\_hash(char *name)''.  It returns -1 if the hash is not found, otherwise the
+position in the descriptor table of the hash.
+
+You can use the table to indirectly call a hash function that is chosen at runtime.  For example:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   unsigned char buffer[100], hash[MAXBLOCKSIZE];
+   int idx, x;
+   hash_state md;
+
+   /* register hashes .... */
+   if (register_hash(&md5_desc) == -1) {
+      printf("Error registering MD5.\n");
+      return -1;
+   }
+
+   /* register other hashes ... */
+
+   /* prompt for name and strip newline */
+   printf("Enter hash name: \n");
+   fgets(buffer, sizeof(buffer), stdin);
+   buffer[strlen(buffer) - 1] = 0;
+
+   /* get hash index */
+   idx = find_hash(buffer);
+   if (idx == -1) {
+      printf("Invalid hash name!\n");
+      return -1;
+   }
+
+   /* hash input until blank line */
+   hash_descriptor[idx].init(&md);
+   while (fgets(buffer, sizeof(buffer), stdin) != NULL)
+         hash_descriptor[idx].process(&md, buffer, strlen(buffer));
+   hash_descriptor[idx].done(&md, hash);
+
+   /* dump to screen */
+   for (x = 0; x < hash_descriptor[idx].hashsize; x++)
+       printf("%02x ", hash[x]);
+   printf("\n");
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+Note the usage of ``MAXBLOCKSIZE''.  In Libtomcrypt no symmetric block, key or hash digest is larger than MAXBLOCKSIZE in
+length.  This provides a simple size you can set your automatic arrays to that will not get overrun.
+
+There are three helper functions as well:
+\index{hash\_memory()} \index{hash\_file()}
+\begin{verbatim}
+int hash_memory(int hash, const unsigned char *data, 
+                unsigned long len, unsigned char *dst,
+                unsigned long *outlen);
+
+int hash_file(int hash, const char *fname, 
+              unsigned char *dst,
+              unsigned long *outlen);
+
+int hash_filehandle(int hash, FILE *in, 
+                    unsigned char *dst, unsigned long *outlen);
+\end{verbatim}
+
+Both functions return {\bf CRYPT\_OK} on success, otherwise they return an error code.  The ``hash'' parameter is
+the location in the descriptor table of the hash.  The ``*outlen'' variable is used to keep track of the output size.  You
+must set it to the size of your output buffer before calling the functions.  When they complete succesfully they store
+the length of the message digest back in it.  The functions are otherwise straightforward.  The ``hash\_filehandle'' function
+assumes that ``in'' is an file handle opened in binary mode.  It will not reset the file position after hashing the content.
+
+To perform the above hash with md5 the following code could be used:
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   int idx, errno;
+   unsigned long len;
+   unsigned char out[MAXBLOCKSIZE];
+
+   /* register the hash */
+   if (register_hash(&md5_desc) == -1) {
+      printf("Error registering MD5.\n");
+      return -1;
+   }
+
+   /* get the index of the hash  */
+   idx = find_hash("md5");
+
+   /* call the hash */
+   len = sizeof(out);
+   if ((errno = hash_memory(idx, "hello world", 11, out, &len)) != CRYPT_OK) {
+      printf("Error hashing data: %s\n", error_to_string(errno));
+      return -1;
+   }
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+The following hashes are provided as of this release:
+\begin{center}
+\begin{tabular}{|c|c|c|}
+      \hline Name & Descriptor Name & Size of Message Digest (bytes) \\
+      \hline SHA-512 & sha512\_desc & 64 \\
+      \hline SHA-384 & sha384\_desc & 48 \\
+      \hline SHA-256 & sha256\_desc & 32 \\
+      \hline TIGER-192 & tiger\_desc & 24 \\
+      \hline SHA-1 & sha1\_desc & 20 \\
+      \hline MD5 & md5\_desc & 16 \\
+      \hline MD4 & md4\_desc & 16 \\
+      \hline MD2 & md2\_desc & 16 \\
+      \hline
+\end{tabular}
+\end{center}
+
+Similar to the cipher descriptor table you must register your hash algorithms before you can use them.  These functions
+work exactly like those of the cipher registration code.  The functions are:
+\begin{verbatim}
+int register_hash(const struct _hash_descriptor *hash);
+int unregister_hash(const struct _hash_descriptor *hash);
+\end{verbatim}
+
+\subsection{Notice}
+It is highly recommended that you not use the MD4 or MD5 hashes for the purposes of digital signatures or authentication codes.  
+These hashes are provided for completeness and they still can be used for the purposes of password hashing or one-way accumulators
+(e.g. Yarrow).
+
+The other hashes such as the SHA-1, SHA-2 (that includes SHA-512, SHA-384 and SHA-256) and TIGER-192 are still considered secure
+for all purposes you would normally use a hash for.
+
+\section{Hash based Message Authenication Codes}
+Thanks to Dobes Vandermeer the library now includes support for hash based message authenication codes or HMAC for short.  An HMAC
+of a message is a keyed authenication code that only the owner of a private symmetric key will be able to verify.  The purpose is
+to allow an owner of a private symmetric key to produce an HMAC on a message then later verify if it is correct.  Any impostor or
+eavesdropper will not be able to verify the authenticity of a message.  
+
+The HMAC support works much like the normal hash functions except that the initialization routine requires you to pass a key 
+and its length.  The key is much like a key you would pass to a cipher.  That is, it is simply an array of octets stored in
+chars.  The initialization routine is:
+\begin{verbatim}
+int hmac_init(hmac_state *hmac, int hash, 
+              const unsigned char *key, unsigned long keylen);
+\end{verbatim}
+The ``hmac'' parameter is the state for the HMAC code.  ``hash'' is the index into the descriptor table of the hash you want
+to use to authenticate the message.  ``key'' is the pointer to the array of chars that make up the key.  ``keylen'' is the
+length (in octets) of the key you want to use to authenticate the message.  To send octets of a message through the HMAC system you must use the following function:
+\begin{verbatim}
+int hmac_process(hmac_state *hmac, const unsigned char *buf,
+                  unsigned long len);
+\end{verbatim}
+``hmac'' is the HMAC state you are working with. ``buf'' is the array of octets to send into the HMAC process.  ``len'' is the
+number of octets to process.  Like the hash process routines you can send the data in arbitrarly sized chunks. When you 
+are finished with the HMAC process you must call the following function to get the HMAC code:
+\begin{verbatim}
+int  hmac_done(hmac_state *hmac, unsigned char *hash);
+\end{verbatim}
+``hmac'' is the HMAC state you are working with.  ``hash'' is the array of octets where the HMAC code should be stored.  You
+must ensure that your destination array is the right size (or just make it of size MAXBLOCKSIZE to be sure).  There are 
+two  utility functions provided to make using HMACs easier todo.
+\begin{verbatim}
+int hmac_memory(int hash, const unsigned char *key, unsigned long keylen,
+                const unsigned char *data, unsigned long len, 
+                unsigned char *dst);
+\end{verbatim}
+This will produce an HMAC code for the array of octets in ``data'' of length ``len''.  The index into the hash descriptor table must be provided in ``hash'' 
+It uses the key from ``key'' with a key length of ``keylen''.  The result is stored in the array of octets``dst''.  
+Similarly for files there is the following function:
+\begin{verbatim}
+int hmac_file(int hash, const char *fname, const unsigned char *key,
+              unsigned long keylen, unsigned char *dst);
+\end{verbatim}
+``hash'' is the index into the hash descriptor table of the hash you want to use.  ``fname'' is the filename to process.  ``key''
+is the array of octets to use as the key.  ``keylen'' is the length of the key.  ``dst'' is the array of octets where the result
+should be stored.
+
+To test if the HMAC code is working there is the following function:
+\begin{verbatim}
+int hmac_test(void);
+\end{verbatim}
+Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code.  Some example code for using the 
+HMAC system is given below.
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   int idx, errno;
+   hmac_state hmac;
+   unsigned char key[16], dst[MAXBLOCKSIZE];
+
+   /* register SHA-1 */
+   if (register_hash(&sha1_desc) == -1) {
+      printf("Error registering SHA1\n");
+      return -1;
+   }
+
+   /* get index of SHA1 in hash descriptor table */
+   idx = find_hash("sha1");
+
+   /* we would make up our symmetric key in "key[]" here */
+
+   /* start the HMAC */
+   if ((errno = hmac_init(&hmac, idx, key, 16)) != CRYPT_OK) {
+      printf("Error setting up hmac: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* process a few octets */
+   if((errno = hmac_process(&hmac, "hello", 5) != CRYPT_OK) {
+      printf("Error processing hmac: %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* get result (presumably to use it somehow...) */
+   if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) {
+      printf("Error finishing hmac: %s\n", error_to_string(errno));
+      return -1;
+   }
+  
+   /* return */
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+\chapter{Pseudo-Random Number Generators}
+\section{Core Functions}
+
+The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well.  A cryptographic PRNG is
+used to expand a shorter bit string into a longer bit string.  PRNGs are used wherever random data is required such as Public Key (PK)
+key generation.  There is a universal structure called ``prng\_state''.  To initialize a PRNG call:
+\begin{verbatim}
+int XXX_start(prng_state *prng);
+\end{verbatim}
+
+This will setup the PRNG for future use and not seed it.  In order 
+for the PRNG to be cryptographically useful you must give it entropy.  Ideally you'd have some OS level source to tap 
+like in UNIX (see section 5.3).  To add entropy to the PRNG call:
+\begin{verbatim}
+int XXX_add_entropy(const unsigned char *in, unsigned long len, 
+                    prng_state *prng);
+\end{verbatim}
+
+Which returns {\bf CRYPTO\_OK} if the entropy was accepted.  Once you think you have enough entropy you call another
+function to put the entropy into action.
+\begin{verbatim}
+int XXX_ready(prng_state *prng);
+\end{verbatim}
+
+Which returns {\bf CRYPTO\_OK} if it is ready.  Finally to actually read bytes call:
+\begin{verbatim}
+unsigned long XXX_read(unsigned char *out, unsigned long len,
+                       prng_state *prng);
+\end{verbatim}
+
+Which returns the number of bytes read from the PRNG.
+
+\subsection{Remarks}
+
+It is possible to be adding entropy and reading from a PRNG at the same time.  For example, if you first seed the PRNG
+and call ready() you can now read from it.  You can also keep adding new entropy to it.  The new entropy will not be used
+in the PRNG until ready() is called again.  This allows the PRNG to be used and re-seeded at the same time.  No real error 
+checking is guaranteed to see if the entropy is sufficient or if the PRNG is even in a ready state before reading.
+
+\subsection{Example}
+
+Below is a simple snippet to read 10 bytes from yarrow.  Its important to note that this snippet is {\bf NOT} secure since
+the entropy added is not random.
+
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   prng_state prng;
+   unsigned char buf[10];
+   int errno;
+   
+   /* start it */
+   if ((errno = yarrow_start(&prng)) != CRYPT_OK) {
+      printf("Start error: %s\n", error_to_string(errno));
+   }
+   /* add entropy */
+   if ((errno = yarrow_add_entropy("hello world", 11, &prng)) != CRYPT_OK) {
+      printf("Add_entropy error: %s\n", error_to_string(errno));
+   }
+   /* ready and read */
+   if ((errno = yarrow_ready(&prng)) != CRYPT_OK) {
+      printf("Ready error: %s\n", error_to_string(errno));
+   }
+   printf("Read %lu bytes from yarrow\n", yarrow_read(buf, 10, &prng));
+   return 0;
+}
+\end{verbatim}
+
+\section{PRNG Descriptors}
+\index{PRNG Descriptor}
+PRNGs have descriptors too (surprised?). Stored in the structure ``prng\_descriptor''.  The format of an element is:
+\begin{verbatim}
+struct _prng_descriptor {
+    char *name;
+    int (*start)      (prng_state *);
+    int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
+    int (*ready)      (prng_state *);
+    unsigned long (*read)(unsigned char *, unsigned long len, prng_state *);
+};
+\end{verbatim}
+
+There is a ``int find\_prng(char *name)'' function as well.  Returns -1 if the PRNG is not found, otherwise it returns
+the position in the prng\_descriptor array.
+
+Just like the ciphers and hashes you must register your prng before you can use it.  The two functions provided work
+exactly as those for the cipher registry functions.  They are:
+\begin{verbatim}
+int register_prng(const struct _prng_descriptor *prng);
+int unregister_prng(const struct _prng_descriptor *prng);
+\end{verbatim}
+
+\subsubsection{PRNGs Provided}
+Currently Yarrow (yarrow\_desc), RC4 (rc4\_desc) and the secure RNG (sprng\_desc) are provided as PRNGs within the 
+library.  
+
+RC4 is provided with a PRNG interface because it is a stream cipher and not well suited for the symmetric block cipher
+interface.  You provide the key for RC4 via the rc4\_add\_entropy() function.  By calling rc4\_ready() the key will be used
+to setup the RC4 state for encryption or decryption.  The rc4\_read() function has been modified from RC4 since it will 
+XOR the output of the RC4 keystream generator against the input buffer you provide.  The following snippet will demonstrate
+how to encrypt a buffer with RC4:
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   prng_state prng;
+   unsigned char buf[32];
+   int errno;
+
+   if ((errno = rc4_start(&prng)) != CRYPT_OK) {
+      printf("RC4 init error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* use ``key'' as the key */
+   if ((errno = rc4_add_entropy("key", 3, &prng)) != CRYPT_OK) {
+      printf("RC4 add entropy error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* setup RC4 for use */
+   if ((errno = rc4_ready(&prng)) != CRYPT_OK) {
+      printf("RC4 ready error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* encrypt buffer */
+   strcpy(buf,"hello world");
+   if (rc4_read(buf, 11, &prng) != 11) {
+      printf("RC4 read error\n");
+      exit(-1);
+   }
+   return 0;
+}   
+\end{verbatim}
+\end{small}
+To decrypt you have to do the exact same steps.  
+
+\section{The Secure RNG}
+\index{Secure RNG}
+An RNG is related to a PRNG except that it doesn't expand a smaller seed to get the data.  They generate their random bits
+by performing some computation on fresh input bits.  Possibly the hardest thing to get correctly in a cryptosystem is the 
+PRNG.  Computers are deterministic beasts that try hard not to stray from pre-determined paths.  That makes gathering 
+entropy needed to seed the PRNG a hard task.  
+
+There is one small function that may help on certain platforms:
+\index{rng\_get\_bytes()}
+\begin{verbatim}
+unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, 
+                  void (*callback)(void));
+\end{verbatim}
+
+Which will try one of three methods of getting random data.  The first is to open the popular ``/dev/random'' device which 
+on most *NIX platforms provides cryptographic random bits\footnote{This device is available in Windows through the Cygwin compiler suite.  It emulates ``/dev/random'' via the Microsoft CSP.}.  
+The second method is to try the Microsoft Cryptographic Service Provider and read the RNG.  The third method is an ANSI C 
+clock drift method that is also somewhat popular but gives bits of lower entropy.  The ``callback'' parameter is a pointer to a function that returns void.  Its used when the slower ANSI C RNG must be 
+used so the calling application can still work.  This is useful since the ANSI C RNG has a throughput of three 
+bytes a second.  The callback pointer may be set to {\bf NULL} to avoid using it if you don't want to.  The function 
+returns the number of bytes actually read from any RNG source.  There is a function to help setup a PRNG as well:
+\index{rng\_make\_prng()}
+\begin{verbatim}
+int rng_make_prng(int bits, int wprng, prng_state *prng, 
+                  void (*callback)(void));
+\end{verbatim}
+This will try to setup the prng with a state of at least ``bits'' of entropy.  The ``callback'' parameter works much like
+the callback in ``rng\_get\_bytes()''.  It is highly recommended that you use this function to setup your PRNGs unless you have a
+platform where the RNG doesn't work well.  Example usage of this function is given below.
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   ecc_key mykey;
+   prng_state prng;
+   int errno;
+
+   /* register yarrow */
+   if (register_prng(&yarrow_desc) == -1) {
+      printf("Error registering Yarrow\n");
+      return -1;
+   }
+
+   /* setup the PRNG */
+   if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, NULL)) != CRYPT_OK) {
+      printf("Error setting up PRNG, %s\n", error_to_string(errno));
+      return -1;
+   }
+
+   /* make a 192-bit ECC key */
+   if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &mykey)) != CRYPT_OK) {
+      printf("Error making key: %s\n", error_to_string(errno));
+      return -1;
+   }
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+\subsection{The Secure PRNG Interface}
+It is possible to access the secure RNG through the PRNG interface and in turn use it within dependent functions such
+as the PK API.  This simplifies the cryptosystem on platforms where the secure RNG is fast.  The secure PRNG never 
+requires to be started, that is you need not call the start, add\_entropy or ready functions.  For example, consider
+the previous example using this PRNG.
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   ecc_key mykey;
+   int errno;
+
+   /* register SPRNG */
+   if (register_prng(&sprng_desc) == -1) {
+      printf("Error registering SPRNG\n");
+      return -1;
+   }
+
+   /* make a 192-bit ECC key */
+   if ((errno = ecc_make_key(NULL, find_prng("sprng"), 24, &mykey)) != CRYPT_OK) {
+      printf("Error making key: %s\n", error_to_string(errno));
+      return -1;
+   }
+   return 0;
+}
+\end{verbatim}
+\end{small}
+
+\chapter{RSA Routines}
+
+\section{Background}
+
+RSA is a public key algorithm that is based on the inability to find the ``e-th'' root modulo a composite of unknown 
+factorization.  Normally the difficulty of breaking RSA is associated with the integer factoring problem but they are
+not strictly equivalent.
+
+The system begins with with two primes $p$ and $q$ and their product $N = pq$.  The order or ``Euler totient'' of the
+multiplicative sub-group formed modulo $N$ is given as $\phi(N) = (p - 1)(q - 1)$ which can be reduced to 
+$\mbox{lcm}(p - 1, q - 1)$.  The public key consists of the composite $N$ and some integer $e$ such that 
+$\mbox{gcd}(e, \phi(N)) = 1$.  The private key consists of the composite $N$ and the inverse of $e$ modulo $\phi(N)$ 
+often simply denoted as $de \equiv 1\mbox{ }(\mbox{mod }\phi(N))$.
+
+A person who wants to encrypt with your public key simply forms an integer (the plaintext) $M$ such that 
+$1 < M < N-2$ and computes the ciphertext $C = M^e\mbox{ }(\mbox{mod }N)$.  Since finding the inverse exponent $d$
+given only $N$ and $e$ appears to be intractable only the owner of the private key can decrypt the ciphertext and compute
+$C^d \equiv \left (M^e \right)^d \equiv M^1 \equiv M\mbox{ }(\mbox{mod }N)$.  Similarly the owner of the private key 
+can sign a message by ``decrypting'' it.  Others can verify it by ``encrypting'' it.  
+
+Currently RSA is a difficult system to cryptanalyze provided that both primes are large and not close to each other.  
+Ideally $e$ should be larger than $100$ to prevent direct analysis.  For example, if $e$ is three and you do not pad
+the plaintext to be encrypted than it is possible that $M^3 < N$ in which case finding the cube-root would be trivial.  
+The most often suggested value for $e$ is $65537$ since it is large enough to make such attacks impossible and also well 
+designed for fast exponentiation (requires 16 squarings and one multiplication).
+
+It is important to pad the input to RSA since it has particular mathematical structure.  For instance  
+$M_1^dM_2^d = (M_1M_2)^d$ which can be used to forge a signature.  Suppose $M_3 = M_1M_2$ is a message you want
+to have a forged signature for.  Simply get the signatures for $M_1$ and $M_2$ on their own and multiply the result
+together.  Similar tricks can be used to deduce plaintexts from ciphertexts.  It is important not only to sign 
+the hash of documents only but also to pad the inputs with data to remove such structure.  
+
+\section{Core Functions}
+
+For RSA routines a single ``rsa\_key'' structure is used.  To make a new RSA key call:
+\index{rsa\_make\_key()}
+\begin{verbatim}
+int rsa_make_key(prng_state *prng, 
+                 int wprng, int size, 
+                 long e, rsa_key *key);
+\end{verbatim}
+
+Where ``wprng'' is the index into the PRNG descriptor array.  ``size'' is the size in bytes of the RSA modulus desired.
+``e'' is the encryption exponent desired, typical values are 3, 17, 257 and 65537.  I suggest you stick with 65537 since its big
+enough to prevent trivial math attacks and not super slow.  ``key'' is where the key is placed.  All keys must be at 
+least 128 bytes and no more than 512 bytes in size (that is from 1024 to 4096 bits).
+
+Note that the ``rsa\_make\_key()'' function allocates memory at runtime when you make the key.  Make sure to call 
+``rsa\_free()'' (see below) when you are finished with the key.  If ``rsa\_make\_key()'' fails it will automatically 
+free the ram allocated itself.
+
+There are three types of RSA keys.  The types are {\bf PK\_PRIVATE\_OPTIMIZED}, {\bf PK\_PRIVATE} and {\bf PK\_PUBLIC}.  The first
+two are private keys where the ``optimized'' type uses the Chinese Remainder Theorem to speed up decryption/signatures.  By 
+default all new keys are of the ``optimized'' type.  The non-optimized private type is provided for backwards compatibility
+as well as to save space since the optimized key requires about four times as much memory.
+
+To do raw work with the RSA function call:
+\index{rsa\_exptmod()}
+\begin{verbatim}
+int rsa_exptmod(const unsigned char *in, unsigned long inlen, 
+                unsigned char *out, unsigned long *outlen, 
+                int which, rsa_key *key);
+\end{verbatim}
+This loads the bignum from ``in'' as a big endian word, raises it to either ``e'' or ``d'' and stores the result
+in ``out'' and the size of the result in ``outlen''. ``which'' is set to {\bf PK\_PUBLIC} to use ``e'' 
+(i.e. for encryption/verifying) and set to {\bf PK\_PRIVATE} to use ``d'' as the exponent (i.e. for decrypting/signing).
+
+\section{Packet Routines}
+The remaining RSA functions are non-standard but should (to the best of my knowledge) be secure if used correctly.  To
+encrypt a buffer of memory in a hybrid fashion call:
+\index{rsa\_encrypt()}
+\begin{verbatim}
+int rsa_encrypt(const unsigned char *in, unsigned long len, 
+                unsigned char *out, unsigned long *outlen,
+                prng_state *prng, int wprng, int cipher, 
+                rsa_key *key);
+\end{verbatim}
+This will encrypt the message with the cipher specified by ``cipher'' under a random key made by a PRNG specified by
+``wprng'' and RSA encrypt the symmetric key with ``key''.  This stores all the relevant information in ``out'' and sets
+the length in ``outlen''.  You must ensure that ``outlen'' is set to the buffer size before calling this.  
+
+The rsa\_encrypt() function will use up to a 256-bit symmetric key (limited by the max key length of the cipher being
+used).  To decrypt packets made by this routine call:
+\index{rsa\_decrypt()}
+\begin{verbatim}
+int rsa_decrypt(const unsigned char *in, unsigned long len, 
+                unsigned char *out, unsigned long *outlen, 
+                rsa_key *key);
+\end{verbatim}
+Which works akin to rsa\_encrypt().  ``in'' is the ciphertext and ``out'' is where the plaintext will be stored.  Similarly
+to sign/verify there are:
+\index{rsa\_sign()} \index{rsa\_verify()}
+\begin{verbatim}
+int rsa_sign(const unsigned char *in, unsigned long inlen, 
+                   unsigned char *out, unsigned long *outlen, 
+                   int hash, rsa_key *key);
+
+int rsa_verify(const unsigned char *sig,
+               const unsigned char *msg, 
+               unsigned long inlen, int *stat, 
+               rsa_key *key);
+\end{verbatim}
+
+The verify function sets ``stat'' to 1 if it passes or to 0 if it fails.  The ``sig'' parameter is the output of the
+rsa\_sign() function and ``msg'' is the original msg that was signed.  An important fact to note is that with
+the padding scheme used in ``rsa\_sign()'' you cannot use the SHA-384 or SHA-512 hash function with 1024 bit
+RSA keys.  This is because the padding makes the values too large to fit in the space allowed.  You can use SHA-384
+with 1160 and above bit RSA keys.  You can use SHA-512 with 1544 and above bit RSA keys.
+
+There are related functions to sign and verify hashes.
+\begin{verbatim}
+int rsa_sign_hash(const unsigned char *in,  unsigned long inlen, 
+                        unsigned char *out, unsigned long *outlen, 
+                        rsa_key *key);
+
+int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash,
+                          int *stat, rsa_key *key);
+\end{verbatim}
+Which works just like the two previous functions except the data is not hashed before being signed.
+
+There are times where you may want to encrypt a message to multiple recipients via RSA public keys.  The simplest way to
+accomplish this is to make up your own symmetric key and then RSA encrypt the symmetric key using all of the recipients
+public keys.  To facilitate this task two functions\footnote{Donated by Clay Culver.} are available:
+\begin{verbatim}
+int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen,
+                          unsigned char *outkey, unsigned long *outlen,
+                          prng_state *prng, int wprng, rsa_key *key);
+
+int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                          unsigned long *keylen, rsa_key *key);
+\end{verbatim}
+
+The ``rsa\_encrypt\_key()'' function accepts a symmetric key (limited to 32 bytes) as input in ``inkey''.  ``inlen''
+is the size of the input key in bytes.  The function will then ``rsa\_pad()'' the key and encrypt it using the RSA
+algorithm.  It will store the result in ``outkey'' along with the length in ``outlen''.  The ``rsa\_decrypt\_key()'' function
+performs the opposite.  The ``in'' variable is where the RSA packet goes and it will store the original symmetric key in
+the ``outkey'' variable along with its length in ``keylen''.
+
+To import/export RSA keys as a memory buffer (e.g. to store them to disk) call:
+\begin{verbatim}
+int rsa_export(unsigned char *out, unsigned long *outlen, 
+               int type, rsa_key *key);
+
+int rsa_import(const unsigned char *in, rsa_key *key);
+\end{verbatim}
+
+The ``type'' parameter is {\bf PK\_PUBLIC}, {\bf PK\_PRIVATE} or {\bf PK\_PRIVATE\_OPTIMIZED} to export either a public or 
+private key.  The latter type will export a key with the optimized parameters.  To free the memory used by an RSA key call:
+\index{rsa\_free()}
+\begin{verbatim}
+void rsa_free(rsa_key *key);
+\end{verbatim}
+
+Note that if the key fails to ``rsa\_import()'' you do not have to free the memory allocated for it.
+
+\section{Remarks}
+It is important that you match your RSA key size with the function you are performing.  The internal padding for both
+signatures and encryption triple the size of the plaintext you send to rsa\_exptmod().  This means to encrypt or sign
+a message of N bytes with rsa\_exptmod() you must have a modulus of 1+3N bytes.  Note that this doesn't affect the length
+of the plaintext you pass into functions like rsa\_encrypt().  This restriction applies only to data that is passed through
+RSA directly.
+
+The following table gives the size requirements for various hashes.
+\begin{center}
+\begin{tabular}{|c|c|c|}
+      \hline Name & Size of Message Digest (bytes) & RSA Key Size (bits)\\
+      \hline SHA-512 & 64 & 1544\\
+      \hline SHA-384 & 48 & 1160 \\
+      \hline SHA-256 & 32 & 776\\
+      \hline TIGER-192 & 24 & 584\\
+      \hline SHA-1 & 20 & 488\\
+      \hline MD5 & 16 & 392\\
+      \hline MD4 & 16 & 392\\
+      \hline
+\end{tabular}
+\end{center}
+
+The symmetric ciphers will use at a maximum a 256-bit key which means at the least a 776-bit RSA key is 
+required to use all of the symmetric ciphers with the RSA routines.  It is suggested that you make keys that 
+are at a minimum 1024 bits in length.  If you want to use any of the large size message digests 
+(SHA-512 or SHA-384) you will have to use a larger key.
+
+\chapter{Diffie-Hellman Key Exchange}
+
+\section{Background}
+
+Diffie-Hellman was the original public key system proposed.  The system is based upon the group structure
+of finite fields.  For Diffie-Hellman a prime $p$ is chosen and a ``base'' $b$ such that $b^x\mbox{ }(\mbox{mod }p)$ 
+generates a large sub-group of prime order (for unique values of $x$).
+
+A secret key is an exponent $x$ and a public key is the value of $y \equiv g^x\mbox{ }(\mbox{mod }p)$.  The term
+``discrete logarithm'' denotes the action of finding $x$ given only $y$, $g$ and $p$.  The key exchange part of
+Diffie-Hellman arises from the fact that two users A and B with keys $(A_x, A_y)$ and $(B_x, B_y)$ can exchange 
+a shared key $K \equiv B_y^{A_x} \equiv A_y^{B_x} \equiv g^{A_xB_x}\mbox{ }(\mbox{mod }p)$.
+
+From this public encryption and signatures can be developed.  The trivial way to encrypt (for example) using a public key 
+$y$ is to perform the key exchange offline.  The sender invents a key $k$ and its public copy 
+$k' \equiv g^k\mbox{ }(\mbox{mod }p)$ and uses $K \equiv k'^{A_x}\mbox{ }(\mbox{mod }p)$ as a key to encrypt
+the message with.  Typically $K$ would be sent to a one-way hash and the message digested used as a key in a 
+symmetric cipher.
+
+It is important that the order of the sub-group that $g$ generates not only be large but also prime.  There are
+discrete logarithm algorithms that take $\sqrt r$ time given the order $r$.  The discrete logarithm can be computed
+modulo each prime factor of $r$ and the results combined using the Chinese Remainder Theorem.  In the cases where 
+$r$ is ``B-Smooth'' (e.g. all small factors or powers of small prime factors) the solution is trivial to find.
+
+To thwart such attacks the primes and bases in the library have been designed and fixed.  Given a prime $p$ the order of
+ the sub-group generated is a large prime namely ${p - 1} \over 2$.  Such primes are known as ``strong primes'' and the 
+smaller prime (e.g. the order of the base) are known as Sophie-Germaine primes.
+
+\section{Core Functions}
+
+This library also provides core Diffie-Hellman functions so you can negotiate keys over insecure mediums.  The routines 
+provided are relatively easy to use and only take two function calls to negotiate a shared key.  There is a structure
+called ``dh\_key'' which stores the Diffie-Hellman key in a format these routines can use.  The first routine is to
+make a Diffie-Hellman private key pair:
+\index{dh\_make\_key()}
+\begin{verbatim}
+int dh_make_key(prng_state *prng, int wprng, 
+                int keysize, dh_key *key);
+\end{verbatim}
+The ``keysize'' is the size of the modulus you want in bytes.  Currently support sizes are 64 to 512 bytes which correspond 
+to key sizes of 512 to 4096 bits. The smaller the key the faster it is to use however it will be less secure.  When 
+specifying a size not explicitly supported by the library it will round {\em up} to the next key size.  If the size is 
+above 512 it will return an error.  So if you pass ``keysize == 32'' it will use a 512 bit key but if you pass 
+``keysize == 20000'' it will return an error.  The primes and generators used are built-into the library and were designed 
+to meet very specific goals.  The primes are strong primes which means that if $p$ is the prime then
+$p-1$ is equal to $2r$ where $r$ is a large prime.  The bases are chosen to generate a group of order $r$ to prevent
+leaking a bit of the key.  This means the bases generate a very large prime order group which is good to make cryptanalysis
+hard.
+
+As for Diffie-Hellman key sizes its recommended that you use at least a 768-bit key.  Since a 512-bit key has never been broken (its much
+harder than 512-bit RSA to attack) a 512-bit key setting is supported.  You can use it if you want I just suggest you don't.
+
+The next two routines are for exporting/importing Diffie-Hellman keys in a binary format.  This is useful for transport
+over communication mediums.  
+
+\index{dh\_export()} \index{dh\_import()}
+\begin{verbatim}
+int dh_export(unsigned char *out, unsigned long *outlen, 
+              int type, dh_key *key);
+
+int dh_import(const unsigned char *in, dh_key *key);
+\end{verbatim}
+
+These two functions work just like the ``rsa\_export()'' and ``rsa\_import()'' functions except these work with 
+Diffie-Hellman keys. Its important to note you do not have to free the ram for a ``dh\_key'' if an import fails.  You can free a 
+``dh\_key'' using:
+\begin{verbatim}
+void dh_free(dh_key *key);
+\end{verbatim}
+After you have exported a copy of your public key (using {\bf PK\_PUBLIC} as ``type'') you can now create a shared secret 
+with the other user using:
+\index{dh\_shared\_secret()}
+\begin{verbatim}
+int dh_shared_secret(dh_key *private_key, 
+                     dh_key *public_key, 
+                     unsigned char *out, unsigned long *outlen);
+\end{verbatim}
+
+Where ``private\_key'' is the key you made and ``public\_key'' is the copy of the public key the other user sent you.  The result goes
+into ``out'' and the length into ``outlen''.  If all went correctly the data in ``out'' should be identical for both parties.  It is important to
+note that the two keys have to be the same size in order for this to work.  There is a function to get the size of a
+key:
+\index{dh\_get\_size()}
+\begin{verbatim}
+int dh_get_size(dh_key *key);
+\end{verbatim}
+This returns the size in bytes of the modulus chosen for that key.
+
+\subsection{Remarks on Usage}
+Its important that you hash the shared key before trying to use it as a key for a symmetric cipher or something.  An 
+example program that communicates over sockets, using MD5 and 1024-bit DH keys is\footnote{This function is a small example.  It is suggested that proper packaging be used.  For example, if the public key sent is truncated these routines will not detect that.}:
+\newpage
+\begin{small}
+\begin{verbatim}
+int establish_secure_socket(int sock, int mode, unsigned char *key, 
+                            prng_state *prng, int wprng)
+{
+   unsigned char buf[4096], buf2[4096];
+   unsigned long x, len;
+   int res, errno;
+   dh_key mykey, theirkey;
+
+   /* make up our private key */
+   if ((errno = dh_make_key(prng, wprng, 128, &mykey)) != CRYPT_OK)  {
+      return errno;
+   }
+
+   /* export our key as public */ 
+   x = sizeof(buf);
+   if ((errno = dh_export(buf, &x, PK_PUBLIC, &mykey)) != CRYPT_OK) {
+      res = errno;
+      goto done2;
+   }
+
+   if (mode == 0) {
+      /* mode 0 so we send first */
+      if (send(sock, buf, x, 0) != x) {
+         res = CRYPT_ERROR;
+         goto done2;
+      }          
+
+      /* get their key */
+      if (recv(sock, buf2, sizeof(buf2), 0) <= 0) {
+         res = CRYPT_ERROR;
+         goto done2;
+      }
+   } else {
+      /* mode >0 so we send second */
+      if (recv(sock, buf2, sizeof(buf2), 0) <= 0) {
+         res = CRYPT_ERROR;
+         goto done2;
+      }
+
+      if (send(sock, buf, x, 0) != x) {
+         res = CRYPT_ERROR;
+         goto done2;
+      }
+   }
+
+   if ((errno = dh_import(buf2, &theirkey)) != CRYPT_OK) { 
+      res = errno;
+      goto done2;
+   }
+
+   /* make shared secret */
+   x = sizeof(buf);
+   if ((errno = dh_shared_secret(&mykey, &theirkey, buf, &x)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+ 
+   /* hash it */
+   len = 16;        /* default is MD5 so "key" must be at least 16 bytes long */
+   if ((errno = hash_memory(find_hash("md5"), buf, x, key, &len)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+
+   /* clean up and return */
+   res = CRYPT_OK;
+done:
+   dh_free(&theirkey);
+done2:
+   dh_free(&mykey);
+   zeromem(buf,  sizeof(buf));
+   zeromem(buf2, sizeof(buf2));
+   return res;
+}
+\end{verbatim}
+\end{small}
+\newpage
+\subsection{Remarks on The Snippet}
+When the above code snippet is done (assuming all went well) their will be a shared 128-bit key in the ``key'' array
+passed to ``establish\_secure\_socket()''.
+
+\section{Other Diffie-Hellman Functions}
+In order to test the Diffie-Hellman function internal workings (e.g. the primes and bases) their is a test function made
+available:
+\index{dh\_test()}
+\begin{verbatim}
+int dh_test(void);
+\end{verbatim}
+
+This function returns {\bf CRYPT\_OK} if the bases and primes in the library are correct.  There is one last helper 
+function:
+\index{dh\_sizes()}
+\begin{verbatim}
+void dh_sizes(int *low, int *high);
+\end{verbatim}
+Which stores the smallest and largest key sizes support into the two variables.
+
+\section{DH Packet}
+There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for DH keys as well.
+The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt
+the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose).  The encrypt
+function is a bit long to call but its worth it.
+\index{dh\_encrypt()}
+\begin{verbatim}
+int dh_encrypt(const unsigned char *in, unsigned long len, 
+               unsigned char *out, unsigned long *outlen,
+               prng_state *prng, int wprng, int cipher, int hash, 
+               dh_key *key);
+\end{verbatim}
+Where ``in'' is the plaintext and ``out'' is where the ciphertext will go.  Make sure you set the ``outlen'' value before
+calling.  The ``key'' is the public DH key of the user you want to encrypt to not your private key.  It will randomly make up
+a Diffie-Hellman key, export the public copy, hash the shared key with the hash you specify and use the message digest in a
+cipher you specify to encrypt the message. To decrypt one of these packets call:
+\index{dh\_decrypt()}
+\begin{verbatim}
+int dh_decrypt(const unsigned char *in, unsigned long len, 
+               unsigned char *out, unsigned long *outlen, 
+               dh_key *key);
+\end{verbatim}
+Where ``in'' is the ciphertext and len is the length of the ciphertext.  ``out'' is where the plaintext should be stored
+and ``outlen'' is the length of the output (you must first set it to the size of your buffer).  
+
+To facilate encrypting to multiple parties the follow two functions are provided:
+\begin{verbatim}
+int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                         unsigned char *out,  unsigned long *len, 
+                         prng_state *prng, int wprng, int hash, 
+                         dh_key *key);
+
+int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                         unsigned long *keylen, dh_key *key);
+\end{verbatim}
+Where ``inkey'' is an input symmetric key of no more than 32 bytes.  Essentially these routines created a random public key
+and find the hash of the shared secret.  The message digest is than XOR'ed against the symmetric key.  All of the required
+data is placed in ``out'' by ``dh\_encrypt\_key()''.   The hash must produce a message digest at least as large
+as the symmetric key you are trying to share.
+
+To sign with a Diffie-Hellman key call:
+\index{dh\_sign()}
+\begin{verbatim}
+int dh_sign(const unsigned char *in, unsigned long inlen, 
+            unsigned char *out, unsigned long *outlen, int hash, 
+            prng_state *prng, int wprng, dh_key *key);
+\end{verbatim}
+Where ``in'' is the message to size of length ``inlen'' bytes.  ``out'' is where the signature is placed and ``outlen''
+is the length of the signature (you must first set it to the size of your buffer).  To verify call:
+\index{dh\_verify()}
+\begin{verbatim}
+int dh_verify(const unsigned char *sig, 
+              const unsigned char *msg, 
+              unsigned long inlen, int *stat, dh_key *key);
+\end{verbatim}
+Where ``sig'' is the output of ''dh\_sign()`` and ``msg'' is the message of length ``inlen''.  It stores a zero in ``stat''
+if the signature is invalid otherwise it puts a one in there.
+
+Similar to the RSA system you can sign and verify a pre-hashed block as well using:
+\begin{verbatim}
+int dh_sign_hash(const unsigned char *in,  unsigned long inlen,
+                       unsigned char *out, unsigned long *outlen,
+                       prng_state *prng, int wprng, dh_key *key);
+
+int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                         unsigned long inlen, int *stat, 
+                         dh_key *key);
+\end{verbatim}
+
+\chapter{Elliptic Curve Cryptography}
+
+\section{Background}
+The library provides a set of core ECC functions as well that are designed to be the Elliptic Curve analogy of all of the 
+Diffie-Hellman routines in the previous chapter.  Elliptic curves (of certain forms) have the benefit that they are harder
+to attack (no sub-exponential attacks exist unlike normal DH crypto) in fact the fastest attack requires the square root
+of the order of the base point in time.  That means if you use a base point of order $2^{192}$ (which would represent a
+192-bit key) then the work factor is $2^{96}$ in order to find the secret key.
+
+The curves in this library are taken from the following website:
+\begin{verbatim}
+http://csrc.nist.gov/cryptval/dss.htm
+\end{verbatim}
+
+They are all curves over the integers modulo a prime.  The curves have the basic equation that is:
+\begin{equation}
+y^2 = x^3 - 3x + b\mbox{ }(\mbox{mod }p)
+\end{equation}
+
+The variable $b$ is chosen such that the number of points is nearly maximal.  In fact the order of the base points $\beta$ 
+provided are very close to $p$ that is $\vert \vert \phi(\beta) \vert \vert \approx \vert \vert p \vert \vert$.  The curves
+range in order from $\approx 2^{192}$ points to $\approx 2^{521}$.  According to the source document any key size greater
+than or equal to 256-bits is sufficient for long term security.  
+
+\section{Core Functions}
+
+Like the DH routines there is a key structure ``ecc\_key'' used by the functions.  There is a function to make a key:
+\index{ecc\_make\_key()}
+\begin{verbatim}
+int ecc_make_key(prng_state *prng, int wprng, 
+                 int keysize, ecc_key *key);
+\end{verbatim}
+
+The ``keysize'' is the size of the modulus in bytes desired.  Currently directly supported values are 20, 24, 28, 32, 48 and 65 bytes which
+correspond to key sizes of 160, 192, 224, 256, 384 and 521 bits respectively.  If you pass a key size that is between any key size
+it will round the keysize up to the next available one.  The rest of the parameters work like they do in the ``dh\_make\_key()'' function.  
+To free the ram allocated by a key call:
+\index{ecc\_free()}
+\begin{verbatim}
+void ecc_free(ecc_key *key);
+\end{verbatim}
+
+To import and export a key there are: 
+\index{ecc\_export()}
+\index{ecc\_import()}
+\begin{verbatim}
+int ecc_export(unsigned char *out, unsigned long *outlen, 
+               int type, ecc_key *key);
+
+int ecc_import(const unsigned char *in, ecc_key *key);
+\end{verbatim}
+These two work exactly like there DH counterparts.  Finally when you share your public key you can make a shared secret
+with:
+\index{ecc\_shared\_secret()}
+\begin{verbatim}
+int ecc_shared_secret(ecc_key *private_key, 
+                      ecc_key *public_key, 
+                      unsigned char *out, unsigned long *outlen);
+\end{verbatim}
+Which works exactly like the DH counterpart, the ``private\_key'' is your own key and ``public\_key'' is the key the other
+user sent you.   Note that this function stores both $x$ and $y$ co-ordinates of the shared
+elliptic point.  You should hash the output to get a shared key in a more compact and useful form (most of the entropy is 
+in $x$ anyways).  Both keys have to be the same size for this to work, to help there is a function to get the size in bytes
+ of a key.
+\index{ecc\_get\_size()}
+\begin{verbatim}
+int ecc_get_size(ecc_key *key);
+\end{verbatim}
+
+To test the ECC routines and to get the minimum and maximum key sizes there are these two functions:
+\index{ecc\_test()}
+\begin{verbatim}
+int ecc_test(void);
+void ecc_sizes(int *low, int *high);
+\end{verbatim}
+Which both work like their DH counterparts.
+
+\section{ECC Packet}
+There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for ECC keys as well.
+The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt
+the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose).  The encrypt
+function is a bit long to call but its worth it.
+\index{ecc\_encrypt()}
+\begin{verbatim}
+int ecc_encrypt(const unsigned char *in, unsigned long len, 
+                unsigned char *out, unsigned long *outlen,
+                prng_state *prng, 
+                int wprng, int cipher, int hash, 
+                ecc_key *key);
+\end{verbatim}
+Where ``in'' is the plaintext and ``out'' is where the ciphertext will go.  Make sure you set the ``outlen'' value before
+calling.  The ``key'' is the public ECC key of the user you want to encrypt too.  To decrypt one of these packets call:
+\index{ecc\_decrypt()}
+\begin{verbatim}
+int ecc_decrypt(const unsigned char *in, unsigned long len, 
+                unsigned char *out, unsigned long *outlen, 
+                ecc_key *key);
+\end{verbatim}
+Similar to the DH code there are two functions to facilate multi-party code.  They work exactly like the DH code and are 
+given as:
+\begin{verbatim}
+int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                          unsigned char *out,  unsigned long *len, 
+                          prng_state *prng, int wprng, int hash, 
+                          ecc_key *key);
+
+int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                          unsigned long *keylen, ecc_key *key);
+\end{verbatim}
+You can sign messages with the ECC routines as well, to sign a message call:
+\index{ecc\_sign()}
+\begin{verbatim}
+int ecc_sign(const unsigned char *in, unsigned long inlen, 
+             unsigned char *out, unsigned long *outlen, 
+             int hash, prng_state *prng, int wprng, 
+             ecc_key *key);
+\end{verbatim}
+Where ``in'' is the message to sign and ``out'' is where the signature will go.  ``hash'' is the index into the descriptor
+table of which hash function you want to use (e.g. use ``find\_hash()'').  You must set ``outlen'' to the size of the 
+output buffer before calling.  To verify a signature call:
+\index{ecc\_verify()}
+\begin{verbatim}
+int ecc_verify(const unsigned char *sig, const unsigned char *msg, 
+               unsigned long inlen, int *stat, ecc_key *key);
+\end{verbatim}
+Where ``sig'' is the signature from ``ecc\_sign()'' and ``msg'' is the input message.  It sets ``stat'' to 0 if the signature
+is invalid and it sets ``stat'' to 1 if its valid.  To sign or verify pre-hashed blocks use
+\begin{verbatim}
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, ecc_key *key);
+
+int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                          unsigned long inlen, int *stat, 
+                          ecc_key *key);
+\end{verbatim}
+
+\chapter{Public Keyrings}
+\section{Introduction}
+In order to simplify the usage of the public key algorithms a set of keyring routines have been developed.  They let the 
+developer manage asymmetric keys by providing load, save, export, import routines as well as encrypt, decrypt, sign, verify
+routines in a unified API.  That is all three types of PK systems can be used within the same keyring with the same API.
+
+To define types of keys there are four enumerations used globaly:
+\begin{verbatim}
+enum {
+   NON_KEY=0,
+   RSA_KEY,
+   DH_KEY,
+   ECC_KEY
+};
+\end{verbatim}
+
+To make use of the system the developer has to know how link-lists work.  The main structure that the keyring routines use 
+is the ``pk\_key'' defined as:
+\begin{small}
+\begin{verbatim}
+typedef struct Pk_key {
+    int     key_type,             /* PUBLIC, PRIVATE, PRIVATE_OPTIMIZED */
+            system;               /* RSA, ECC or DH ?   */
+
+    char    name[MAXLEN],         /* various info's about this key */
+            email[MAXLEN],
+            description[MAXLEN];
+
+    unsigned long ID;             /* CRC32 of the name/email/description together */
+
+    _pk_key key;
+
+    struct Pk_key  *next;         /* linked list chain */
+} pk_key;
+\end{verbatim}
+\end{small}
+
+The list is chained via the ``next'' member and terminated with the node of the list that has ``system'' equal to 
+{\bf NON\_KEY}.
+
+\section{The Keyring API}
+To initialize a blank keyring the function ``kr\_init()'' is used.
+\begin{verbatim}
+int kr_init(pk_key **pk);
+\end{verbatim}
+You pass it a pointer to a pointer of type ``pk\_key'' where it will allocate ram for one node of the keyring and sets the
+pointer.
+
+Now instead of calling the PK specific ``make\_key'' functions there is one function that can make all three types of keys.
+\begin{verbatim}
+int kr_make_key(pk_key *pk, prng_state *prng, int wprng, 
+                int system, int keysize, const char *name,
+                const char *email, const char *description);
+\end{verbatim}
+The ``name'', ``email'' and ``description'' parameters are simply little pieces of information that you can tag along with a
+key.  They can each be either blank or any string less than 256 bytes.  ``system'' is one of the enumeration elements, that
+is {\bf RSA\_KEY}, {\bf DH\_KEY} or {\bf ECC\_KEY}.  ``keysize'' is the size of the key you desire which is regulated by
+the individual systems, for example, RSA keys are limited in keysize from 128 to 512 bytes.
+
+To find keys along a keyring there are two functions provided:
+\begin{verbatim}
+pk_key *kr_find(pk_key *pk, unsigned long ID);
+
+pk_key *kr_find_name(pk_key *pk, const char *name);
+\end{verbatim}
+The first searches by the 32-bit ID provided and the latter checks the name against the keyring.  They both return a pointer
+to the node in the ring of a match or {\bf NULL} if no match is found.
+
+To export or import a single node of a keyring the two functions are provided:
+\begin{verbatim}
+int kr_export(pk_key *pk, unsigned long ID, int key_type, 
+              unsigned char *out, unsigned long *outlen);
+
+int kr_import(pk_key *pk, const unsigned char *in);
+\end{verbatim}
+The export function exports the key with an ID provided and of a specific type much like the normal PK export routines.  The
+``key\_type'' is one of {\bf PK\_PUBLIC} or {\bf PK\_PRIVATE}.  In this function with RSA keys the type 
+{\bf PK\_PRIVATE\_OPTIMIZED} is the same as the {\bf PK\_PRIVATE} type.  The import function will read in a packet and 
+add it to the keyring.  
+
+To load and save whole keyrings from disk:
+\begin{verbatim}
+int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr);
+
+int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr);
+\end{verbatim}
+Both take file pointers to allow the user to pre-append data to the stream.  The ``ctr'' parameter should be setup with 
+``ctr\_start'' or set to NULL.  This parameter lets the user encrypt the keyring as its written to disk, if it is set
+to NULL the data is written without being encrypted.  The load function assumes the list has not been initialized yet 
+and will reset the pointer given to it.
+
+There are the four encrypt, decrypt, sign and verify functions as well
+\begin{verbatim}
+int kr_encrypt_key(pk_key *pk, unsigned long ID, 
+                   const unsigned char *in, unsigned long inlen,
+                   unsigned char *out, unsigned long *outlen,
+                   prng_state *prng, int wprng, int hash);
+
+int kr_decrypt_key(pk_key *pk, const unsigned char *in,
+                   unsigned char *out, unsigned long *outlen);
+\end{verbatim}
+
+The kr\_encrypt\_key() routine is designed to encrypt a symmetric key with a specified users public key.  The symmetric
+key is then used with a block cipher to encode the message.  The recipient can call kr\_decrypt\_key() to get the original
+symmetric key back and decode the message.  The hash specified must produce a message digest longer than symmetric key 
+provided.  
+
+\begin{verbatim}
+int kr_sign_hash(pk_key *pk, unsigned long ID, 
+                 const unsigned char *in, unsigned long inlen,
+                 unsigned char *out, unsigned long *outlen,
+                 prng_state *prng, int wprng);
+
+int kr_verify_hash(pk_key *pk, const unsigned char *in, 
+                   const unsigned char *hash, unsigned long hashlen,
+                   int *stat);
+\end{verbatim}
+
+Similar to the two previous these are used to sign a message digest or verify one.  This requires hashing the message
+first then passing the output in. 
+
+To delete keys and clear rings there are:
+\begin{verbatim}
+int kr_del(pk_key **_pk, unsigned long ID);
+int kr_clear(pk_key **pk);
+\end{verbatim}
+``kr\_del'' will try to remove a key with a given ID from the ring and ``kr\_clear'' will completely empty a list and free
+the memory associated with it.  Below is small example using the keyring API:
+
+\begin{small}
+\begin{verbatim}
+#include <mycrypt.h>
+int main(void)
+{
+   pk_key *kr;
+   unsigned char buf[4096], buf2[4096];
+   unsigned long len;
+   int errno;
+
+   /* make a new list */
+   if ((errno = kr_init(&kr)) != CRYPT_OK) {
+      printf("kr_init: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* add a key to it */
+   register_prng(&sprng_desc);
+   if ((errno = kr_make_key(kr, NULL, find_prng("sprng"), RSA_KEY, 128, 
+                "TomBot", "[email protected]", "test key")) == CRYPT_OK) {
+      printf("kr_make_key: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* export the first key */
+   len = sizeof(buf);
+   if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf, &len)) != CRYPT_OK) {
+      printf("kr_export: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* ... */
+}  
+\end{verbatim}
+\end{small}
+
+\chapter{$GF(2^w)$ Math Routines}
+
+The library provides a set of polynomial-basis $GF(2^w)$ routines to help facilitate algorithms such as ECC over such
+fields.  Note that the current implementation of ECC in the library is strictly over the integers only.  The routines
+are simple enough to use for other purposes outside of ECC.  
+
+At the heart of all of the GF routines is the data type ``gf\_int'.  It is simply a type definition for an array of 
+$L$ 32-bit words.  You can configure the maximum size $L$ of the ``gf\_int'' type by opening the file ``mycrypt.h'' and 
+changing ``LSIZE''.  Note that if you set it to $n$ then you can only multiply upto two $n \over 2$ bit polynomials without
+an overflow.  The type ``gf\_intp'' is associated with a pointer to an ``unsigned long'' as required in the algorithms.
+
+There are no initialization routines for ``gf\_int'' variables and you can simply use them after declaration.  There are five
+low level functions:
+\index{gf\_copy()} \index{gf\_zero()} \index{gf\_iszero()} \index{gf\_isone()} 
+\index{gf\_deg()} 
+\begin{verbatim}
+void gf_copy(gf_intp a, gf_intp b);
+void gf_zero(gf_intp a);
+int gf_iszero(gf_intp a);
+int gf_isone(gf_intp a);
+int gf_deg(gf_intp a);
+\end{verbatim}
+There are all fairly self-explanatory.  ``gf\_copy(a, b)'' copies the contents of ``a'' into ``b''.  ``gf\_zero()'' simply
+zeroes the entire polynomial.  ``gf\_iszero()'' tests to see if the polynomial is all zero and ``gf\_isone()'' tests to see
+if the polynomial is equal to the multiplicative identity.  ``gf\_deg()'' returns the degree of the polynomial or $-1$ if its
+a zero polynomial.
+
+There are five core math routines as well:
+\index{gf\_shl()} \index{gf\_shr()} \index{gf\_add()} \index{gf\_mul()} \index{gf\_div()} 
+\begin{verbatim}
+void gf_shl(gf_intp a, gf_intp b);
+void gf_shr(gf_intp a, gf_intp b);
+void gf_add(gf_intp a, gf_intp b, gf_intp c);
+void gf_mul(gf_intp a, gf_intp b, gf_intp c);
+void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r);
+\end{verbatim}
+
+Which are all fairly obvious.  ``gf\_shl(a,b)'' multiplies the polynomial ``a'' by $x$ and stores it in ``b''.  
+``gf\_shl(a,b)'' divides the polynomial ``a'' by $x$ and stores it in ``b''.  ``gf\_add(a,b,c)'' adds the polynomial
+``a'' to ``b'' and stores the sum in ``c''.  Similarly for ``gf\_mul(a,b,c)''.  The ``gf\_div(a,b,q,r)'' function divides
+``a'' by ``b'' and stores the quotient in ``q'' and the remainder in ``r''.
+
+There are six number theoretic functions as well:
+\index{gf\_mod()} \index{gf\_mulmod()} \index{gf\_invmod()} \index{gf\_gcd()} \index{gf\_is\_prime()} 
+\index{gf\_sqrt()}
+\begin{verbatim}
+void gf_mod(gf_intp a, gf_intp m, gf_intp b);
+void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c);
+void gf_invmod(gf_intp A, gf_intp M, gf_intp B);
+void gf_sqrt(gf_intp a, gf_intp m, gf_intp b);
+void gf_gcd(gf_intp A, gf_intp B, gf_intp c);
+int gf_is_prime(gf_intp a);
+\end{verbatim}
+
+Which all work similarly except for  ``gf\_mulmod(a,b,m,c)'' which computes $c = ab\mbox{ }(\mbox{mod }m)$.  The 
+``gf\_is\_prime()'' function returns one if the polynomial is primitive, otherwise it returns zero.
+
+Finally to read/store a ``gf\_int'' in a binary string use:
+\index{gf\_size()} \index{gf\_toraw()} \index{gf\_readraw()} 
+\begin{verbatim}
+int gf_size(gf_intp a);
+void gf_toraw(gf_intp a, unsigned char *dst);
+void gf_readraw(gf_intp a, unsigned char *str, int len);
+\end{verbatim}
+Where ``gf\_size()'' returns the size in bytes required for the data.  ``gf\_toraw(a,b)'' stores the polynomial in ``b''
+in binary format (endian neutral).  ``gf\_readraw(a,b,c)'' reads the binary string in ``b'' back.  Note that the length 
+you pass it must be the same as returned by ``gf\_size()'' or it will not load correctly.
+
+\chapter{Miscellaneous}
+\section{Base64 Encoding and Decoding}
+The library provides functions to encode and decode a RFC1521 base64 coding scheme.  This means that it can decode what it 
+encodes but the format used does not comply to any known standard.  The characters used in the mappings are:
+\begin{verbatim}
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
+\end{verbatim}
+Those characters should are supported in virtually any 7-bit ASCII system which means they can be used for transport over
+common e-mail, usenet and HTTP mediums.  The format of an encoded stream is just a literal sequence of ASCII characters
+where a group of four represent 24-bits of input.  The first four chars of the encoders output is the length of the 
+original input.  After the first four characters is the rest of the message.
+
+Often it is desirable to line wrap the output to fit nicely in an e-mail or usenet posting.  The decoder allows you to
+put any character (that is not in the above sequence) in between any character of the encoders output.  You may not however,
+break up the first four characters.
+
+To encode a binary string in base64 call:
+\index{base64\_encode()}  \index{base64\_decode()} 
+\begin{verbatim}
+int base64_encode(const unsigned char *in, unsigned long len, 
+                  unsigned char *out, unsigned long *outlen);
+\end{verbatim}
+Where ``in'' is the binary string and ``out'' is where the ASCII output is placed.  You must set the value of ``outlen'' prior
+to calling this function and it sets the length of the base64 output in ``outlen'' when it is done.  To decode a base64 
+string call:
+\begin{verbatim}
+int base64_decode(const unsigned char *in, unsigned long len, 
+                  unsigned char *out, unsigned long *outlen);
+\end{verbatim}
+
+\section{The Multiple Precision Integer Library (MPI)}
+The library comes with a copy of Michael Fromberger's\footnote{Michael J. Fromberger, [email protected]} multiple
+precision integer library MPI.  MPI is a trivial to use ANSI C compatible large integer library.  It is free for all uses and
+is distributed freely.
+
+At the heart of all MPI functions is the data type ``mp\_int'' (defined in mpi.h).  This data type is what will hold all large
+integers.  In order to use an mp\_int one must initialize it first, for example:
+\begin{verbatim}
+#include <mycrypt.h> /* mycrypt.h includes mpi.h automatically */
+int main(void)
+{ 
+   mp_int bignum;
+   
+   /* initialize it */
+   mp_init(&bignum);
+
+   return 0;
+}
+\end{verbatim}
+If you are unfamiliar with the syntax of C the \& symbol is used to pass the address of ``bignum'' to the function.  All
+MPI functions require the address of the parameters.  To free the memory of a mp\_int use (for example):
+\begin{verbatim}
+mp_clear(&bignum);
+\end{verbatim}
+
+All MPI functions have the basic form of one of the following:
+\begin{verbatim}
+mp_XXX(mp_int *a);
+mp_XXX(mp_int *a, mp_int *b, mp_int *c);
+mp_XXX(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+\end{verbatim}
+
+Where they perform some operation and store the result in the mp\_int variable passed on the far right.  For example, to
+compute $c = a + b \mbox{ }(\mbox{mod }m)$ you would call:
+\begin{verbatim}
+mp_addmod(&a, &b, &m, &c);
+\end{verbatim}
+
+The simplest way to get a complete listing of all MPI functions is to open ``mpi.h'' and look.  They're all fairly 
+well documented.
+
+\subsection{Binary Forms of ``mp\_int'' Variables}
+
+Often it is required to store a ``mp\_int'' in binary form for transport (e.g. exporting a key, packet encryption, etc.).
+MPI includes two functions to help when exporting numbers:
+\begin{verbatim}
+int mp_raw_size(mp_int *num);
+mp_toraw(&num, buf);
+\end{verbatim}
+
+The former function gives the size in bytes of the raw format and the latter function actually stores the raw data.  All
+``mp\_int'' numbers are stored in big endian form (like PKCS demands) with the first byte being the sign of the number.  The
+``rsa\_exptmod()'' function differs slightly since it will take the input in the form exactly as PKCS demands (without the
+leading sign byte).  All other functions include the sign byte (since its much simpler just to include it).  The sign byte
+must be zero for positive numbers and non-zero for negative numbers.  For example,
+the sequence:
+\begin{verbatim}
+00 FF 30 04
+\end{verbatim}
+Represents the integer $255 \cdot 256^2 + 48 \cdot 256^1 + 4 \cdot 256^0$ or 16,723,972.
+
+To read a binary string back into a ``mp\_int'' call:
+\begin{verbatim}
+mp_read_raw(mp_int *num, unsigned char *str, int len);
+\end{verbatim}
+Where ``num'' is where to store it, ``str'' is the binary string (including the leading sign byte) and ``len'' is the 
+length of the binary string.
+
+\subsection{Primality Testing}
+\index{Primality Testing}
+The library includes primality testing and random prime functions as well.  The primality tester will perform the test in
+two phases.  First it will perform trial division by the first few primes.  Second it will perform sixteen rounds of the 
+Rabin-Miller primality testing algorithm.  If the candidate passes both phases it is declared prime otherwise it is declared
+composite.  No prime number will fail the two phases but composites can.  Each round of the Rabin-Miller algorithm reduces
+the probability of a pseudo-prime by $1 \over 4$ therefore after sixteen rounds the probability is no more than 
+$\left ( { 1 \over 4 } \right )^{16} = 2^{-32}$.  Even if a composite did make it through it would most likely cause the 
+the algorithm trying to use it to fail.  For instance, in RSA two primes $p$ and $q$ are required.  The order of the 
+multiplicative sub-group (modulo $pq$) is given as $\phi(pq)$ or $(p - 1)(q - 1)$.  The decryption exponent $d$ is found
+as $de \equiv 1\mbox{ }(\mbox{mod } \phi(pq))$.  If either $p$ or $q$ is composite the value of $d$ will be incorrect and the user
+will not be able to sign or decrypt messages at all.  Suppose $p$ was prime and $q$ was composite this is just a variation of 
+the multi-prime RSA.  Suppose $q = rs$ for two primes $r$ and $s$ then $\phi(pq) = (p - 1)(r - 1)(s - 1)$ which clearly is 
+not equal to $(p - 1)(rs - 1)$.
+
+These are not technically part of the MPI
+library\footnote{As written by Michael Fromberger} but this is the best place to document them.  To test if a ``mp\_int'' is
+prime call:
+\begin{verbatim}
+int is_prime(mp_int *N, int *result);
+\end{verbatim}
+This puts a one in ``result'' if the number is probably prime, otherwise it places a zero in it.  It is assumed that if 
+it returns an error that the value in ``result'' is undefined.  To make 
+a random prime call:
+\begin{verbatim}
+int rand_prime(mp_int *N, unsigned long len, prng_state *prng, int wprng);
+\end{verbatim}
+Where ``len'' is the size of the prime in bytes ($2 \le len \le 1024$).  You can set ``len'' to the negative size you want
+to get a prime of the form $p \equiv 3\mbox{ }(\mbox{mod } 4)$.  So if you want a 1024-bit prime of this sort pass 
+``len = -128'' to the function.  Upon success it will return {\bf CRYPT\_OK} and ``N'' will contain an integer which
+is very likely prime.
+
+\chapter{Programming Guidelines}
+
+\section{Secure Pseudo Random Number Generators}
+Probably the singal most vulnerable point of any cryptosystem is the PRNG.  Without one generating and protecting secrets
+would be impossible.  The requirement that one be setup correctly is vitally important and to address this point the library
+does provide two RNG sources that will address the largest amount of end users as possible.  The ``sprng'' PRNG provided 
+provides and easy to access source of entropy for any application on a *NIX or Windows computer.  
+
+However, when the end user is not on one of these platforms the application developer must address the issue of finding
+entropy.  This manual is not designed to be a text on cryptography.  I would just like to highlight that when you design
+a cryptosystem make sure the first problem you solve is getting a fresh source of entropy.  
+
+\section{Preventing Trivial Errors}
+Two simple ways to prevent trivial errors is to prevent overflows and to check the return values.  All of the functions
+which output variable length strings will require you to pass the length of the destination.  If the size of your output
+buffer is smaller than the output it will report an error.  Therefore, make sure the size you pass is correct!
+
+Also virtually all of the functions return an error code or {\bf CRYPT\_OK}.  You should detect all errors as simple 
+typos or such can cause algorithms to fail to work as desired.
+
+\section{Registering Your Algorithms}
+To avoid linking and other runtime errors it is important to register the ciphers, hashes and PRNGs you intend to use 
+before you try to use them.  This includes any function which would use an algorithm indirectly through a descriptor table.
+
+A neat bonus to the registry system is that you can add external algorithms that are not part of the library without 
+having to hack the library.  For example, suppose you have a hardware specific PRNG on your system.  You could easily 
+write the few functions required plus a descriptor.  After registering your PRNG all of the library functions that 
+need a PRNG can instantly take advantage of it.
+
+\section{Key Sizes}
+
+\subsection{Symmetric Ciphers}
+For symmetric ciphers use as large as of a key as possible.  For the most part ``bits are cheap'' so using a 256-bit key
+is not a hard thing todo.  
+
+\subsection{Assymetric Ciphers}
+The following chart gives the work factor for solving a DH/RSA public key using the NFS.  The work factor for a key of order
+$n$ is estimated to be
+\begin{equation}
+e^{1.923 \cdot ln(n)^{1 \over 3} \cdot ln(ln(n))^{2 \over 3}} 
+\end{equation}
+
+Note that $n$ is not the bit-length but the magnitude.  For example, for a 1024-bit key $n = 2^{1024}$.  The work required 
+is:
+\begin{center}
+\begin{tabular}{|c|c|}
+    \hline RSA/DH Key Size (bits) & Work Factor ($log_2$) \\
+    \hline 512 & 63.92 \\
+    \hline 768 & 76.50 \\
+    \hline 1024 & 86.76 \\
+    \hline 1536 & 103.37 \\
+    \hline 2048 & 116.88 \\
+    \hline 2560 & 128.47 \\
+    \hline 3072 & 138.73 \\
+    \hline 4096 & 156.49 \\
+    \hline 
+\end{tabular}
+\end{center}
+
+The work factor for ECC keys is much higher since the best attack is still fully exponentional.  Given a key of magnitude
+$n$ it requires $\sqrt n$ work.  The following table sumarizes the work required:
+\begin{center}
+\begin{tabular}{|c|c|}
+    \hline ECC Key Size (bits) & Work Factor ($log_2$) \\
+    \hline 160 & 80  \\
+    \hline 192 & 96  \\
+    \hline 224 & 112 \\
+    \hline 256 & 128 \\
+    \hline 384 & 192 \\
+    \hline 521 & 260.5 \\
+    \hline
+\end{tabular}
+\end{center}
+
+Using the above tables the following suggestions for key sizes seems appropriate:
+\begin{center}
+\begin{tabular}{|c|c|c|}
+    \hline Security Goal & RSA/DH Key Size (bits) & ECC Key Size (bits) \\
+    \hline Short term (less than a year) & 1024 & 160 \\
+    \hline Short term (less than five years) & 1536 & 192 \\
+    \hline Long Term (less than ten years) & 2560 & 256 \\
+    \hline 
+\end{tabular}
+\end{center}
+
+\section{Thread Safety}
+The library is not thread safe but several simple precautions can be taken to avoid any problems.  The registry functions
+such as register\_cipher() are not thread safe no matter what you do.  Its best to call them from your programs initializtion
+code before threads are initiated.
+
+The rest of the code uses state variables you must pass it such as hash\_state, hmac\_state, etc.  This means that if each
+thread has its own state variables then they will not affect each other.  This is fairly simple with symmetric ciphers
+and hashes.  However, the keyring and PRNG support is something the threads will want to share.  The simplest workaround 
+is create semaphores or mutexes around calls to those functions.  
+
+Since C does not have standard semaphores this support is not native to Libtomcrypt.  Even a C based semaphore is not entire
+possible as some compilers may ignore the ``volatile'' keyword or have multiple processors.  Provide your host application
+is modular enough putting the locks in the right place should not bloat the code significantly and will solve all thread
+safety issues within the library.
+
+\chapter{Configuring the Library}
+\section{Introduction}
+The library is fairly flexible about how it can be built, used and generally distributed.  Additions are being made with
+each new release that will make the library even more flexible.  Most options are placed in the makefile and others
+are in ``mycrypt\_cfg.h''.  All are used when the library is built from scratch.
+
+For GCC platforms the file ``makefile'' is the makefile to be used.  On MSVC platforms ``makefile.vc'' and on PS2 platforms
+``makefile.ps2''.
+
+\section{mycrypt\_cfg.h}
+The file ``mycrypt\_cfg.h'' is what lets you control what functionality you want to remove from the library.  By default,
+everything the library has to offer it built.  
+
+\subsubsection{ARGTYPE}
+This lets you control how the \_ARGCHK macro will behave.  The macro is used to check pointers inside the functions against
+NULL.  There are three settings for ARGTYPE.  When set to 0 it will have the default behaviour of printing a message to 
+stderr and raising a SIGABRT signal.  This is provided so all platforms that use libtomcrypt can have an error that functions
+similarly.  When set to 1 it will simply pass on to the assert() macro.  When set to 2 it will resolve to a empty macro
+and no error checking will be performed.
+
+\subsubsection{Endianess}
+There are five macros related to endianess issues.  For little endian platforms define, ENDIAN\_LITTLE.  For big endian
+platforms define ENDIAN\_BIG.  Similarly when the default word size of an ``unsigned long'' is 32-bits define ENDIAN\_32BITWORD
+or define ENDIAN\_64BITWORD when its 64-bits.  If you do not define any of them the library will automatically use ENDIAN\_NEUTRAL
+which will work on all platforms.  Currently the system will automatically detect GCC or MSVC on a windows platform as well
+as GCC on a PS2 platform.
+
+\section{The makefile}
+There are also options you can specify from the makefiles themselves.  
+
+\subsubsection{X memory routines}
+The makefiles must define three macros denoted as XMALLOC, XCALLOC and XFREE which resolve to the name of the respective
+functions.  This lets you substitute in your own memory routines.  If you substitute in your own functions they must behave
+like the standard C library functions in terms of what they expect as input and output.  By default the library uses the
+standard C routines.
+
+\subsubsection{X clock routines}
+The rng\_get\_bytes() function can call a function that requires the clock() function.  These macros let you override
+the default clock() used with a replacement.  By default the standard C library clock() function is used.
+
+\subsubsection{NO\_FILE}
+During the build if NO\_FILE is defined then any function in the library that uses file I/O will not call the file I/O 
+functions and instead simply return CRYPT\_ERROR.  This should help resolve any linker errors stemming from a lack of
+file I/O on embedded platforms.
+
+\subsubsection{CLEAN\_STACK}
+When this functions is defined the functions that store key material on the stack will clean up afterwards.  Assumes that
+you have no memory paging with the stack.
+
+\subsubsection{Symmetric Ciphers, One-way Hashes, PRNGS and Public Key Functions}
+There are a plethora of macros for the ciphers, hashes, PRNGs and public key functions which are fairly self-explanatory.  
+When they are defined the functionality is included otherwise it is not.  There are some dependency issues which are
+noted in the file.  For instance, Yarrow requires CTR chaining mode, a block cipher and a hash function.
+
+\subsubsection{TWOFISH\_SMALL and TWOFISH\_TABLES}
+Twofish is a 128-bit symmetric block cipher that is provided within the library.  The cipher itself is flexible enough
+to allow some tradeoffs in the implementation.  When TWOFISH\_SMALL is defined the scheduled symmetric key for Twofish 
+requires only 200 bytes of memory.  This is achieved by not pre-computing the substitution boxes.  Having this 
+defined will also greatly slow down the cipher.  When this macro is not defined Twofish will pre-compute the 
+tables at a cost of 4KB of memory.  The cipher will be much faster as a result.  
+
+When TWOFISH\_TABLES is defined the cipher will use pre-computed (and fixed in code) tables required to work.  This is
+useful when TWOFISH\_SMALL is defined as the table values are computed on the fly.  When this is defined the code size
+will increase by approximately 500 bytes.  If this is defined but TWOFISH\_SMALL is not the cipher will still work but
+it will not speed up the encryption or decryption functions.
+
+\subsubsection{SAFERP\_SMALL and RIJNDAEL\_SMALL}
+These two build options let you use slower versions of the ciphers which are also much smaller.  In the case of the SAFER+
+implementation it ends up being 1/6th the size.  As for Rijndael its roughly half the size.
+
+
+\end{document}

+ 77 - 0
ctr.c

@@ -0,0 +1,77 @@
+#include "mycrypt.h"
+
+#ifdef CTR
+
+int ctr_start(int cipher, const unsigned char *count, const unsigned char *key, int keylen, 
+              int num_rounds, symmetric_CTR *ctr)
+{
+   int x, errno;
+
+   _ARGCHK(count != NULL);
+   _ARGCHK(key != NULL);
+   _ARGCHK(ctr != NULL);
+
+   /* bad param? */
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* setup cipher */
+   if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ctr->key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* copy ctr */
+   ctr->blocklen = cipher_descriptor[cipher].block_length;
+   ctr->cipher   = cipher;
+   ctr->padlen   = 0;
+   for (x = 0; x < ctr->blocklen; x++) {
+       ctr->ctr[x] = count[x];
+   }
+   cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key);
+   return CRYPT_OK;
+}
+
+int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr)
+{
+   int x, errno;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ctr != NULL);
+
+   if ((errno = cipher_is_valid(ctr->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+
+   while (len--) {
+      /* is the pad empty? */
+      if (ctr->padlen == ctr->blocklen) {
+         /* increment counter */
+         for (x = 0; x < ctr->blocklen; x++) {
+            ctr->ctr[x] = (ctr->ctr[x] + 1) & 255;
+            if (ctr->ctr[x] != 0) {
+               break;
+            }
+         }
+
+         /* encrypt it */
+         cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key);
+         ctr->padlen = 0;
+      }
+      *ct++ = *pt++ ^ ctr->pad[ctr->padlen++];
+   }
+   return CRYPT_OK;
+}
+
+int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr)
+{
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ctr != NULL);
+
+   return ctr_encrypt(ct, pt, len, ctr);
+}
+
+#endif
+

+ 202 - 0
demos/encrypt.c

@@ -0,0 +1,202 @@
+/* encrypt V1.1 Fri Oct 18 04:28:03 NZDT 2002 */
+/* File de/encryption, using libtomcrypt */
+/* Written by Daniel Richards <[email protected]> */
+/* Help from Tom St Denis with various bits */
+/* This code is public domain, no rights reserved. */
+/* Encrypts by default, -d flag enables decryption */
+/* ie: ./encrypt blowfish story.txt story.ct */
+/* ./encrypt -d blowfish story.ct story.pt */
+
+#include <mycrypt.h>
+
+int errno;
+
+static const struct _cipher_descriptor *ciphers[] = {
+   &blowfish_desc,   &xtea_desc,        &rc5_desc,        &rc6_desc,
+   &saferp_desc,     &serpent_desc,     &rijndael_desc,
+   &twofish_desc,    &safer_k64_desc,   &safer_sk64_desc,
+   &safer_k128_desc, &safer_sk128_desc, &rc2_desc,
+   &des_desc,        &des3_desc,        &cast5_desc, NULL
+};
+
+int usage(void) 
+{
+   int x;
+
+   printf("Usage: ./crypt [-d](ecrypt) cipher infile outfile\nCiphers:\n");
+   for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+      printf("%s\n",cipher_descriptor[x].name);
+   }
+   exit(1);
+}
+
+void register_algs(void)
+{
+   int x;
+   
+   for (x = 0; ciphers[x] != NULL; x++) {
+       if (register_cipher(ciphers[x]) == -1) {
+          printf("Error registering cipher\n");
+          exit(-1);
+       }
+   }
+
+   if (register_hash(&sha256_desc) == -1) {
+      printf("Error registering SHA256\n");
+      exit(-1);
+   } 
+
+   if (register_prng(&yarrow_desc) == -1) {
+      printf("Error registering yarrow PRNG\n");
+      exit(-1);
+   }
+
+   if (register_prng(&sprng_desc) == -1) {
+      printf("Error registering sprng PRNG\n");
+      exit(-1);
+   }
+}
+
+int main(int argc, char *argv[]) 
+{
+   unsigned char plaintext[512],ciphertext[512];
+   unsigned char tmpkey[512], key[MAXBLOCKSIZE], IV[MAXBLOCKSIZE];
+   unsigned char inbuf[512]; /* i/o block size */
+   unsigned long outlen, y, ivsize, x, decrypt;
+   symmetric_CTR ctr;
+   int cipher_idx, hash_idx, ks;
+   char *infile, *outfile, *cipher;
+   prng_state prng;
+   FILE *fdin, *fdout;
+
+   /* register algs, so they can be printed */
+   register_algs();
+
+   if (argc < 4) {
+      return usage();
+   }
+
+   if (!strcmp(argv[1], "-d")) {
+      decrypt = 1;
+      cipher  = argv[2];
+      infile  = argv[3];
+      outfile = argv[4];
+   } else {
+      decrypt = 0;
+      cipher  = argv[1];
+      infile  = argv[2];
+      outfile = argv[3];
+   }   
+
+   /* file handles setup */
+   fdin = fopen(infile,"rb");
+   if (fdin == NULL) {
+      perror("Can't open input for reading");
+      exit(-1);
+   }
+
+   fdout = fopen(outfile,"wb");
+   if (fdout == NULL) { 
+      perror("Can't open output for writing");
+      exit(-1);
+   }
+ 
+   cipher_idx = find_cipher(cipher);
+   if (cipher_idx == -1) {
+      printf("Invalid cipher entered on command line.\n");
+      exit(-1);
+   }
+
+   hash_idx = find_hash("sha256");
+   if (hash_idx == -1) {
+      printf("SHA256 not found...?\n");
+      exit(-1);
+   }
+
+   ivsize = cipher_descriptor[cipher_idx].block_length;
+   ks = hash_descriptor[hash_idx].hashsize;
+   if (cipher_descriptor[cipher_idx].keysize(&ks) != CRYPT_OK) { 
+      printf("Invalid keysize???\n");
+      exit(-1);
+   }
+
+   printf("\nEnter key: ");
+   fgets(tmpkey,sizeof(tmpkey), stdin);
+   outlen = sizeof(key);
+   if ((errno = hash_memory(hash_idx,tmpkey,strlen(tmpkey),key,&outlen)) != CRYPT_OK) {
+      printf("Error hashing key: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   
+   if (decrypt) {
+      /* Need to read in IV */
+      if (fread(IV,1,ivsize,fdin) != ivsize) {
+         printf("Error reading IV from input.\n");
+         exit(-1);
+      }
+   
+      if ((errno = ctr_start(cipher_idx,IV,key,ks,0,&ctr)) != CRYPT_OK) {
+         printf("ctr_start error: %s\n",error_to_string(errno));
+         exit(-1);
+      }
+
+      /* IV done */
+      do {
+         y = fread(inbuf,1,sizeof(inbuf),fdin);
+
+         if ((errno = ctr_decrypt(inbuf,plaintext,y,&ctr)) != CRYPT_OK) {
+            printf("ctr_decrypt error: %s\n", error_to_string(errno));
+            exit(-1);
+         }
+
+         if (fwrite(plaintext,1,y,fdout) != y) {
+            printf("Error writing to file.\n");
+            exit(-1);
+         }
+      } while (y == sizeof(inbuf));
+      fclose(fdin);
+      fclose(fdout);
+
+   } else {  /* encrypt */
+      /* Setup yarrow for random bytes for IV */
+      
+      if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, NULL)) != CRYPT_OK) {
+         printf("Error setting up PRNG, %s\n", error_to_string(errno));
+      }      
+
+      /* You can use rng_get_bytes on platforms that support it */
+      /* x = rng_get_bytes(IV,ivsize,NULL);*/
+      x = yarrow_read(IV,ivsize,&prng);
+      if (x != ivsize) {
+         printf("Error reading PRNG for IV required.\n");
+         exit(-1);
+      }
+   
+      if (fwrite(IV,1,ivsize,fdout) != ivsize) {
+         printf("Error writing IV to output.\n");
+         exit(-1);
+      }
+
+      if ((errno = ctr_start(cipher_idx,IV,key,ks,0,&ctr)) != CRYPT_OK) {
+         printf("ctr_start error: %s\n",error_to_string(errno));
+         exit(-1);
+      }
+
+      do {
+         y = fread(inbuf,1,sizeof(inbuf),fdin);
+
+         if ((errno = ctr_encrypt(inbuf,ciphertext,y,&ctr)) != CRYPT_OK) {
+            printf("ctr_encrypt error: %s\n", error_to_string(errno));
+            exit(-1);
+         }
+
+         if (fwrite(ciphertext,1,y,fdout) != y) {
+            printf("Error writing to output.\n");
+            exit(-1);
+         }
+      } while (y == sizeof(inbuf));   
+      fclose(fdout);
+      fclose(fdin);
+   }
+   return 0;
+}

+ 77 - 0
demos/hashsum.c

@@ -0,0 +1,77 @@
+/*
+ * Written by Daniel Richards <[email protected]> 6/7/2002
+ * hash.c: This app uses libtomcrypt to hash either stdin or a file
+ * This file is Public Domain. No rights are reserved.
+ * Compile with 'gcc hashsum.c -o hashsum -ltomcrypt'
+ * This example isn't really big enough to warrent splitting into
+ * more functions ;)
+*/
+
+#include <mycrypt.h>
+
+int errno;
+
+void register_algs();
+
+int main(int argc, char **argv)
+{
+   int idx, x, z;
+   unsigned long w;
+   unsigned char hash_buffer[MAXBLOCKSIZE];
+   hash_state md;
+
+   /* You need to register algorithms before using them */
+   register_algs();
+   if (argc < 2) {
+      printf("usage: ./hash algorithm file [file ...]\n");
+      printf("Algorithms:\n");
+      for (x = 0; hash_descriptor[x].name != NULL; x++) {
+         printf(" %s\n", hash_descriptor[x].name);
+      }
+      exit(EXIT_SUCCESS);
+   }
+
+   idx = find_hash(argv[1]);
+   if (idx == -1) {
+      fprintf(stderr, "\nInvalid hash specified on command line.\n");
+      return -1;
+   }
+
+   if (argc == 2) {
+      hash_descriptor[idx].init(&md);
+      do {
+         x = fread(hash_buffer, 1, sizeof(hash_buffer), stdin);
+         hash_descriptor[idx].process(&md, hash_buffer, x);
+      } while (x == sizeof(hash_buffer));
+      hash_descriptor[idx].done(&md, hash_buffer);
+      for (x = 0; x < (int)hash_descriptor[idx].hashsize; x++) {
+          printf("%02x",hash_buffer[x]);
+      }
+      printf("  (stdin)\n");
+   } else {
+      for (z = 2; z < argc; z++) {
+         w = sizeof(hash_buffer);
+         if ((errno = hash_file(idx,argv[z],hash_buffer,&w)) != CRYPT_OK) {
+            printf("File hash error: %s\n", error_to_string(errno));
+         } else {
+             for (x = 0; x < (int)hash_descriptor[idx].hashsize; x++) {
+                 printf("%02x",hash_buffer[x]);
+             }
+             printf("  %s\n", argv[z]);
+         }
+      }
+   }
+   return EXIT_SUCCESS;
+}
+
+void register_algs(void) 
+{
+   register_hash(&sha512_desc);
+   register_hash(&sha384_desc);
+   register_hash(&sha256_desc);
+   register_hash(&sha1_desc);
+   register_hash(&md5_desc);
+   register_hash(&md4_desc);
+   register_hash(&tiger_desc);
+   register_hash(&md2_desc);
+}

+ 11 - 0
demos/small.c

@@ -0,0 +1,11 @@
+// small demo app that just includes a cipher/hash/prng
+
+#include <mycrypt.h>
+
+int main(void)
+{
+   register_cipher(&rijndael_desc);
+   register_prng(&yarrow_desc);
+   register_hash(&sha1_desc);
+   return 0;
+}

+ 1586 - 0
demos/test.c

@@ -0,0 +1,1586 @@
+/* This is the worst code you have ever seen written on purpose.... this code is just a big hack to test
+out the functionality of the library */
+
+#ifdef SONY_PS2
+#include <eetypes.h>
+#include <eeregs.h>
+#include "timer.h"
+#endif
+
+#include "../mycrypt.h"
+
+int errno;
+
+
+int null_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   return CRYPT_OK;
+}
+
+void null_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+{
+   memcpy(ct, pt, 8);
+}
+
+void null_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+{
+   memcpy(pt, ct, 8);
+}
+
+int null_test(void)
+{
+   return CRYPT_OK;
+}
+
+int null_keysize(int *desired_keysize)
+{
+   return CRYPT_OK;
+} 
+
+const struct _cipher_descriptor null_desc =
+{
+    "memcpy()",
+    255,
+    8, 8, 8, 1,
+    &null_setup,
+    &null_ecb_encrypt,
+    &null_ecb_decrypt,
+    &null_test,
+    &null_keysize
+};
+
+
+prng_state prng;
+
+void store_tests(void) 
+{
+ unsigned char buf[8];
+ unsigned long L;
+ ulong64 LL;
+
+ printf("LOAD32/STORE32 tests\n");
+ L = 0x12345678UL;
+ STORE32L(L, &buf[0]);
+ L = 0;
+ LOAD32L(L, &buf[0]);
+ if (L != 0x12345678UL) printf("LOAD/STORE32 Little don't work\n");
+ LL = CONST64(0x01020304050607);
+ STORE64L(LL, &buf[0]);
+ LL = 0;
+ LOAD64L(LL, &buf[0])
+ if (LL != CONST64(0x01020304050607)) printf("LOAD/STORE64 Little don't work\n");
+
+ L = 0x12345678UL;
+ STORE32H(L, &buf[0]);
+ L = 0;
+ LOAD32H(L, &buf[0]);
+ if (L != 0x12345678UL) printf("LOAD/STORE32 High don't work\n");
+ LL = CONST64(0x01020304050607);
+ STORE64H(LL, &buf[0]);
+ LL = 0;
+ LOAD64H(LL, &buf[0])
+ if (LL != CONST64(0x01020304050607)) printf("LOAD/STORE64 High don't work\n");
+}
+
+void cipher_tests(void) {
+   int x;
+
+   printf("Ciphers compiled in\n");
+ for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+     printf(" %12s (%2d) Key Size: %4ld to %4ld, Block Size: %3ld, Default # of rounds: %2ld\n", cipher_descriptor[x].name,
+            cipher_descriptor[x].ID,
+            cipher_descriptor[x].min_key_length*8,cipher_descriptor[x].max_key_length*8,
+            cipher_descriptor[x].block_length*8, cipher_descriptor[x].default_rounds);
+ }
+
+}
+
+void ecb_tests(void)
+{
+ int x;
+
+ printf("ECB tests\n");
+ for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+     printf(" %12s: ",
+           cipher_descriptor[x].name);
+     if ((errno = cipher_descriptor[x].test()) != CRYPT_OK)
+        printf(" **failed** Reason: %s\n", error_to_string(errno));
+     else 
+        printf("passed\n");
+ }
+}
+
+#ifdef CBC
+void cbc_tests(void)
+{
+ symmetric_CBC cbc;
+ int x, y;
+ unsigned char blk[32], ct[32], key[32], IV[32];
+ const unsigned char test[] = { 0XFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ printf("CBC tests\n");
+ /* ---- CBC ENCODING ---- */
+ /* make up a block and IV */
+ for (x = 0; x < 32; x++) blk[x] = IV[x] = x;
+
+ /* now lets start a cbc session */
+ if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets encode 32 bytes */
+ for (x = 0; x < 4; x++)
+    cbc_encrypt(blk+8*x, ct+8*x, &cbc);
+
+ zeromem(blk, sizeof(blk));
+
+ /* ---- CBC DECODING ---- */
+ /* make up a IV */
+ for (x = 0; x < 32; x++) IV[x] = x;
+
+ /* now lets start a cbc session */
+ if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets decode 32 bytes */
+ for (x = 0; x < 4; x++)
+    cbc_decrypt(ct+8*x, blk+8*x, &cbc);
+
+ /* print output */
+ for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1;
+ printf("  %s\n", y?"failed":"passed");
+
+ /* lets actually check the bytes */
+ memset(IV, 0, 8); IV[0] = 0xFF;              /* IV  = FF 00 00 00 00 00 00 00 */
+ memset(blk, 0, 32); blk[8] = 0xFF;           /* BLK = 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 */
+ cbc_start(find_cipher("memcpy()"), IV, key, 8, 0, &cbc);
+ cbc_encrypt(blk, ct, &cbc);                  /* expect: FF 00 00 00 00 00 00 00 */
+ cbc_encrypt(blk+8, ct+8, &cbc);              /* expect: 00 00 00 00 00 00 00 00 */
+ if (memcmp(ct, test, 16)) {
+    printf("CBC failed logical testing.\n");
+    for (x = 0; x < 16; x++) printf("%02x ", ct[x]);
+    printf("\n");
+ } else {
+    printf("CBC passed logical testing.\n");
+ }
+}
+#else
+void cbc_tests(void) { printf("CBC not compiled in\n"); }
+#endif
+
+#ifdef OFB
+void ofb_tests(void)
+{
+ symmetric_OFB ofb;
+ int x, y;
+ unsigned char blk[32], ct[32], key[32], IV[32];
+
+ printf("OFB tests\n");
+ /* ---- ofb ENCODING ---- */
+ /* make up a block and IV */
+ for (x = 0; x < 32; x++) blk[x] = IV[x] = x;
+
+ /* now lets start a ofb session */
+ if ((errno = ofb_start(find_cipher("blowfish"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets encode 32 bytes */
+ for (x = 0; x < 4; x++)
+    ofb_encrypt(blk+8*x, ct+8*x, 8, &ofb);
+
+ zeromem(blk, sizeof(blk));
+
+ /* ---- ofb DECODING ---- */
+ /* make up a IV */
+ for (x = 0; x < 32; x++) IV[x] = x;
+
+ /* now lets start a ofb session */
+ if ((errno = ofb_start(find_cipher("blowfish"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets decode 32 bytes */
+ for (x = 0; x < 4; x++)
+    ofb_decrypt(ct+8*x, blk+8*x, 8, &ofb);
+
+ /* print output */
+ for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1;
+ printf("  %s\n", y?"failed":"passed");
+}
+#else
+void ofb_tests(void) { printf("OFB not compiled in\n"); }
+#endif
+
+#ifdef CFB
+void cfb_tests(void)
+{
+ symmetric_CFB cfb;
+ int x, y;
+ unsigned char blk[32], ct[32], key[32], IV[32];
+
+ printf("CFB tests\n");
+ /* ---- cfb ENCODING ---- */
+ /* make up a block and IV */
+ for (x = 0; x < 32; x++) blk[x] = IV[x] = x;
+
+ /* now lets start a cfb session */
+ if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets encode 32 bytes */
+ for (x = 0; x < 4; x++)
+    cfb_encrypt(blk+8*x, ct+8*x, 8, &cfb);
+
+ zeromem(blk, sizeof(blk));
+
+ /* ---- cfb DECODING ---- */
+ /* make up ahash_descriptor[prng->yarrow.hash].hashsize IV */
+ for (x = 0; x < 32; x++) IV[x] = x;
+
+ /* now lets start a cfb session */
+ if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets decode 32 bytes */
+ for (x = 0; x < 4; x++)
+    cfb_decrypt(ct+8*x, blk+8*x, 8, &cfb);
+
+ /* print output */
+ for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1;
+ printf("  %s\n", y?"failed":"passed");
+}
+#else
+void cfb_tests(void) { printf("CFB not compiled in\n"); }
+#endif
+
+#ifdef CTR
+void ctr_tests(void)
+{
+ symmetric_CTR ctr;
+ int x, y;
+ unsigned char blk[32], ct[32], key[32], count[32];
+ const unsigned char test[] = { 0xFF, 0, 0, 0, 0, 0, 0, 0,  0, 3, 0, 0, 0, 0, 0, 0 };
+
+ printf("CTR tests\n");
+ /* ---- CTR ENCODING ---- */
+ /* make up a block and IV */
+ for (x = 0; x < 32; x++) blk[x] = count[x] = x;
+
+ /* now lets start a ctr session */
+ if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets encode 32 bytes */
+ for (x = 0; x < 4; x++)
+    ctr_encrypt(blk+8*x, ct+8*x, 8, &ctr);
+
+ zeromem(blk, sizeof(blk));
+
+ /* ---- CTR DECODING ---- */
+ /* make up a IV */
+ for (x = 0; x < 32; x++) count[x] = x;
+
+ /* now lets start a cbc session */
+ if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* now lets decode 32 bytes */
+ for (x = 0; x < 4; x++)
+    ctr_decrypt(ct+8*x, blk+8*x, 8, &ctr);
+
+ /* print output */
+ for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1;
+ printf("  %s\n", y?"failed":"passed");
+
+ /* lets actually check the bytes */
+ memset(count, 0, 8); count[0] = 0xFF;        /* IV  = FF 00 00 00 00 00 00 00 */
+ memset(blk, 0, 32); blk[9] = 2;              /* BLK = 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 */
+ ctr_start(find_cipher("memcpy()"), count, key, 8, 0, &ctr);
+ ctr_encrypt(blk, ct, 8, &ctr);               /* expect: FF 00 00 00 00 00 00 00 */
+ ctr_encrypt(blk+8, ct+8, 8, &ctr);           /* expect: 00 03 00 00 00 00 00 00 */
+ if (memcmp(ct, test, 16)) {
+    printf("CTR failed logical testing.\n");
+    for (x = 0; x < 16; x++) printf("%02x ", ct[x]);
+    printf("\n");
+ } else {
+    printf("CTR passed logical testing.\n");
+ }
+
+}
+#else
+void ctr_tests(void) { printf("CTR not compiled in\n"); }
+#endif
+
+void hash_tests(void)
+{
+ int x;
+ printf("Hash tests\n");
+ for (x = 0; hash_descriptor[x].name != NULL; x++) {
+     printf(" %10s (%2d) ", hash_descriptor[x].name, hash_descriptor[x].ID);
+     if (hash_descriptor[x].test() != CRYPT_OK)
+        printf("**failed** Reason: %s\n", error_to_string(errno));
+     else 
+        printf("passed\n");
+ }
+}
+
+#ifdef MRSA
+void pad_test(void)
+{
+ unsigned char in[100], out[100];
+ unsigned long x, y;
+  
+ /* make a dummy message */
+ for (x = 0; x < 16; x++) in[x] = (unsigned char)x;
+
+ /* pad the message so that random filler is placed before and after it */
+ y = 100;
+ if ((errno = rsa_pad(in, 16, out, &y, find_prng("yarrow"), &prng)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* depad the message to get the original content */
+ memset(in, 0, sizeof(in));
+ x = 100;
+ if ((errno = rsa_depad(out, y, in, &x)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* check outcome */
+ printf("rsa_pad: ");
+ if (x != 16) { printf("Failed.  Wrong size.\n"); return; }
+ for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed.  Expected %02lx and got %02x.\n", x, in[x]); return; }
+ printf("passed.\n");
+}
+
+void rsa_test(void)
+{
+ unsigned char in[4096], out[4096];
+ unsigned long x, y, z, limit;
+ int stat;
+ rsa_key key;
+ clock_t t;
+
+ /* ---- SINGLE ENCRYPT ---- */
+ /* encrypt a short 8 byte string */
+ if ((errno = rsa_make_key(&prng, find_prng("yarrow"), 1024/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+ for (x = 0; x < 8; x++) in[x] = (unsigned char)(x+1);
+ y = sizeof(in);
+ if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* decrypt it */
+ zeromem(in, sizeof(in));
+ x = sizeof(out);
+ if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+
+ /* compare */
+ printf("RSA    : ");
+ for (x = 0; x < 8; x++) if (in[x] != (x+1)) { printf("Failed.  x==%02lx, in[%ld]==%02x\n", x, x, in[x]); }
+ printf("passed.\n");
+
+#ifdef PK_PACKET 
+ /* ---- BLOCK ENCRYPT ---- */
+ /* now lets test rsa_encrypt() */
+ for (x = 0; x < 8; x++) in[x] = (unsigned char)x;
+ x = sizeof(out);
+ if ((errno = rsa_encrypt(in, 8, out, &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+
+ /* test rsa_decrypt() */
+ zeromem(in, sizeof(in));
+ y = sizeof(in);
+ if ((errno = rsa_decrypt(out, x, in, &y, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("rsa_encrypt()/rsa_decrypt(): ");
+ for (y = 0; y < 8; y++) if (in[y] != y) { printf("failed.\n"); return; }
+ printf("Passed.\n");
+
+ /* ---- SIGNATURES ---- */
+ x = sizeof(in);
+ if ((errno = rsa_sign("hello", 5, in, &x, find_hash("md5"), &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ if ((errno = rsa_verify(in, "hello", 5, &stat, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("RSA Signatures: %s, ", (stat==1)?"pass":"fail");
+ if ((errno = rsa_verify(in, "abcde", 5, &stat, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("%s\n", (stat==0)?"pass":"fail");
+
+ /* ---- EXPORT/IMPORT ---- */
+ x = sizeof(out);
+ if ((errno = rsa_export(out, &x, PK_PRIVATE_OPTIMIZED, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("RSA Export takes %lu bytes\n", x);
+ rsa_free(&key);
+ if ((errno = rsa_import(out, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("RSA Import: ");
+ if ((errno = rsa_verify(in, "hello", 5, &stat, &key)) != CRYPT_OK) { 
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("%s, ", (stat==1)?"pass":"fail");
+ if ((errno = rsa_verify(in, "abcde", 5, &stat, &key)) != CRYPT_OK) { 
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("%s\n", (stat==0)?"pass":"fail");
+#endif 
+
+ /* test the rsa_encrypt_key functions */
+ for (x = 0; x < 16; x++) in[x] = x;
+ y = sizeof(out);
+ if ((errno = rsa_encrypt_key(in, 16, out, &y, &prng, find_prng("yarrow"), &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ zeromem(in, sizeof(in));
+ x = sizeof(in);
+ if ((errno = rsa_decrypt_key(out, in, &x, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("RSA en/de crypt key routines: ");
+ if (x != 16) { printf("Failed (length)\n"); return; }
+ for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed (contents)\n"); return; }
+ printf("Passed\n");
+
+ /* test sign_hash functions */
+ for (x = 0; x < 16; x++) in[x] = x;
+ x = sizeof(in);
+ if ((errno = rsa_sign_hash(in, 16, out, &x, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("RSA signed hash: %lu bytes\n", x);
+ if ((errno = rsa_verify_hash(out, in, &stat, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("Verify hash: %s, ", stat?"passed":"failed");
+ in[0] ^= 1;
+ if ((errno = rsa_verify_hash(out, in, &stat, &key)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("%s\n", (!stat)?"passed":"failed");
+ rsa_free(&key);
+
+ /* make a RSA key */
+#ifdef SONY_PS2
+   limit = 1024;
+#else
+   limit = 2048;
+#endif
+
+ for (z = 1024; z <= limit; z += 512) {
+    t = XCLOCK();
+    if ((errno = rsa_make_key(&prng, find_prng("yarrow"), z/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+    t = XCLOCK() - t;
+    printf("Took %.0f ms to make a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z);
+
+    /* time encryption */
+    y = sizeof(in);
+    t = XCLOCK();
+    if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+    t = XCLOCK() - t;
+    printf("Took %.0f ms to encrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z);
+
+    /* time decryption */
+    x = sizeof(out);
+    t = XCLOCK();
+    if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; }
+    t = XCLOCK() - t;
+    printf("Took %.0f ms to decrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z);
+    rsa_free(&key);
+ }
+ 
+
+
+}
+#else
+void pad_test(void) { printf("MRSA not compiled in\n"); }
+void rsa_test(void) { printf("MRSA not compiled in\n"); }
+#endif
+
+#ifdef BASE64
+void base64_test(void)
+{
+   unsigned char buf[2][100];
+   unsigned long x, y;
+
+   printf("Base64 tests\n");
+   zeromem(buf, sizeof(buf));
+   for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x;
+
+   x = 100;
+   if (base64_encode(buf[0], 16, buf[1], &x) != CRYPT_OK) {
+      printf("  error: %s\n", error_to_string(errno));
+      return;
+   }
+   printf("  encoded 16 bytes to %ld bytes...[%s]\n", x, buf[1]);
+   memset(buf[0], 0, 100);
+   y = 100;
+   if (base64_decode(buf[1], x, buf[0], &y) != CRYPT_OK) {
+      printf("  error: %s\n", error_to_string(errno));
+      return;
+   }
+   printf("  decoded %ld bytes to %ld bytes\n", x, y);
+   for (x = 0; x < 16; x++) if (buf[0][x] != x) { 
+      printf(" **failed**\n"); 
+      return; 
+   }
+   printf("  passed\n");
+}
+#else
+void base64_test(void) { printf("Base64 not compiled in\n"); }
+#endif
+
+void time_hash(void)
+{
+    clock_t t1;
+    int x, y;
+    unsigned long z;
+    unsigned char input[4096], out[MAXBLOCKSIZE];
+    printf("Hash Time Trials (4KB blocks):\n");
+    for (x = 0; hash_descriptor[x].name != NULL; x++) {
+        t1 = XCLOCK();
+        z = sizeof(out);
+        y = 0;
+        while (XCLOCK() - t1 < (3 * XCLOCKS_PER_SEC)) {
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z);
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z);
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z);
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); 
+            hash_memory(x, input, 4096, out, &z); y += 16;
+        }
+        t1 = XCLOCK() - t1;
+        printf("%-20s: Hash at %5.2f Mbit/sec\n", hash_descriptor[x].name,
+               ((8.0 * 4096.0) * ((double)y / ((double)t1 / (double)XCLOCKS_PER_SEC))) / 1000000.0);
+    }
+}
+
+void time_ecb(void)
+{
+    clock_t t1, t2;
+    long x, y1, y2;
+    unsigned char pt[32], key[32];
+    symmetric_key skey;
+    void (*func)(const unsigned char *, unsigned char *, symmetric_key *);
+
+    printf("ECB Time Trials for the Symmetric Ciphers:\n");
+    for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+        cipher_descriptor[x].setup(key, cipher_descriptor[x].min_key_length, 0, &skey);
+
+#define DO1   func(pt,pt,&skey);
+#define DO2   DO1 DO1
+#define DO4   DO2 DO2
+#define DO8   DO4 DO4
+#define DO16  DO8 DO8
+#define DO32  DO16 DO16
+#define DO64  DO32 DO32
+#define DO128 DO64 DO64
+#define DO256 DO128 DO128 
+
+        func = cipher_descriptor[x].ecb_encrypt;
+        y1 = 0;
+        t1 = XCLOCK();
+        while (XCLOCK() - t1 < 2*XCLOCKS_PER_SEC) {
+            DO256; y1 += 256;
+        }
+        t1 = XCLOCK() - t1;
+
+        func = cipher_descriptor[x].ecb_decrypt;
+        y2 = 0;
+        t2 = XCLOCK();
+        while (XCLOCK() - t2 < 2*XCLOCKS_PER_SEC) {
+            DO256; y2 += 256;
+        }
+        t2 = XCLOCK() - t2;
+        printf("%-20s: Encrypt at %5.2f Mbit/sec and Decrypt at %5.2f Mbit/sec\n",
+               cipher_descriptor[x].name,
+               ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y1 / ((double)t1 / (double)XCLOCKS_PER_SEC))) / 1000000.0,
+               ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y2 / ((double)t2 / (double)XCLOCKS_PER_SEC))) / 1000000.0);
+
+#undef DO256
+#undef DO128
+#undef DO64
+#undef DO32
+#undef DO16
+#undef DO8
+#undef DO4
+#undef DO2
+#undef DO1
+    }
+}
+
+#ifdef MDH
+void dh_tests(void)
+{
+   unsigned char buf[3][4096];
+   unsigned long x, y, z;
+   int low, high, stat, stat2;
+   dh_key usera, userb;
+   clock_t t1;
+
+/*   if ((errno = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errno)); */
+
+   dh_sizes(&low, &high);
+   printf("DH Keys from %d to %d supported.\n", low*8, high*8);
+
+   /* make up two keys */
+   if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   /* make the shared secret */
+   x = 4096;
+   if ((errno = dh_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   y = 4096;
+   if ((errno = dh_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   if (y != x) { printf("DH Shared keys are not same size.\n"); return; }
+   if (memcmp(buf[0], buf[1], x)) { printf("DH Shared keys not same contents.\n"); return; }
+
+   /* now export userb */
+   y = 4096;
+   if ((errno = dh_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   dh_free(&userb);
+
+   /* import and make the shared secret again */
+   if ((errno = dh_import(buf[1], &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   z = 4096;
+   if ((errno = dh_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("DH routines: ");
+   if (z != x) { printf("failed.  Size don't match?\n"); return; }
+   if (memcmp(buf[0], buf[2], x)) { printf("Failed.  Content didn't match.\n"); return; }
+   printf("Passed\n");
+   dh_free(&usera);
+   dh_free(&userb);
+
+/* time stuff */
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 64, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-512 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 96, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-768 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 128, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-1024 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+#ifndef SONY_PS2
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 160, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-1280 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 192, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-1536 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 224, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-1792 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 256, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-2048 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+
+   t1 = XCLOCK();
+   dh_make_key(&prng, find_prng("yarrow"), 320, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make dh-2560 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   dh_free(&usera);
+#endif   
+   
+#ifdef PK_PACKET
+/* try dh packet stuff */
+   for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x;
+   dh_make_key(&prng, find_prng("yarrow"), 24, &usera);
+
+   x = 4096;
+   if (dh_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"),
+                   find_hash("sha1"), &usera) != CRYPT_OK) {
+      printf("dh_encrypt says %s\n", error_to_string(errno));
+      return;
+   }
+   printf("dh encrypted 16 bytes into %ld bytes!\n", x);
+
+   y = 4096;
+   if ((errno = dh_decrypt(buf[1], x, buf[2], &y, &usera)) != CRYPT_OK) {
+      printf("dh_decrypt says %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("dh packet: ");
+   if (16 != y) { printf("Failed: Sizes different! 16 vs %ld\n", y); return; }
+   if (memcmp(buf[0], buf[2], 16)) { printf("Failed; Content mismatch.\n"); return; }
+   printf("Passed!\n");
+   dh_free(&usera);
+
+/* try dh signatures */
+   dh_make_key(&prng, find_prng("yarrow"), 96, &usera);
+   x = 4096;
+   if ((errno = dh_sign("hello", 5, buf[0], &x, find_hash("sha1"), &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("dh-768 Signature took %ld bytes\n", x);
+
+   if ((errno = dh_verify(buf[0], "hello", 5, &stat, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   if ((errno = dh_verify(buf[0], "hellp", 5, &stat2, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("dh Signatures: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2);
+   dh_free(&usera);
+#endif  
+
+/* test encrypt_key */
+ dh_make_key(&prng, find_prng("yarrow"), 96, &usera);
+ for (x = 0; x < 16; x++) buf[0][x] = x;
+ y = sizeof(buf[1]);
+ if ((errno = dh_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ zeromem(buf[0], sizeof(buf[0]));
+ x = sizeof(buf[0]);
+ if ((errno = dh_decrypt_key(buf[1], buf[0], &x, &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("DH en/de crypt key routines: ");
+ if (x != 16) { printf("Failed (length)\n"); return; }
+ for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); return; }
+ printf("Passed (size %lu)\n", y);
+
+/* test sign_hash */
+   for (x = 0; x < 16; x++) buf[0][x] = x;
+   x = sizeof(buf[1]);
+   if ((errno = dh_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   if (dh_verify_hash(buf[1], buf[0], 16, &stat, &usera)) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   buf[0][0] ^= 1;
+   if (dh_verify_hash(buf[1], buf[0], 16, &stat2, &usera)) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   printf("dh_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2);
+ dh_free(&usera);
+}
+#else
+void dh_tests(void) { printf("MDH not compiled in\n"); }
+#endif
+
+int callback_x = 0;
+void callback(void)
+{ 
+   printf("%c\x08", "-\\|/"[++callback_x & 3]); 
+#ifndef SONY_PS2
+   fflush(stdout);
+#endif
+}
+
+void rng_tests(void)
+{
+   unsigned char buf[16];
+   clock_t t1;
+   int x, y;
+
+   printf("RNG tests\n");
+   t1 = XCLOCK();
+   x = rng_get_bytes(buf, sizeof(buf), &callback);
+   t1 = XCLOCK() - t1;
+   printf("  %f bytes per second...",
+         (double)x / ((double)t1 / (double)XCLOCKS_PER_SEC));
+   printf("read %d bytes.\n  ", x);
+   for (y = 0; y < x; y++)
+       printf("%02x ", buf[y]);
+   printf("\n");
+
+#ifdef YARROW
+   if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, &callback)) != CRYPT_OK) {
+       printf(" starting yarrow error: %s\n", error_to_string(errno));
+       exit(-1);
+   }
+#endif
+}
+
+#ifdef MECC
+void ecc_tests(void)
+{
+   unsigned char buf[4][4096];
+   unsigned long x, y, z;
+   int stat, stat2, low, high;
+   ecc_key usera, userb;
+   clock_t t1;
+
+   if ((errno = ecc_test()) != CRYPT_OK) printf("ecc Error: %s\n", error_to_string(errno));
+
+   ecc_sizes(&low, &high);
+   printf("ecc Keys from %d to %d supported.\n", low*8, high*8);
+
+   /* make up two keys */
+   if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   /* make the shared secret */
+   x = 4096;
+   if ((errno = ecc_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   y = 4096;
+   if ((errno = ecc_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   if (y != x) { printf("ecc Shared keys are not same size.\n"); return; }
+
+   if (memcmp(buf[0], buf[1], x)) { printf("ecc Shared keys not same contents.\n"); return; }
+
+   /* now export userb */
+   y = 4096;
+   if ((errno = ecc_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   ecc_free(&userb);
+   printf("ECC-192 export took %ld bytes\n", y);
+
+   /* import and make the shared secret again */
+   if ((errno = ecc_import(buf[1], &userb)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   z = 4096;
+   if ((errno = ecc_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("ecc routines: ");
+   if (z != x) { printf("failed.  Size don't match?\n"); return; }
+   if (memcmp(buf[0], buf[2], x)) { printf("Failed.  Content didn't match.\n"); return; }
+   printf("Passed\n");
+   ecc_free(&usera);
+   ecc_free(&userb);
+
+/* time stuff */
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 20, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-160 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 24, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-192 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 28, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-224 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+   
+#ifndef SONY_PS2
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 32, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-256 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 48, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-384 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+
+   t1 = XCLOCK();
+   ecc_make_key(&prng, find_prng("yarrow"), 65, &usera);
+   t1 = XCLOCK() - t1;
+   printf("Make ECC-521 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC));
+   ecc_free(&usera);
+#endif   
+
+#ifdef PK_PACKET
+/* try ECC packet stuff */
+   for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x;
+   ecc_make_key(&prng, find_prng("yarrow"), 20, &usera);
+
+   x = 4096;
+   if (ecc_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"),
+                   find_hash("tiger"), &usera) != CRYPT_OK) {
+      printf("ecc_encrypt says %s\n", error_to_string(errno));
+      return;
+   }
+   printf("Ecc encrypted 16 bytes into %ld bytes!\n", x);
+
+   y = 4096;
+   if ((errno = ecc_decrypt(buf[1], x, buf[2], &y, &usera)) != CRYPT_OK) {
+      printf("ecc_decrypt says %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("ECC packet: ");
+   if (16 != y) { printf("Failed: Sizes different! 16 vs %ld\n", y); return; }
+   if (memcmp(buf[0], buf[2], 16)) { printf("Failed; Content mismatch.\n"); return; }
+   printf("Passed!\n");
+   ecc_free(&usera);
+
+/* try ECC signatures */
+   ecc_make_key(&prng, find_prng("yarrow"), 20, &usera);
+   x = 4096;
+   if ((errno = ecc_sign("hello", 5, buf[0], &x, find_hash("sha1"), &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("ECC-160 Signature took %ld bytes\n", x);
+
+   if ((errno = ecc_verify(buf[0], "hello", 5, &stat, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+   if ((errno = ecc_verify(buf[0], "hellp", 5, &stat2, &usera)) != CRYPT_OK) {
+      printf("Error: %s\n", error_to_string(errno));
+      return;
+   }
+
+   printf("ECC Signatures: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2);
+   ecc_free(&usera);
+#endif
+
+/* test encrypt_key */
+ ecc_make_key(&prng, find_prng("yarrow"), 32, &usera);
+ for (x = 0; x < 16; x++) buf[0][x] = x;
+ y = sizeof(buf[1]);
+ if ((errno = ecc_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ zeromem(buf[0], sizeof(buf[0]));
+ x = sizeof(buf[0]);
+ if ((errno = ecc_decrypt_key(buf[1],buf[0], &x, &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+ }
+ printf("ECC en/de crypt key routines: ");
+ if (x != 16) { printf("Failed (length)\n"); return; }
+ for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); return; }
+ printf("Passed (size: %lu)\n", y);
+/* test sign_hash */
+   for (x = 0; x < 16; x++) buf[0][x] = x;
+   x = sizeof(buf[1]);
+   if ((errno = ecc_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   if (ecc_verify_hash(buf[1], buf[0], 16, &stat, &usera)) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   buf[0][0] ^= 1;
+   if (ecc_verify_hash(buf[1], buf[0], 16, &stat2, &usera)) {
+    printf("Error: %s\n", error_to_string(errno));
+    return;
+   }
+   printf("ecc_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2);
+ ecc_free(&usera);
+}
+#else
+void ecc_tests(void) { printf("MECC not compiled in\n"); }
+#endif
+
+#ifdef GF
+void gf_tests(void)
+{
+   gf_int a, b, c, d;
+   int n;
+   unsigned char buf[1024];
+
+   printf("GF tests\n");
+   gf_zero(a);gf_zero(b);gf_zero(c);gf_zero(d);
+
+   /* a == 0x18000000b */
+   a[1] = 1;
+   a[0] = 0x8000000bUL;
+
+   /* b == 0x012345678 */
+   b[0] = 0x012345678UL;
+
+   /* find 1/b mod a */
+   gf_invmod(b,a,c);
+
+   /* find 1/1/b mod a */
+   gf_invmod(c,a,d);
+
+   /* display them */
+   printf("  %08lx %08lx\n", c[0], d[0]);
+
+   /* store as binary string */
+   n = gf_size(a);
+   printf("  a takes %d bytes\n", n);
+   gf_toraw(a, buf);
+   gf_readraw(a, buf, n);
+   printf("  a == %08lx%08lx\n", a[1], a[0]);
+
+   /* primality testing */
+   gf_zero(a);
+   a[0] = 0x169;
+   printf("  GF prime: %s, ", gf_is_prime(a)?"passed":"failed");
+   a[0] = 0x168;
+   printf("  %s\n", gf_is_prime(a)?"failed":"passed");
+
+   /* test sqrt code */
+   gf_zero(a);
+   a[1] = 0x00000001;
+   a[0] = 0x8000000bUL;
+   gf_zero(b);
+   b[0] = 0x12345678UL;
+
+   gf_sqrt(b, a, c);
+   gf_mulmod(c, c, a, b);
+   printf("  (%08lx)^2 = %08lx (mod %08lx%08lx) \n", c[0], b[0], a[1], a[0]);
+}
+#else
+void gf_tests(void) { printf("GF not compiled in\n"); }
+#endif
+
+#ifdef MPI
+void test_prime(void)
+{
+   unsigned char buf[1024];
+   mp_int a;
+   int x;
+  
+   /* make a 1024 bit prime */
+   mp_init(&a);
+   rand_prime(&a, 128, &prng, find_prng("yarrow"));
+
+   /* dump it */
+   mp_todecimal(&a, buf);
+   printf("1024-bit prime:\n");
+   for (x = 0; x < (int)strlen(buf); ) {
+       printf("%c", buf[x]);
+       if (!(++x % 60)) printf("\\ \n");
+   }
+   printf("\n\n");
+
+   mp_clear(&a);
+}
+#else
+void test_prime(void) { printf("MPI not compiled in\n"); }
+#endif
+
+void register_all_algs(void)
+{
+#ifdef BLOWFISH
+   register_cipher(&blowfish_desc);
+#endif
+#ifdef XTEA
+   register_cipher(&xtea_desc);
+#endif
+#ifdef RC5
+   register_cipher(&rc5_desc);
+#endif
+#ifdef RC6
+   register_cipher(&rc6_desc);
+#endif
+#ifdef SAFERP
+   register_cipher(&saferp_desc);
+#endif
+#ifdef SERPENT
+   register_cipher(&serpent_desc);
+#endif
+#ifdef RIJNDAEL
+   register_cipher(&rijndael_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 TWOFISH
+   register_cipher(&twofish_desc);
+#endif
+#ifdef RC2
+   register_cipher(&rc2_desc);
+#endif
+#ifdef CAST5
+   register_cipher(&cast5_desc);
+#endif
+#ifdef DES
+   register_cipher(&des_desc);
+   register_cipher(&des3_desc);
+#endif
+
+   register_cipher(&null_desc);
+
+#ifdef SHA256
+   register_hash(&sha256_desc);
+#endif
+#ifdef TIGER
+   register_hash(&tiger_desc);
+#endif
+#ifdef SHA1
+   register_hash(&sha1_desc);
+#endif
+#ifdef MD5
+   register_hash(&md5_desc);
+#endif
+#ifdef SHA384
+   register_hash(&sha384_desc);
+#endif
+#ifdef SHA512
+   register_hash(&sha512_desc);
+#endif
+#ifdef MD4
+   register_hash(&md4_desc);
+#endif
+#ifdef MD2
+   register_hash(&md2_desc);
+#endif
+
+#ifdef YARROW
+   register_prng(&yarrow_desc);
+#endif
+#ifdef SPRNG
+   register_prng(&sprng_desc);
+#endif
+}
+
+void kr_display(pk_key *kr)
+{
+   static const char *system[] = { "NON-KEY", "RSA", "DH", "ECC" };
+   static const char *type[]   = { "PRIVATE", "PUBLIC", "PRIVATE_OPTIMIZED" };
+
+   while (kr->system != NON_KEY) {
+       printf("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, system[kr->system], type[kr->key_type], kr->name, kr->email, kr->description);
+       kr = kr->next;
+   }
+   printf("\n");
+}
+
+void kr_test_makekeys(pk_key **kr)
+{
+   if ((errno = kr_init(kr)) != CRYPT_OK) {
+      printf("KR init error %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* make a ECC key */
+   printf("KR: Making ECC key...\n");
+   if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), ECC_KEY, 24, "ecckey", "[email protected]", "ecckey one")) != CRYPT_OK) {
+      printf("Make key error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* make a RSA key */
+   printf("KR: Making RSA key...\n");
+   if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), RSA_KEY, 128, "rsakey", "[email protected]", "rsakey one")) != CRYPT_OK) {
+      printf("Make key error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   /* make a DH key */
+   printf("KR: Making DH key...\n");
+   if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), DH_KEY, 128, "dhkey", "[email protected]", "dhkey one")) != CRYPT_OK) {
+      printf("Make key error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+}
+
+void kr_test(void)
+{
+   pk_key *kr, *_kr;
+   unsigned char buf[8192], buf2[8192], buf3[8192];
+   unsigned long len;
+   int i, j, stat;
+#ifndef NO_FILE   
+   FILE *f;
+#endif
+
+   kr_test_makekeys(&kr);
+
+   printf("The original list:\n");
+   kr_display(kr);
+
+   for (i = 0; i < 3; i++) {
+       len = sizeof(buf);
+       if ((errno = kr_export(kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) {
+          printf("Error exporting key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       printf("Exported key was: %lu bytes\n", len);
+       if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) {
+          printf("Error deleting key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       kr_display(kr);
+       if ((errno = kr_import(kr, buf)) != CRYPT_OK) {
+          printf("Error importing key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       kr_display(kr);
+   }         
+
+   for (i = 0; i < 3; i++) {
+       len = sizeof(buf);
+       if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) {
+          printf("Error exporting key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       printf("Exported key was: %lu bytes\n", len);
+       if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) {
+          printf("Error deleting key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       kr_display(kr);
+       if ((errno = kr_import(kr, buf)) != CRYPT_OK) {
+          printf("Error importing key %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       kr_display(kr);
+   }
+
+   if ((errno = kr_clear(&kr)) != CRYPT_OK) {
+      printf("Error clearing ring: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+
+/* TEST output to file */
+#ifndef NO_FILE
+
+   if ((errno = kr_init(&kr)) != CRYPT_OK) {
+      printf("KR init error %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   kr_test_makekeys(&kr);
+
+   /* save to file */
+   f = fopen("ring.dat", "wb");
+   if ((errno = kr_save(kr, f, NULL)) != CRYPT_OK) {
+      printf("kr_save error %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   fclose(f);
+
+   /* delete and load */
+   if ((errno = kr_clear(&kr)) != CRYPT_OK) {
+      printf("clear error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   f = fopen("ring.dat", "rb");
+   if ((errno = kr_load(&kr, f, NULL)) != CRYPT_OK) {
+      printf("kr_load error %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   fclose(f);
+   remove("ring.dat");
+   printf("After load and save...\n");
+   kr_display(kr);
+  
+   if ((errno = kr_clear(&kr)) != CRYPT_OK) {
+      printf("clear error: %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+#endif
+
+/* test the packet encryption/sign stuff */
+   for (i = 0; i < 16; i++) buf[i] = i;
+   kr_test_makekeys(&kr);
+   _kr = kr;
+   for (i = 0; i < 3; i++) {
+       printf("Testing a key with system %d, type %d:\t", _kr->system, _kr->key_type);
+       len = sizeof(buf2);
+       if ((errno = kr_encrypt_key(kr, _kr->ID, buf, 16, buf2, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) {
+          printf("Encrypt error, %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       len = sizeof(buf3);
+       if ((errno = kr_decrypt_key(kr, buf2, buf3, &len)) != CRYPT_OK) {
+          printf("decrypt error, %d, %s\n", i, error_to_string(errno));
+          exit(-1);
+       }
+       if (len != 16 || memcmp(buf3, buf, 16)) {
+          printf("kr_decrypt_key failed, %i, %lu\n", i, len);
+          exit(-1);
+       }
+       printf("kr_encrypt_key passed, ");
+
+       len = sizeof(buf2);
+       if ((errno = kr_sign_hash(kr, _kr->ID, buf, 16, buf2, &len, &prng, find_prng("yarrow"))) != CRYPT_OK) {
+          printf("kr_sign_hash failed, %i, %lu\n", i, len);
+          exit(-1);
+       }
+       printf("kr_sign_hash: ");
+       if ((errno = kr_verify_hash(kr, buf2, buf, 16, &stat)) != CRYPT_OK) {
+          printf("kr_sign_hash failed, %i, %lu\n", i, len);
+          exit(-1);
+       }
+       printf("%s, ", stat?"passed":"failed");
+       buf[15] ^= 1;
+       if ((errno = kr_verify_hash(kr, buf2, buf, 16, &stat)) != CRYPT_OK) {
+          printf("kr_sign_hash failed, %i, %lu\n", i, len);
+          exit(-1);
+       }
+       printf("%s\n", (!stat)?"passed":"failed");
+       buf[15] ^= 1;
+
+       len = sizeof(buf);
+       if ((errno = kr_fingerprint(kr, _kr->ID, find_hash("sha1"), buf, &len)) != CRYPT_OK) {
+          printf("kr_fingerprint failed, %i, %lu\n", i, len);
+          exit(-1);
+       }
+       printf("Fingerprint:  ");
+       for (j = 0; j < 20; j++) {
+           printf("%02x", buf[j]);
+           if (j < 19) printf(":");
+       }
+       printf("\n\n");
+
+       _kr = _kr->next;
+    }
+
+/* Test encrypting/decrypting to a public key */
+/* first dump the other two keys */
+   kr_del(&kr, kr->ID);
+   kr_del(&kr, kr->ID);
+   kr_display(kr);
+
+   /* now export it as public and private */
+   len = sizeof(buf);
+   if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) {
+       printf("Error exporting key %d, %s\n", i, error_to_string(errno));
+       exit(-1);
+   }
+
+   /* check boundaries */
+   memset(buf+len, 0, sizeof(buf)-len);
+
+   len = sizeof(buf2);
+   if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) {
+       printf("Error exporting key  %s\n", error_to_string(errno));
+       exit(-1);
+   }
+
+   /* check boundaries */
+   memset(buf2+len, 0, sizeof(buf2)-len);
+
+   /* delete the key and import the public */
+   kr_clear(&kr);
+   kr_init(&kr);
+   kr_display(kr);
+   if ((errno = kr_import(kr, buf)) != CRYPT_OK) {
+      printf("Error importing key %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   kr_display(kr);
+   
+   /* now encrypt a buffer */
+   for (i = 0; i < 16; i++) buf[i] = i;
+   len = sizeof(buf3);
+   if ((errno = kr_encrypt_key(kr, kr->ID, buf, 16, buf3, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) {
+      printf("Encrypt error, %d, %s\n", i, error_to_string(errno));
+      exit(-1);
+   }
+
+   /* now delete the key and import the private one */
+   kr_clear(&kr);
+   kr_init(&kr);
+   kr_display(kr);
+   if ((errno = kr_import(kr, buf2)) != CRYPT_OK) {
+      printf("Error importing key %s\n", error_to_string(errno));
+      exit(-1);
+   }
+   kr_display(kr);
+
+   /* now decrypt */
+   len = sizeof(buf2);
+   if ((errno = kr_decrypt_key(kr, buf3, buf2, &len)) != CRYPT_OK) {
+      printf("decrypt error, %s\n", error_to_string(errno));
+      exit(-1);
+   }
+
+   printf("KR encrypt to public, decrypt with private: ");
+   if (len == 16 && !memcmp(buf2, buf, 16)) {
+      printf("passed\n"); 
+   } else {
+      printf("failed\n");
+   }
+
+   kr_clear(&kr);
+
+}   
+
+void test_errs(void)
+{
+   #define ERR(x)  printf("%25s => %s\n", #x, error_to_string(x));
+
+   ERR(CRYPT_OK);
+   ERR(CRYPT_ERROR);
+
+   ERR(CRYPT_INVALID_KEYSIZE);
+   ERR(CRYPT_INVALID_ROUNDS);
+   ERR(CRYPT_FAIL_TESTVECTOR);
+
+   ERR(CRYPT_BUFFER_OVERFLOW);
+   ERR(CRYPT_INVALID_PACKET);
+
+   ERR(CRYPT_INVALID_PRNGSIZE);
+   ERR(CRYPT_ERROR_READPRNG);
+
+   ERR(CRYPT_INVALID_CIPHER);
+   ERR(CRYPT_INVALID_HASH);
+   ERR(CRYPT_INVALID_PRNG);
+
+   ERR(CRYPT_MEM);
+
+   ERR(CRYPT_PK_TYPE_MISMATCH);
+   ERR(CRYPT_PK_NOT_PRIVATE);
+
+   ERR(CRYPT_INVALID_ARG);
+
+   ERR(CRYPT_PK_INVALID_TYPE);
+   ERR(CRYPT_PK_INVALID_SYSTEM);
+   ERR(CRYPT_PK_DUP);
+   ERR(CRYPT_PK_NOT_FOUND);
+   ERR(CRYPT_PK_INVALID_SIZE);
+
+   ERR(CRYPT_INVALID_PRIME_SIZE);
+}   
+
+
+
+int main(void)
+{
+#ifdef SONY_PS2
+  TIMER_Init();
+#endif
+
+ register_all_algs();
+
+ if ((errno = yarrow_start(&prng)) != CRYPT_OK) {
+    printf("yarrow_start: %s\n", error_to_string(errno));
+ }
+ if ((errno = yarrow_add_entropy("hello", 5, &prng)) != CRYPT_OK) {
+    printf("yarrow_add_entropy: %s\n", error_to_string(errno));
+ }
+ if ((errno = yarrow_ready(&prng)) != CRYPT_OK) {
+    printf("yarrow_ready: %s\n", error_to_string(errno));
+ }
+
+ printf(crypt_build_settings);
+ test_errs();
+
+
+#ifdef HMAC
+  printf("HMAC: %s\n", hmac_test() == CRYPT_OK ? "passed" : "failed");
+#endif
+
+ store_tests();
+ cipher_tests();
+ hash_tests();
+
+ ecb_tests();
+ cbc_tests();
+ ctr_tests();
+ ofb_tests();
+ cfb_tests();
+
+ rng_tests();
+ //test_prime();
+
+ kr_test();
+ rsa_test();
+ pad_test();
+ ecc_tests();
+ dh_tests();
+
+ gf_tests();
+ base64_test();
+
+ time_ecb();
+ time_hash();
+
+#ifdef SONY_PS2
+  TIMER_Shutdown();
+#endif
+
+ return 0;
+}

+ 7 - 0
demos/timer.c

@@ -0,0 +1,7 @@
+/*
+ * The working version of this file can be found
+ * at the PlayStation(r)2 Developer Network website
+ * under the libtomcrypt project.
+ */
+
+#error Please download the implemented version of this file from the PlayStation(r)2 Developer Network website

+ 51 - 0
demos/timer.h

@@ -0,0 +1,51 @@
+#ifndef __TIMER_H__
+#define __TIMER_H__
+/****************************************************************************
+*
+*   Copyright (c) 2000, Sony Computer Entertainment of America Inc.
+*   All rights reserved
+*   SCEA Confidential
+*
+*    Document: TIMER.H
+*      Author: Ben Wiggins
+*        Date: 7/15/2002   
+*      Header: Timer stuff
+*
+****************************************************************************/
+/*============================================================================
+=    INTERFACE REQUIRED HEADERS
+============================================================================*/
+/*============================================================================
+=    INTERFACE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
+============================================================================*/
+/*============================================================================
+=    INTERFACE STRUCTURES / UTILITY CLASSES
+============================================================================*/
+/*============================================================================
+=    INTERFACE DATA DECLARATIONS
+============================================================================*/
+/*============================================================================
+=    INTERFACE FUNCTION PROTOTYPES
+============================================================================*/
+void TIMER_Init(void);
+void TIMER_Shutdown(void);
+double TIMER_GetTime(void);
+
+#include <time.h>
+#ifdef CLOCKS_PER_SEC
+#undef CLOCKS_PER_SEC
+#endif
+#define CLOCKS_PER_SEC 576000
+extern clock_t TIMER_clock(void);
+
+/*============================================================================
+=    INTERFACE TRAILING HEADERS
+============================================================================*/
+
+/****************************************************************************
+*
+*    END HEADER TIMER.H
+*
+****************************************************************************/
+#endif // __TIMER_H__
+

+ 728 - 0
des.c

@@ -0,0 +1,728 @@
+/* DES code submitted by Dobes Vandermeer */
+#include "mycrypt.h"
+
+#ifdef DES
+
+#define EN0 0 
+#define DE1 1
+
+const struct _cipher_descriptor des_desc =
+{
+    "des",
+    13,
+    8, 8, 8, 16,
+    &des_setup,
+    &des_ecb_encrypt,
+    &des_ecb_decrypt,
+    &des_test,
+    &des_keysize
+};
+
+const struct _cipher_descriptor des3_desc =
+{
+    "3des",
+    14,
+    24, 24, 8, 16,
+    &des3_setup,
+    &des3_ecb_encrypt,
+    &des3_ecb_decrypt,
+    &des3_test,
+    &des3_keysize
+};
+
+static const unsigned char Df_Key[24] =
+{
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+    0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 
+};
+
+static const unsigned short bytebit[8] =
+{
+    0200, 0100, 040, 020, 010, 04, 02, 01 
+};
+
+static const unsigned long bigbyte[24] =
+{
+    0x800000L,  0x400000L,  0x200000L,  0x100000L,
+    0x80000L,   0x40000L,   0x20000L,   0x10000L,
+    0x8000L,    0x4000L,    0x2000L,    0x1000L,
+    0x800L,     0x400L,     0x200L,     0x100L,
+    0x80L,      0x40L,      0x20L,      0x10L,
+    0x8L,       0x4L,       0x2L,       0x1L 
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const unsigned char pc1[56] = {
+    56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  
+     9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 
+    62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
+    13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3 
+};
+
+static const unsigned char totrot[16] = {
+    1,   2,  4,  6,
+    8,  10, 12, 14, 
+    15, 17, 19, 21, 
+    23, 25, 27, 28
+};
+
+static const unsigned char pc2[48] = {
+    13, 16, 10, 23,  0,  4,      2, 27, 14,  5, 20,  9,
+    22, 18, 11,  3, 25,  7,     15,  6, 26, 19, 12,  1,
+    40, 51, 30, 36, 46, 54,     29, 39, 50, 44, 32, 47,
+    43, 48, 38, 55, 33, 52,     45, 41, 49, 35, 28, 31
+};
+
+
+static const unsigned long SP1[64] =
+{
+    0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+    0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+    0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+    0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+    0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+    0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+    0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+    0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+    0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+    0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+    0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+    0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+    0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+    0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+    0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+    0x00010004L, 0x00010400L, 0x00000000L, 0x01010004
+};
+
+static const unsigned long SP2[64] =
+{
+    0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+    0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+    0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+    0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+    0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+    0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+    0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+    0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+    0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+    0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+    0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+    0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+    0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+    0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+    0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+    0x80000000L, 0x80100020L, 0x80108020L, 0x00108000
+};
+
+static const unsigned long SP3[64] =
+{
+    0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+    0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+    0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+    0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+    0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+    0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+    0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+    0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+    0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+    0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+    0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+    0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+    0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+    0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+    0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+    0x00020208L, 0x00000008L, 0x08020008L, 0x00020200
+};
+
+static const unsigned long SP4[64] =
+{
+    0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+    0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+    0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+    0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+    0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+    0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+    0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+    0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+    0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+    0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+    0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+    0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+    0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+    0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+    0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+    0x00000080L, 0x00800000L, 0x00002000L, 0x00802080
+};
+
+static const unsigned long SP5[64] =
+{
+    0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+    0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+    0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+    0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+    0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+    0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+    0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+    0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+    0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+    0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+    0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+    0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+    0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+    0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+    0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+    0x00000000L, 0x40080000L, 0x02080100L, 0x40000100
+};
+
+static const unsigned long SP6[64] =
+{
+    0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+    0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+    0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+    0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+    0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+    0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+    0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+    0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+    0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+    0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+    0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+    0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+    0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+    0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+    0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+    0x20404000L, 0x20000000L, 0x00400010L, 0x20004010
+};
+
+static const unsigned long SP7[64] =
+{
+    0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+    0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+    0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+    0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+    0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+    0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+    0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+    0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+    0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+    0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+    0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+    0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+    0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+    0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+    0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+    0x04000002L, 0x04000800L, 0x00000800L, 0x00200002
+};
+
+static const unsigned long SP8[64] =
+{
+    0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+    0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+    0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+    0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+    0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+    0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+    0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+    0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+    0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+    0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+    0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+    0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+    0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+    0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+    0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+    0x00001040L, 0x00040040L, 0x10000000L, 0x10041000
+};
+
+
+static void cookey(const unsigned long *raw1, unsigned long *keyout);
+
+#ifdef CLEAN_STACK
+void _deskey(const unsigned char *key, short edf, unsigned long *keyout)
+#else
+void deskey(const unsigned char *key, short edf, unsigned long *keyout)
+#endif
+{
+    int i, j, l, m, n;
+    unsigned char pc1m[56], pcr[56];
+    unsigned long kn[32];
+
+    for(j=0; j < 56; j++)
+    {
+        l = pc1[j];
+        m = l & 07;
+        pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+    }
+
+    for(i=0; i < 16; i++)
+    {
+        if(edf == DE1) m = (15 - i) << 1;
+        else m = i << 1;
+        n = m + 1;
+        kn[m] = kn[n] = 0L;
+        for(j=0; j < 28; j++) 
+        {
+            l = j + totrot[i];
+            if(l < 28) pcr[j] = pc1m[l];
+            else pcr[j] = pc1m[l - 28];
+        }
+        for(/*j = 28*/; j < 56; j++)
+        {
+            l = j + totrot[i];
+            if(l < 56) pcr[j] = pc1m[l];
+            else pcr[j] = pc1m[l - 28];
+        }
+        for(j=0; j < 24; j++)
+        {
+            if(pcr[pc2[j]]) kn[m] |= bigbyte[j];
+            if(pcr[pc2[j+24]]) kn[n] |= bigbyte[j];
+        }
+    }
+
+    cookey(kn, keyout);
+}
+
+#ifdef CLEAN_STACK
+void deskey(const unsigned char *key, short edf, unsigned long *keyout)
+{
+   _deskey(key, edf, keyout);
+   burn_stack(sizeof(int)*5 + sizeof(unsigned long)*32 + sizeof(unsigned char)*112);
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _cookey(const unsigned long *raw1, unsigned long *keyout)
+#else
+static void cookey(const unsigned long *raw1, unsigned long *keyout)
+#endif
+{
+    unsigned long *cook;
+    const unsigned long *raw0;
+    unsigned long dough[32];
+    int i;
+
+    cook = dough;
+    for(i=0; i < 16; i++, raw1++)
+    {
+        raw0 = raw1++;
+        *cook    = (*raw0 & 0x00fc0000L) << 6;
+        *cook   |= (*raw0 & 0x00000fc0L) << 10;
+        *cook   |= (*raw1 & 0x00fc0000L) >> 10;
+        *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+        *cook    = (*raw0 & 0x0003f000L) << 12;
+        *cook   |= (*raw0 & 0x0000003fL) << 16;
+        *cook   |= (*raw1 & 0x0003f000L) >> 4;
+        *cook++ |= (*raw1 & 0x0000003fL);
+    }
+
+    memcpy(keyout, dough, sizeof dough);
+}
+
+#ifdef CLEAN_STACK
+static void cookey(const unsigned long *raw1, unsigned long *keyout)
+{
+   _cookey(raw1, keyout);
+   burn_stack(sizeof(unsigned long *) * 2 + sizeof(unsigned long)*32 + sizeof(int));
+}
+#endif
+
+#ifndef CLEAN_STACK
+static void desfunc(unsigned long *block, const unsigned long *keys)
+#else
+static void _desfunc(unsigned long *block, const unsigned long *keys)
+#endif
+{
+    unsigned long fval, work, right, leftt;
+    int round;
+
+    leftt = block[0];
+    right = block[1];
+
+    work = ((leftt >> 4)  ^ right) & 0x0f0f0f0fL;
+    right ^= work;
+    leftt ^= (work << 4);
+
+    work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+    right ^= work;
+    leftt ^= (work << 16);
+
+    work = ((right >> 2)  ^ leftt) & 0x33333333L;
+    leftt ^= work;
+    right ^= (work << 2);
+
+    work = ((right >> 8)  ^ leftt) & 0x00ff00ffL;
+    leftt ^= work;
+    right ^= (work << 8);
+
+    right = ((right << 1) | ((right >> 31) & 1L)) & 0xFFFFFFFFL;
+    work = (leftt ^ right) & 0xaaaaaaaaL;
+    
+    leftt ^= work;
+    right ^= work;
+    leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+    for( round = 0; round < 8; round++)
+    {
+        work  = ((right << 28) | (right >> 4)) ^ *keys++;
+        fval  = SP7[ work        & 0x3fL]
+              | SP5[(work >>  8) & 0x3fL]
+              | SP3[(work >> 16) & 0x3fL]
+              | SP1[(work >> 24) & 0x3fL];
+        work  = right ^ *keys++;
+        fval |= SP8[ work        & 0x3fL]
+              | SP6[(work >>  8) & 0x3fL]
+              | SP4[(work >> 16) & 0x3fL]
+              | SP2[(work >> 24) & 0x3fL];
+        leftt ^= fval;
+
+        work = ((leftt << 28) | (leftt >> 4)) ^ *keys++;
+        fval  = SP7[ work        & 0x3fL]
+              | SP5[(work >>  8) & 0x3fL]
+              | SP3[(work >> 16) & 0x3fL]
+              | SP1[(work >> 24) & 0x3fL];
+        work  = leftt ^ *keys++;
+        fval |= SP8[ work        & 0x3fL]
+              | SP6[(work >>  8) & 0x3fL]
+              | SP4[(work >> 16) & 0x3fL]
+              | SP2[(work >> 24) & 0x3fL];
+        right ^= fval;
+    }
+    right = (right << 31) | (right >> 1);
+    work = (leftt ^ right) & 0xaaaaaaaaL;
+    leftt ^= work;
+    right ^= work;
+    leftt = (leftt << 31) | (leftt >> 1);
+    work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+    right ^= work;
+    leftt ^= (work << 8);
+    // --
+    work = ((leftt >> 2) ^ right) & 0x33333333L;
+    right ^= work;
+    leftt ^= (work << 2);
+    work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+    leftt ^= work;
+    right ^= (work << 16);
+    work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+    leftt ^= work;
+    right ^= (work << 4);
+    
+    block[0] = right;
+    block[1] = leftt;
+}
+
+#ifdef CLEAN_STACK
+static void desfunc(unsigned long *block, const unsigned long *keys)
+{
+   _desfunc(block, keys);
+   burn_stack(sizeof(unsigned long) * 4 + sizeof(int));
+}
+#endif
+
+
+int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    _ARGCHK(key != NULL);
+    _ARGCHK(skey != NULL);
+
+    if (num_rounds != 0 && num_rounds != 16) {
+        return CRYPT_INVALID_ROUNDS;
+    }
+
+    if (keylen != 8) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    deskey(key, EN0, skey->des.ek);
+    deskey(key, DE1, skey->des.dk);
+
+    return CRYPT_OK;
+}
+
+int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    _ARGCHK(key != NULL);
+    _ARGCHK(skey != NULL);
+
+    if( num_rounds != 0 && num_rounds != 16) {
+        return CRYPT_INVALID_ROUNDS;
+    }
+
+    if (keylen != 24) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    deskey(key,    EN0, skey->des3.ek[0]);
+    deskey(key+8,  DE1, skey->des3.ek[1]);
+    deskey(key+16, EN0, skey->des3.ek[2]);
+
+    deskey(key,    DE1, skey->des3.dk[2]);
+    deskey(key+8,  EN0, skey->des3.dk[1]);
+    deskey(key+16, DE1, skey->des3.dk[0]);
+
+    return CRYPT_OK;
+}
+
+void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+{
+    unsigned long work[2];
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+    LOAD32H(work[0], pt+0);
+    LOAD32H(work[1], pt+4);
+    desfunc(work, key->des.ek);
+    STORE32H(work[0],ct+0);
+    STORE32H(work[1],ct+4);
+}
+
+void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+{
+    unsigned long work[2];
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+    LOAD32H(work[0], ct+0);
+    LOAD32H(work[1], ct+4);
+    desfunc(work, key->des.dk);
+    STORE32H(work[0],pt+0);
+    STORE32H(work[1],pt+4);
+}
+
+void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+{
+    unsigned long work[2];
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+    LOAD32H(work[0], pt+0);
+    LOAD32H(work[1], pt+4);
+    desfunc(work, key->des3.ek[0]);
+    desfunc(work, key->des3.ek[1]);
+    desfunc(work, key->des3.ek[2]);
+    STORE32H(work[0],ct+0);
+    STORE32H(work[1],ct+4);
+}
+
+void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+{
+    unsigned long work[2];
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+    LOAD32H(work[0], ct+0);
+    LOAD32H(work[1], ct+4);
+    desfunc(work, key->des3.dk[0]);
+    desfunc(work, key->des3.dk[1]);
+    desfunc(work, key->des3.dk[2]);
+    STORE32H(work[0],pt+0);
+    STORE32H(work[1],pt+4);
+}
+
+int des_test(void)
+{
+    int errno;
+    static const struct des_test_case {
+        int num, mode; // mode 1 = encrypt
+        unsigned char key[8], txt[8], out[8];
+    } cases[] = {
+        { 1, 1,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 } },
+        { 2, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 },
+                    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 3, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 },
+                    { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 4, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA },
+                    { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 5, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F },
+                    { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 6, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 },
+                    { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 7, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF },
+                    { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 8, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F },
+                    { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 9, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 }, 
+                    { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        {10, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A },
+                    { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+
+        { 1, 0,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
+                    { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 2, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 } },
+        { 3, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 } },
+        { 4, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA } },
+        { 5, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F } },
+        { 6, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 } },
+        { 7, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF } },
+        { 8, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F } },
+        { 9, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 } }, 
+        {10, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A } }
+
+        /*** more test cases you could add if you are not convinced (the above test cases aren't really too good):
+
+                key              plaintext        ciphertext
+                0000000000000000 0000000000000000 8CA64DE9C1B123A7
+                FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58
+                3000000000000000 1000000000000001 958E6E627A05557B
+                1111111111111111 1111111111111111 F40379AB9E0EC533
+                0123456789ABCDEF 1111111111111111 17668DFC7292532D
+                1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD
+                0000000000000000 0000000000000000 8CA64DE9C1B123A7
+                FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4
+                7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
+                0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
+                07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
+                3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
+                04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
+                0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
+                0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
+                43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
+                07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
+                04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
+                37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
+                1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
+                584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
+                025816164629B007 480D39006EE762F2 A1F9915541020B56
+                49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
+                4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
+                49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
+                018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
+                1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
+                0101010101010101 0123456789ABCDEF 617B3A0CE8F07100
+                1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606
+                E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7
+                0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451
+                FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE
+                0123456789ABCDEF 0000000000000000 D5D44FF720683D0D
+                FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2
+
+            http://www.ecs.soton.ac.uk/~prw99r/ez438/vectors.txt
+        ***/
+    };
+    int i, failed=0;
+    unsigned char out[8];
+    symmetric_key des;
+
+    for(i=0; i < (int)(sizeof(cases)/sizeof(cases[0])); i++)
+    {
+        if ((errno = des_setup(cases[i].key, 8, 0, &des)) != CRYPT_OK) {
+           return errno;
+        }
+        if (cases[i].mode) { 
+           des_ecb_encrypt(cases[i].txt, out, &des);
+        } else {
+           des_ecb_decrypt(cases[i].txt, out, &des);
+        }
+
+        if (memcmp(cases[i].out, out, sizeof out) != 0) {
+#if 0
+            int j;
+            printf("DES test #%d failed!\n", cases[i].num);
+
+            printf(  "got:    "); 
+            for (j=0; j < (int)sizeof out; j++) {
+                printf("%02x ", out[j] & 0xff);
+            }
+            printf("\nwanted: ");
+            for(j=0; j < (int)sizeof out; j++) {
+                printf("%02x ", cases[i].out[j] & 0xff);
+            }
+            printf("\n");
+#endif
+
+            failed++;
+        }
+    }
+
+    if(failed > 0) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    return CRYPT_OK;
+}
+
+int des3_test(void)
+{
+   unsigned char key[24], pt[8], ct[8], tmp[8];
+   symmetric_key skey;
+   int x, errno;
+
+   if ((errno = des_test()) != CRYPT_OK) {
+      return errno;
+   }
+
+   for (x = 0; x < 8; x++) {
+       pt[x] = x;
+   }
+   
+   for (x = 0; x < 24; x++) {
+       key[x] = x;
+   }
+
+   if ((errno = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+   
+   des3_ecb_encrypt(pt, ct, &skey);
+   des3_ecb_decrypt(ct, tmp, &skey);
+   
+   if (memcmp(pt, tmp, 8)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   
+   return CRYPT_OK;
+}
+
+int des_keysize(int *desired_keysize)
+{
+    _ARGCHK(desired_keysize != NULL);
+    if(*desired_keysize < 8) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+    *desired_keysize = 8;
+    return CRYPT_OK;
+}
+
+int des3_keysize(int *desired_keysize)
+{
+    _ARGCHK(desired_keysize != NULL);
+    if(*desired_keysize < 24) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+    *desired_keysize = 24;
+    return CRYPT_OK;
+}
+
+#endif
+

+ 489 - 0
dh.c

@@ -0,0 +1,489 @@
+#include "mycrypt.h"
+
+#ifdef MDH
+
+static const struct {
+    int size;
+    char *name, *base, *prime;
+} sets[] = {
+#ifdef DH512
+{ 
+    64,
+   "DH-512",
+   "3",
+   "1793360119486011337223707056216512835002732007217684422667328794587337075124"
+   "5439587792371960615073855669274087805055507977323024886880985062002853331424"
+   "203"
+},
+#endif
+#ifdef DH768
+{
+   96,
+   "DH-768",
+   "2",
+   "2893527720709661239493896562339544088620375736490408468011883030469939904368"
+   "0860923364582982212457078989335831907131881773994018526277492109945959747917"
+   "8279025394653904396221302707492255957231214118178743427870878320796645901947"
+   "9487"
+},
+#endif
+#ifdef DH1024
+{
+   128,
+   "DH-1024",
+   "2",
+   "3477431594398766260792527967974222231775354473882066076071816639030459075912"
+   "0194047822362172211817327089848758298713770865641434468581617942085516098634"
+   "0457973820182883508387588163122354089264395604796675278966117567294812714812"
+   "7968205965648764507160662831267200108590414847865290564578963676831229604111"
+   "36319"
+},
+#endif
+#ifdef DH1280
+{
+   160,
+   "DH-1280",
+   "2",
+   "2618298020488323341377089635550383393554460131909411928885489146533597039863"
+   "5379029297773089246854323581071445272213255646852180580463169755159411503866"
+   "4190218001872082125570169842848154404911652982668791288605239288293106162305"
+   "7236093554796242806887062958692596037823904832542385180840218330924392268465"
+   "0197244314233248991982159235832322194332167923655574170280697353556560854901"
+   "280047"
+},
+#endif
+#ifdef DH1536
+{
+   192,
+   "DH-1536",
+   "3",
+   "2992593690703251306835100868059076484222548092264611010748654597096560864537"
+   "1704684310938824733433085888971827086341295918925237859522548192211945291282"
+   "1170570153374563548621496076860061698150233114892317627457427359445435608693"
+   "5625000902194809114890745455404045166957722404567939575618007347432055137282"
+   "3291711752537781447636541738638119983678441628437171377508654097130147131310"
+   "9209393805685590941710151477648542896503595482724205166251069428524927527085"
+   "2602467"
+},
+#endif
+#ifdef DH1792
+{
+   224,
+   "DH-1792",
+   "2",
+   "3210090394251532205679207425273650879078185529033544241951292722086520015900"
+   "0402371844205168176419829949232601235193754977706171541009393172204470047690"
+   "6659627844880912479392592056697278305733615369406596661203184035142652643118"
+   "1379603333858737848321053048184938839622944591194935387992479717305577175500"
+   "2554620614907177847128950276247571809502831255425929468853285490357704941968"
+   "3407102520889651917659577334897408316217748346860775479727332331727022096550"
+   "7718799868459391361770854814013613619048768630587629568449528005570971478547"
+   "34960319"
+},
+#endif
+#ifdef DH2048
+{
+   256,
+   "DH-2048",
+   "2",
+   "4726642895635639316469736509812041897640060270607231273592407174543853221823"
+   "7979333351774907308168340693326687317443721193266215155735814510792148768576"
+   "4984911991227443513994894535335532038333186916782632419417062569961974604240"
+   "2901241901263467186228353234265630967717360250949841797609150915436003989316"
+   "5037637034737020327399910409885798185771003505320583967737293415979917317338"
+   "9858373857347474783642420203804168920566508414708692945275435973492502995396"
+   "8243060517332102902655554683247304860032703684578197028928889831788842751736"
+   "4945316709081173840186150794397479045034008257793436817683392375274635794835"
+   "245695887"
+},
+#endif
+#ifdef DH2560
+{
+   320,
+   "DH-2560",
+   "3",
+   "4364638085059577685748948703943497396233464406019459611612544400721432981520"
+   "4010567649104824811014627875285783993051576616744140702150122992472133564455"
+   "7342265864606569000117714935185566842453630868849121480179691838399545644365"
+   "5711067577313173717585579907818806913366955847993133136872874688941488237617"
+   "8558298254958618375680644901754262226787427510387748147553499120184991222267"
+   "0102069951687572917937634467778042874315463238062009202992087620963771759666"
+   "4482665328580794026699200252242206134194410697184828373996126449788399252071"
+   "0987084027819404215874884544513172913711709852902888677006373648742061314404"
+   "5836803985635654192482395882603511950547826439092832800532152534003936926017"
+   "6124466061356551464456206233957889787267447285030586700468858762515271223502"
+   "75750995227"
+},
+#endif
+#ifdef DH3072
+{
+   384,
+   "DH-3072",
+   "2",
+   "1142416747335183639807830604262436227795642944052113706188970261176634876069"
+   "2206243140413411077394583180726863277012016602279290144126785129569474909173"
+   "5847898223419867427192303319460727303195559844849117167970588759054009995043"
+   "0587724584911968750902323279027363746682105257685923245298206183100977078603"
+   "1785669030271542286603956118755585683996118896215213488875253101894663403069"
+   "6777459483058938495054342017637452328957807119724320113448575216910178963168"
+   "6140320644942133224365885545343578400651720289418164056243357539082138421096"
+   "0117518650374602256601091379644034244332285065935413233557998331562749140202"
+   "9658442193362989700115138825649355387042894469683222814519074873620465114612"
+   "2132979989735099337056069750580968643878203623537213701573130477907243026098"
+   "6460269894522159103008260495503005267165927542949439526272736586626709581721"
+   "0321895327263896436255906801057848442461527026701693042037830722750891947548"
+   "89511973916207"
+},
+#endif
+#ifdef DH4096
+{
+   512,
+   "DH-4096", 
+   "3",
+   "1214855636816562637502584060163403830270705000634713483015101384881871978446"
+   "8012247985361554068958233050354675916325310675478909486951171720769542207270"
+   "7568804875102242119871203284889005635784597424656074834791863005085393369779"
+   "2254955890439720297560693579400297062396904306270145886830719309296352765295"
+   "7121830407731464190228751653827780070401099576097395898755908857011261979060"
+   "6362013395489321661267883850754077713843779770560245371955901763398648664952"
+   "3611975865005712371194067612263330335590526176087004421363598470302731349138"
+   "7732059014477046821815179040647356365184624522427916765417252923789255682968"
+   "5801015185232631677751193503753101741391050692192245066693320227848902452126"
+   "3798482237150056835746454842662048692127173834433089016107854491097456725016"
+   "3277096631997382384421648431471327891537255132571679155551620949708535844479"
+   "9312548860769600816980737473671129700747381225627224548940589847029717873802"
+   "9484459690836250560495461579533254473316340608217876781986188705928270735695"
+   "7528308255279638383554197625162460286802809880204019145518254873499903069763"
+   "0409310938445143881325121105159739212749146489879740678917545306796007200859"
+   "0614886532333015881171367104445044718144312416815712216611576221546455968770"
+   "801413440778423979"
+},
+#endif
+{   
+   0,
+   NULL,
+   NULL,
+   NULL
+}
+};
+
+static int is_valid_idx(int n)
+{
+   int x;
+
+   for (x = 0; sets[x].size; x++);
+   if ((n < 0) || (n >= x)) {
+      return 0;
+   }
+   return 1;
+}
+
+int dh_test(void)
+{
+    mp_int p, g, tmp;
+    int x, res, primality;
+
+    if (mp_init_multi(&p, &g, &tmp, NULL) != MP_OKAY)                 { goto error; }
+
+    for (x = 0; sets[x].size; x++) {
+#if 0
+        printf("dh_test():testing size %d-bits\n", sets[x].size * 8);
+#endif
+        /* see if g^((p-1)/2) == 1 mod p. */
+        if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY)           { goto error; }
+        if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY)          { goto error; }
+
+        /* ensure p is prime */
+        if ((res = is_prime(&p, &primality)) != CRYPT_OK)             { goto done; }
+        if (primality == 0) { 
+           res = CRYPT_FAIL_TESTVECTOR;
+           goto done;
+        }
+
+        if (mp_sub_d(&p, 1, &tmp) != MP_OKAY)                         { goto error; }
+        if (mp_div_2(&tmp, &tmp) != MP_OKAY)                          { goto error; }
+
+        /* ensure (p-1)/2 is prime */
+        if ((res = is_prime(&tmp, &primality)) != CRYPT_OK)           { goto done; }
+        if (primality == 0) {
+           res = CRYPT_FAIL_TESTVECTOR;
+           goto done;
+        }
+
+        /* now see if g^((p-1)/2) mod p is in fact 1 */
+        if (mp_exptmod(&g, &tmp, &p, &tmp) != MP_OKAY)                { goto error; }
+        if (mp_cmp_d(&tmp, 1)) {
+           res = CRYPT_FAIL_TESTVECTOR;
+           goto done;
+        }
+    }
+    res = CRYPT_OK;
+    goto done;
+error:
+    res = CRYPT_MEM;
+done:
+    mp_clear_multi(&tmp, &g, &p, NULL);
+    return res;
+}
+
+void dh_sizes(int *low, int *high)
+{
+   int x;
+   _ARGCHK(low != NULL);
+   _ARGCHK(high != NULL);
+   *low  = INT_MAX;
+   *high = 0;
+   for (x = 0; sets[x].size; x++) {
+       if (*low > sets[x].size)  *low  = sets[x].size;
+       if (*high < sets[x].size) *high = sets[x].size;
+   }
+}
+
+int dh_get_size(dh_key *key)
+{
+    _ARGCHK(key != NULL);
+    if (is_valid_idx(key->idx)) 
+        return sets[key->idx].size;
+    else
+        return INT_MAX; /* large value that would cause dh_make_key() to fail */
+}
+  
+int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
+{
+   unsigned char buf[768];
+   unsigned long x;
+   mp_int p, g;
+   int res, errno;
+
+   _ARGCHK(key  != NULL);
+
+   /* good prng? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* find key size */
+   for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++);
+#ifdef FAST_PK
+   keysize = MIN(sets[x].size, 32);
+#else  
+   keysize = sets[x].size;
+#endif
+
+   if (sets[x].size == 0) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   key->idx = x;
+
+   /* make up random string */
+   buf[0] = 0;
+   if (prng_descriptor[wprng].read(buf+1, keysize, prng) != (unsigned long)keysize) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   /* init parameters */
+   if (mp_init_multi(&g, &p, &key->x, &key->y, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+   if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY)             { goto error2; }
+   if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY)            { goto error2; }
+
+   /* load the x value */
+   mp_read_raw(&key->x, buf, keysize+1);
+   if (mp_exptmod(&g, &key->x, &p, &key->y) != MP_OKAY)            { goto error2; }
+   key->type = PK_PRIVATE;
+
+   /* free up ram */
+   res = CRYPT_OK;
+   goto done2;
+error2:
+   res = CRYPT_MEM;
+   mp_clear_multi(&key->x, &key->y, NULL);
+done2:
+   mp_clear_multi(&p, &g, NULL);
+   zeromem(buf, sizeof(buf));
+   return res;
+}
+
+void dh_free(dh_key *key)
+{
+   _ARGCHK(key != NULL);
+   mp_clear_multi(&key->x, &key->y, NULL);
+}
+
+#define OUTPUT_BIGNUM(num, buf2, y, z)         \
+{                                              \
+      z = mp_raw_size(num);                    \
+      STORE32L(z, buf2+y);                     \
+      y += 4;                                  \
+      mp_toraw(num, buf2+y);                   \
+      y += z;                                  \
+}
+
+
+#define INPUT_BIGNUM(num, in, x, y)                              \
+{                                                                \
+     /* load value */                                            \
+     LOAD32L(x, in+y);                                           \
+     y += 4;                                                     \
+                                                                 \
+     /* sanity check... */                                       \
+     if (x > 1024) {                                             \
+        errno = CRYPT_ERROR;                                     \
+        goto error;                                              \
+     }                                                           \
+                                                                 \
+     /* load it */                                               \
+     if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\
+        return CRYPT_MEM;                                        \
+        goto error;                                              \
+     }                                                           \
+     y += x;                                                     \
+}
+
+
+int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
+{
+   unsigned char buf2[1536];
+   unsigned long y, z;
+
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* header */
+   y = PACKET_SIZE;
+
+   /* header */
+   buf2[y++] = type;
+   buf2[y++] = key->idx;
+
+   /* export y */
+   OUTPUT_BIGNUM(&key->y, buf2, y, z);
+
+   if (type == PK_PRIVATE) { 
+      /* export x */
+      OUTPUT_BIGNUM(&key->x, buf2, y, z);
+   }
+   
+   /* check for overflow */
+   if (*outlen < y) {
+      #ifdef CLEAN_STACK
+         zeromem(buf2, sizeof(buf2));
+      #endif
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store header */
+   packet_store_header(buf2, PACKET_SECT_DH, PACKET_SUB_KEY, y);
+
+   /* output it */
+   *outlen = y;
+   memcpy(out, buf2, y);
+
+   /* clear mem */
+   zeromem(buf2, sizeof(buf2));
+   return CRYPT_OK;
+}
+
+int dh_import(const unsigned char *in, dh_key *key)
+{
+   long x, y;
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(key != NULL);
+
+   /* check type byte */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* init */
+   if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   y = PACKET_SIZE;
+   key->type = in[y++];
+   key->idx  = in[y++];
+
+   /* type check both values */
+   if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE))  {
+      errno = CRYPT_PK_TYPE_MISMATCH;
+      goto error;
+   }
+
+   /* is the key idx valid? */
+   if (!is_valid_idx(key->idx)) {
+      errno = CRYPT_PK_TYPE_MISMATCH;
+      goto error;
+   }
+
+   /* load public value g^x mod p*/
+   INPUT_BIGNUM(&key->y, in, x, y);
+
+   if (key->type == PK_PRIVATE) {
+      INPUT_BIGNUM(&key->x, in, x, y);
+   }
+   return CRYPT_OK;
+error:
+   mp_clear_multi(&key->y, &key->x, NULL);
+   return errno;
+}
+
+int dh_shared_secret(dh_key *private_key, dh_key *public_key, 
+                     unsigned char *out, unsigned long *outlen)
+{
+   mp_int tmp, p;
+   unsigned long x;
+   int res;
+
+   _ARGCHK(private_key != NULL);
+   _ARGCHK(public_key  != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* types valid? */
+   if (private_key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* same idx? */
+   if (private_key->idx != public_key->idx) {
+      return CRYPT_PK_TYPE_MISMATCH;
+   }
+
+   /* compute y^x mod p */
+   if (mp_init_multi(&tmp, &p, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   if (mp_read_radix(&p, sets[private_key->idx].prime, 10) != MP_OKAY)     { goto error; }
+   if (mp_exptmod(&public_key->y, &private_key->x, &p, &tmp) != MP_OKAY)   { goto error; }
+
+   /* enough space for output? */
+   x = mp_raw_size(&tmp);
+   if (*outlen < x) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+   mp_toraw(&tmp, out);
+   *outlen = x;
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&p, &tmp, NULL);
+   return res;
+}
+
+#include "dh_sys.c"
+
+#endif
+

+ 774 - 0
dh_sys.c

@@ -0,0 +1,774 @@
+#ifdef PK_PACKET
+
+int dh_encrypt(const unsigned char *in,  unsigned long len, 
+                     unsigned char *out, unsigned long *outlen,
+                     prng_state *prng, int wprng, int cipher, int hash, 
+                     dh_key *key)
+{
+    unsigned char pub_expt[1536], dh_shared[1536], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE];
+    dh_key pubkey;
+    unsigned long x, y, z, hashsize, blocksize, pubkeysize;
+    int keysize, errno;
+    symmetric_CTR ctr;
+
+    _ARGCHK(in != NULL);
+    _ARGCHK(out != NULL);
+    _ARGCHK(outlen != NULL);
+    _ARGCHK(key != NULL);
+
+    /* check that wprng/cipher/hash are not invalid */
+    if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* make a random key and export the public copy */
+    if ((errno = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) {
+       return errno;
+    }
+
+    pubkeysize = sizeof(pub_expt);
+    if ((errno = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+       dh_free(&pubkey);
+       return errno;
+    }
+    
+    /* now check if the out buffer is big enough */
+    if (*outlen < (10 + PACKET_SIZE + pubkeysize + cipher_descriptor[cipher].block_length + len)) {
+       dh_free(&pubkey);
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* make random key */
+    blocksize = cipher_descriptor[cipher].block_length;
+    hashsize  = hash_descriptor[hash].hashsize;
+    keysize = hashsize;
+    if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) {
+       dh_free(&pubkey);
+       return errno;
+    }
+
+    x = sizeof(dh_shared);
+    if ((errno = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) {
+       dh_free(&pubkey);
+       return errno;
+    }
+    dh_free(&pubkey);
+
+    z = sizeof(skey);
+    if ((errno = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* make up IV */
+    if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != 
+        cipher_descriptor[cipher].block_length) {
+       return CRYPT_ERROR_READPRNG;
+    }
+
+    /* setup CTR mode */
+    if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* output header */
+    y = PACKET_SIZE;
+ 
+    /* size of cipher name and the name itself */
+    out[y++] = cipher_descriptor[cipher].ID;
+
+    /* size of hash name and the name itself */
+    out[y++] = hash_descriptor[hash].ID;
+
+    /* length of DH pubkey and the key itself */
+    STORE32L(pubkeysize, out+y);
+    y += 4;
+    for (x = 0; x < pubkeysize; x++, y++) {
+        out[y] = pub_expt[x];
+    }
+
+    /* cipher IV */
+    for (x = 0; x < blocksize; x++, y++) {
+        out[y] = IV[x];
+    }
+
+    /* length of ciphertext */
+    STORE32L(len, out+y);
+    y += 4;
+
+    /* encrypt the message */
+    if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) {
+       return errno;
+    }
+    y += len;
+
+    /* store header */
+    packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED, y);
+
+#ifdef CLEAN_STACK
+    /* clean up */
+    zeromem(pub_expt, sizeof(pub_expt));
+    zeromem(dh_shared, sizeof(dh_shared));
+    zeromem(skey, sizeof(skey));
+    zeromem(IV, sizeof(IV));
+    zeromem(&ctr, sizeof(ctr));
+#endif
+    *outlen = y;
+    return CRYPT_OK;
+}
+
+int dh_decrypt(const unsigned char *in,  unsigned long len, 
+                     unsigned char *out, unsigned long *outlen, 
+                     dh_key *key)
+{
+   unsigned char shared_secret[1536], skey[MAXBLOCKSIZE];
+   unsigned long x, y, z, res, hashsize, blocksize;
+   int hash, cipher, keysize, errno;
+   dh_key pubkey;
+   symmetric_CTR ctr;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* is header correct? */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* now lets get the cipher name */
+   y = PACKET_SIZE;
+   cipher = find_cipher_id(in[y++]);
+   if (cipher == -1) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* now lets get the hash name */
+   hash = find_hash_id(in[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* common values */
+   blocksize = cipher_descriptor[cipher].block_length;
+   hashsize  = hash_descriptor[hash].hashsize;
+   keysize = hashsize;
+   if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get public key */
+   LOAD32L(x, in+y);
+   y += 4;
+   if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* make shared key */
+   x = sizeof(shared_secret);
+   if ((errno = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) {
+      dh_free(&pubkey);
+      return errno;
+   }
+   dh_free(&pubkey);
+
+   z = sizeof(skey);
+   if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* setup CTR mode */
+   if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+
+   /* skip over the IV */
+   y += blocksize;
+
+   /* get length */
+   LOAD32L(len,in+y);
+   y += 4;
+
+   /* buffer overflow? */
+   if (len > *outlen) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+
+   /* decrypt message */
+   if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+   *outlen = len;
+   
+   res = CRYPT_OK;
+done:
+#ifdef CLEAN_STACK
+   zeromem(shared_secret, sizeof(shared_secret));
+   zeromem(skey, sizeof(skey));
+   zeromem(&ctr, sizeof(ctr));
+#endif
+   return res;
+}
+
+int dh_sign(const unsigned char *in,  unsigned long inlen,
+                  unsigned char *out, unsigned long *outlen,
+                  int hash, prng_state *prng, int wprng,
+                  dh_key *key)
+{
+   mp_int a, b, k, m, g, p, p1, tmp;
+   unsigned char buf[1536], md[MAXBLOCKSIZE];
+   unsigned long x, y, z;
+   int res, errno;
+
+    _ARGCHK(in != NULL);
+    _ARGCHK(out != NULL);
+    _ARGCHK(outlen != NULL);
+    _ARGCHK(key != NULL);
+
+   /* check parameters */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* hash the message */
+   z = sizeof(md) - 1;
+   md[0] = 0;
+   if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* make up a random value k,
+    * since the order of the group is prime
+    * we need not check if gcd(k, r) is 1 
+    */
+   buf[0] = 0;
+   if (prng_descriptor[wprng].read(buf+1, sets[key->idx].size-1, prng) != (unsigned long)(sets[key->idx].size-1)) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   /* init bignums */
+   if (mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* load k and m */
+   if (mp_read_raw(&m, md,  1+hash_descriptor[hash].hashsize) != MP_OKAY)     { goto error; }
+   if (mp_read_raw(&k, buf, sets[key->idx].size) != MP_OKAY)                  { goto error; }
+
+   /* load g, p and p1 */
+   if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY)                 { goto error; }
+   if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY)                { goto error; }
+   if (mp_sub_d(&p, 1, &p1) != MP_OKAY)                         { goto error; } /* p1 = p-1 */
+   if (mp_div_2(&p1, &p1) != MP_OKAY)                           { goto error; } /* p1 = (p-1)/2 */
+
+   /* now get a = g^k mod p */
+   if (mp_exptmod(&g, &k, &p, &a) != MP_OKAY)                   { goto error; } /* a = g^k mod p */
+
+   /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */
+   if (mp_invmod(&k, &p1, &k) != MP_OKAY)                       { goto error; } /* k = 1/k mod p1 */
+   if (mp_mulmod(&a, &key->x, &p1, &tmp) != MP_OKAY)            { goto error; } /* tmp = xa */
+   if (mp_submod(&m, &tmp, &p1, &tmp) != MP_OKAY)               { goto error; } /* tmp = M - xa */
+   if (mp_mulmod(&k, &tmp, &p1, &b) != MP_OKAY)                 { goto error; } /* b = (M - xa)/k */
+
+   /* store header  */
+   y = PACKET_SIZE;
+
+   /* store length and name of hash */
+   buf[y++] = hash_descriptor[hash].ID;                         /* store hash ID */
+ 
+   /* now store them both (a,b) */
+   x = mp_raw_size(&a);                                         /* get raw size of a */
+   STORE32L(x, buf+y);  y += 4;                                 /* store size of a */
+   mp_toraw(&a, buf+y); y += x;                                 /* store a itself */
+
+   x = mp_raw_size(&b);                                         /* get raw size of b */
+   STORE32L(x, buf+y);  y += 4;                                 /* store size of b */
+   mp_toraw(&b, buf+y); y += x;                                 /* store b itself */
+
+   /* check if size too big */
+   if (*outlen < y) { goto error; }
+
+   /* store header */
+   packet_store_header(buf, PACKET_SECT_DH, PACKET_SUB_SIGNED, y);
+
+   /* store it */
+   memcpy(out, buf, y);
+   *outlen = y;
+
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+   zeromem(buf, sizeof(buf));
+#endif
+
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL);
+   return res;
+}
+
+int dh_verify(const unsigned char *sig, const unsigned char *msg, 
+                    unsigned long inlen, int *stat, 
+                    dh_key *key)
+{
+   mp_int a, b, p, g, m, tmp;
+   unsigned char md[MAXBLOCKSIZE];
+   unsigned long x, y, z;
+   int hash, res, errno;
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(msg != NULL);
+   _ARGCHK(stat != NULL);
+   _ARGCHK(key != NULL);
+
+   /* default to invalid */
+   *stat = 0;
+
+   /* header ok? */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get hash out of packet */
+   y = PACKET_SIZE;
+   hash = find_hash_id(sig[y++]);
+
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* hash the message */
+   md[0] = 0;
+   z = sizeof(md) - 1;
+   if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* init all bignums */
+   if (mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* load a and b */
+   LOAD32L(x, sig+y);
+   y += 4;
+   if (mp_read_raw(&a, (unsigned char *)sig+y, x) != MP_OKAY)        { goto error; }
+   y += x;
+
+   LOAD32L(x, sig+y);
+   y += 4;
+   if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY)        { goto error; }
+   y += x;
+
+   /* load p and g */
+   if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY)       { goto error; }
+   if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY)        { goto error; }
+
+   /* load m */
+   if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY) { goto error; }
+
+   /* find g^m mod p */
+   if (mp_exptmod(&g, &m, &p, &m) != MP_OKAY)                        { goto error; } /* m = g^m mod p */
+
+   /* find y^a * a^b */
+   if (mp_exptmod(&key->y, &a, &p, &tmp) != MP_OKAY)                 { goto error; } /* tmp = y^a mod p */
+   if (mp_exptmod(&a, &b, &p, &a) != MP_OKAY)                        { goto error; } /* a = a^b mod p */
+   if (mp_mulmod(&a, &tmp, &p, &a) != MP_OKAY)                       { goto error; } /* a = y^a * a^b mod p */
+
+   /* y^a * a^b == g^m ??? */
+   if (mp_cmp(&a, &m) == 0) {
+      *stat = 1;
+   }
+
+   /* clean up */
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL);
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+#endif
+   return res;
+}
+
+#endif
+
+int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                         unsigned char *out,  unsigned long *len,
+                         prng_state *prng, int wprng, int hash,
+                         dh_key *key)
+{
+    unsigned char pub_expt[1536], dh_shared[1536], skey[MAXBLOCKSIZE];
+    dh_key pubkey;
+    unsigned long x, y, z, hashsize, pubkeysize;
+    int errno;
+
+    _ARGCHK(inkey != NULL);
+    _ARGCHK(out != NULL);
+    _ARGCHK(len != NULL);
+    _ARGCHK(key != NULL);
+
+    /* check that wprng/hash are not invalid */
+    if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if (keylen > hash_descriptor[hash].hashsize)  {
+        return CRYPT_INVALID_ARG;
+    }
+
+    /* make a random key and export the public copy */
+    if ((errno = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) {
+       return errno;
+    }
+
+    pubkeysize = sizeof(pub_expt);
+    if ((errno = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+       dh_free(&pubkey);
+       return errno;
+    }
+
+    /* now check if the out buffer is big enough */
+    if (*len < (9 + PACKET_SIZE + pubkeysize + keylen)) {
+       dh_free(&pubkey);
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* make random key */
+    hashsize  = hash_descriptor[hash].hashsize;
+
+    x = sizeof(dh_shared);
+    if ((errno = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) {
+       dh_free(&pubkey);
+       return errno;
+    }
+    dh_free(&pubkey);
+
+    z = sizeof(skey);
+    if ((errno = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* output header */
+    y = PACKET_SIZE;
+
+    /* size of hash name and the name itself */
+    out[y++] = hash_descriptor[hash].ID;
+
+    /* length of DH pubkey and the key itself */
+    STORE32L(pubkeysize, out+y);
+    y += 4;
+    for (x = 0; x < pubkeysize; x++, y++) {
+        out[y] = pub_expt[x];
+    }
+
+    /* Store the encrypted key */
+    STORE32L(keylen, out+y);
+    y += 4;
+
+    for (x = 0; x < keylen; x++, y++) {
+      out[y] = skey[x] ^ inkey[x];
+    }
+
+    /* store header */
+    packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENC_KEY, y);
+
+#ifdef CLEAN_STACK
+    /* clean up */
+    zeromem(pub_expt, sizeof(pub_expt));
+    zeromem(dh_shared, sizeof(dh_shared));
+    zeromem(skey, sizeof(skey));
+#endif
+
+    *len = y;
+    return CRYPT_OK;
+}
+
+int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                         unsigned long *keylen, dh_key *key)
+{
+   unsigned char shared_secret[1536], skey[MAXBLOCKSIZE];
+   unsigned long x, y, z, res, hashsize, keysize;
+   int hash, errno;
+   dh_key pubkey;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(outkey != NULL);
+   _ARGCHK(keylen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* is header correct? */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENC_KEY)) != CRYPT_OK)  {
+      return errno;
+   }
+
+   /* now lets get the hash name */
+   y = PACKET_SIZE;
+   hash = find_hash_id(in[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* common values */
+   hashsize  = hash_descriptor[hash].hashsize;
+
+   /* get public key */
+   LOAD32L(x, in+y);
+   y += 4;
+   if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* make shared key */
+   x = sizeof(shared_secret);
+   if ((errno = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) {
+      dh_free(&pubkey);
+      return errno;
+   }
+   dh_free(&pubkey);
+
+   z = sizeof(skey);
+   if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* load in the encrypted key */
+   LOAD32L(keysize, in+y);
+   if (keysize > *keylen) {
+       res = CRYPT_BUFFER_OVERFLOW;
+       goto done;
+   }
+   y += 4;
+
+   *keylen = keysize;
+
+   for (x = 0; x < keysize; x++, y++) {
+      outkey[x] = skey[x] ^ in[y];
+   }
+
+   res = CRYPT_OK;
+done:
+#ifdef CLEAN_STACK
+   zeromem(shared_secret, sizeof(shared_secret));
+   zeromem(skey, sizeof(skey));
+#endif
+   return res;
+}
+
+
+int dh_sign_hash(const unsigned char *in,  unsigned long inlen,
+                       unsigned char *out, unsigned long *outlen,
+                       prng_state *prng, int wprng, dh_key *key)
+{
+   mp_int a, b, k, m, g, p, p1, tmp;
+   unsigned char buf[1536], md[MAXBLOCKSIZE];
+   unsigned long x, y;
+   int res, errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* check parameters */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* hash the message */
+   md[0] = 0;
+   memcpy(md+1, in, MIN(sizeof(md) - 1, inlen));
+
+   /* make up a random value k,
+    * since the order of the group is prime
+    * we need not check if gcd(k, r) is 1 
+    */
+   buf[0] = 0;
+   if (prng_descriptor[wprng].read(buf+1, sets[key->idx].size-1, prng) != 
+       (unsigned long)(sets[key->idx].size-1)) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   /* init bignums */
+   if (mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* load k and m */
+   if (mp_read_raw(&m, md,  1+MIN(sizeof(md) - 1, inlen)) != MP_OKAY)       { goto error; }
+   if (mp_read_raw(&k, buf, sets[key->idx].size) != MP_OKAY)                { goto error; }
+
+   /* load g, p and p1 */
+   if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY)               { goto error; }
+   if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY)              { goto error; }
+   if (mp_sub_d(&p, 1, &p1) != MP_OKAY)                                     { goto error; }
+   if (mp_div_2(&p1, &p1) != MP_OKAY)                                       { goto error; } /* p1 = (p-1)/2 */
+
+   /* now get a = g^k mod p */
+   if (mp_exptmod(&g, &k, &p, &a) != MP_OKAY)                               { goto error; }
+
+   /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */
+   if (mp_invmod(&k, &p1, &k) != MP_OKAY)                                   { goto error; } /* k = 1/k mod p1 */
+   if (mp_mulmod(&a, &key->x, &p1, &tmp) != MP_OKAY)                        { goto error; } /* tmp = xa */
+   if (mp_submod(&m, &tmp, &p1, &tmp) != MP_OKAY)                           { goto error; } /* tmp = M - xa */
+   if (mp_mulmod(&k, &tmp, &p1, &b) != MP_OKAY)                             { goto error; } /* b = (M - xa)/k */
+
+   /* store header  */
+   y = PACKET_SIZE;
+
+   /* now store them both (a,b) */
+   x = mp_raw_size(&a);
+   STORE32L(x, buf+y);  y += 4;
+   mp_toraw(&a, buf+y); y += x;
+
+   x = mp_raw_size(&b);
+   STORE32L(x, buf+y);  y += 4;
+   mp_toraw(&b, buf+y); y += x;
+
+   /* check if size too big */
+   if (*outlen < y) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+
+   /* store header */
+   packet_store_header(buf, PACKET_SECT_DH, PACKET_SUB_SIGNED, y);
+
+   /* store it */
+   memcpy(out, buf, y);
+   *outlen = y;
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+   zeromem(buf, sizeof(buf));
+#endif
+
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL);
+   return res;
+}
+
+int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                         unsigned long inlen, int *stat, 
+                         dh_key *key)
+{
+   mp_int a, b, p, g, m, tmp;
+   unsigned char md[MAXBLOCKSIZE];
+   unsigned long x, y;
+   int res, errno;
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(hash != NULL);
+   _ARGCHK(stat != NULL);
+   _ARGCHK(key != NULL);
+
+   /* default to invalid */
+   *stat = 0;
+
+   /* header ok? */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get hash out of packet */
+   y = PACKET_SIZE;
+
+   /* hash the message */
+   md[0] = 0;
+   memcpy(md+1, hash, MIN(sizeof(md) - 1, inlen));
+
+   /* init all bignums */
+   if (mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* load a and b */
+   LOAD32L(x, sig+y);
+   y += 4;
+   if (mp_read_raw(&a, (unsigned char *)sig+y, x) != MP_OKAY)            { goto error; }
+   y += x;
+
+   LOAD32L(x, sig+y);
+   y += 4;
+   if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY)            { goto error; }
+   y += x;
+
+   /* load p and g */
+   if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY)           { goto error; }
+   if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY)            { goto error; }
+
+   /* load m */
+   if (mp_read_raw(&m, md, 1+MIN(sizeof(md)-1, inlen)) != MP_OKAY)       { goto error; }
+
+   /* find g^m mod p */
+   if (mp_exptmod(&g, &m, &p, &m) != MP_OKAY)                            { goto error; } /* m = g^m mod p */
+
+   /* find y^a * a^b */
+   if (mp_exptmod(&key->y, &a, &p, &tmp) != MP_OKAY)                     { goto error; } /* tmp = y^a mod p */
+   if (mp_exptmod(&a, &b, &p, &a) != MP_OKAY)                            { goto error; } /* a = a^b mod p */
+   if (mp_mulmod(&a, &tmp, &p, &a) != MP_OKAY)                           { goto error; } /* a = y^a * a^b mod p */
+
+   /* y^a * a^b == g^m ??? */
+   if (mp_cmp(&a, &m) == 0) {
+      *stat = 1;
+   }
+
+   /* clean up */
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL);
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+#endif
+   return res;
+}
+

+ 49 - 0
ecb.c

@@ -0,0 +1,49 @@
+#include "mycrypt.h"
+
+#ifdef ECB
+
+int ecb_start(int cipher, const unsigned char *key, int keylen, int num_rounds, symmetric_ECB *ecb)
+{
+   int errno;
+   _ARGCHK(key != NULL);
+   _ARGCHK(ecb != NULL);
+
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+   ecb->cipher = cipher;
+   ecb->blocklen = cipher_descriptor[cipher].block_length;
+   return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ecb->key);
+}
+
+int ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ECB *ecb)
+{
+   int errno;
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ecb != NULL);
+
+   if ((errno = cipher_is_valid(ecb->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   cipher_descriptor[ecb->cipher].ecb_encrypt(pt, ct, &ecb->key);
+   return CRYPT_OK;
+}
+
+int ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ECB *ecb)
+{
+   int errno;
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ecb != NULL);
+
+   if ((errno = cipher_is_valid(ecb->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   cipher_descriptor[ecb->cipher].ecb_decrypt(ct, pt, &ecb->key);
+   return CRYPT_OK;
+}
+
+#endif
+
+

+ 827 - 0
ecc.c

@@ -0,0 +1,827 @@
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+
+#include "mycrypt.h"
+
+#ifdef MECC
+
+static const struct {
+   int size;
+   char *name, *prime, *B, *order, *Gx, *Gy;
+} sets[] = {
+#ifdef ECC160
+{
+   20,
+   "ECC-160",
+   /* prime */
+   "1461501637330902918203684832716283019655932542983",
+   /* B */
+   "1C9E7C2E5891CBE097BD46",
+   /* order */
+   "1461501637330902918203686297565868358251373258181",
+   /* Gx */
+   "2DCF462904B478D868A7FF3F2BF1FCD9",
+   /* Gy */
+   "DFFAF2EE3848FA75FB967CEC7B9A399E085ACED8",
+},
+#endif
+#ifdef ECC192
+{  
+    24,
+   "ECC-192",
+   /* prime */
+   "6277101735386680763835789423207666416083908700390324961279",
+
+   /* B */
+   "64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+
+   /* order */
+   "6277101735386680763835789423176059013767194773182842284081",
+
+   /* Gx */
+   "188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+
+   /* Gy */
+   "07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
+},
+#endif
+#ifdef ECC224
+{
+   28,
+   "ECC-224",
+
+   /* prime */
+   "26959946667150639794667015087019630673637144422540572481103610249951",
+
+   /* B */
+   "2051BA041508CED34B3",
+
+   /* order */
+   "26959946667150639794667015087019637467111563745054605861463538557247",
+
+   /* Gx */
+   "2DCF462904B478D868A7FF3F2BF1FCD9",
+ 
+   /* Gy */
+   "CF337F320BC44A15C3EDB8C4258BB958E57A0CAFA73EB46E9C4BA9AE",
+},
+#endif
+#ifdef ECC256
+{
+   32,
+   "ECC-256",
+   /* Prime */
+   "115792089210356248762697446949407573530086143415290314195533631308867097853951",
+
+   /* B */
+   "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+
+   /* Order */
+   "115792089210356248762697446949407573529996955224135760342422259061068512044369",
+
+   /* Gx */
+   "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+
+   /* Gy */
+   "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
+}, 
+#endif
+#ifdef ECC384
+{
+   48,
+   "ECC-384",
+   /* prime */
+   "394020061963944792122790401001436138050797392704654466679482934042457217714968"
+   "70329047266088258938001861606973112319",
+
+   /* B */
+   "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed1"
+   "9d2a85c8edd3ec2aef",
+
+   /* Order */
+   "394020061963944792122790401001436138050797392704654466679469052796276593991132"
+   "63569398956308152294913554433653942643",
+
+   /* Gx and Gy */
+   "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf5529"
+   "6c3a545e3872760ab7",
+   "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e81"
+   "9d7a431d7c90ea0e5f"
+},
+#endif
+#ifdef ECC521
+{
+   65,
+   "ECC-521",
+   /* prime */ 
+   "686479766013060971498190079908139321726943530014330540939446345918554318339765"
+   "6052122559640661454554977296311391480858037121987999716643812574028291115057151",
+ 
+   /* B */
+   "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7"
+   "e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+ 
+   /* Order */ 
+   "686479766013060971498190079908139321726943530014330540939446345918554318339765"
+   "5394245057746333217197532963996371363321113864768612440380340372808892707005449",
+
+   /* Gx and Gy */
+   "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe7"
+   "5928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+   "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef"
+   "42640c550b9013fad0761353c7086a272c24088be94769fd16650",
+},
+#endif
+{
+   0,
+   NULL, NULL, NULL, NULL, NULL, NULL
+}
+};
+
+#if 0
+
+/* you plug in a prime and B value and it finds a pseudo-random base point */
+void ecc_find_base(void)
+{
+   static char *prime = "26959946667150639794667015087019630673637144422540572481103610249951";
+   static char *order = "26959946667150639794667015087019637467111563745054605861463538557247";
+   static char *b     = "9538957348957353489587";
+   mp_int pp, p, r, B, tmp1, tmp2, tx, ty, x, y;
+   char buf[4096];
+   int i;
+
+   mp_init_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL);
+   mp_read_radix(&p, prime, 10);
+   mp_read_radix(&r, order, 10);
+   mp_read_radix(&B, b, 10);
+
+   /* get (p+1)/4 */
+   mp_add_d(&p, 1, &pp);
+   mp_div_2(&pp, &pp);
+   mp_div_2(&pp, &pp);
+
+   buf[0] = 0;
+   do {
+      printf("."); fflush(stdout);
+      /* make a random value of x */
+      for (i = 0; i < 16; i++) buf[i+1] = rand() & 255;
+      mp_read_raw(&x, buf, 17);
+      mp_copy(&x, &tx);
+
+      /* now compute x^3 - 3x + b */
+      mp_expt_d(&x, 3, &tmp1);
+      mp_mul_d(&x, 3, &tmp2);
+      mp_sub(&tmp1, &tmp2, &tmp1);
+      mp_add(&tmp1, &B, &tmp1);
+      mp_mod(&tmp1, &p, &tmp1);
+
+      /* now compute sqrt via x^((p+1)/4) */
+      mp_exptmod(&tmp1, &pp, &p, &tmp2);
+      mp_copy(&tmp2, &ty);
+
+      /* now square it */
+      mp_sqrmod(&tmp2, &p, &tmp2);
+
+      /* tmp2 should equal tmp1 */
+   } while (mp_cmp(&tmp1, &tmp2)); 
+
+   /* now output values in way that libtomcrypt wants */
+   mp_todecimal(&p, buf);
+   printf("\n\np==%s\n", buf);
+   mp_tohex(&B, buf);
+   printf("b==%s\n", buf);
+   mp_todecimal(&r, buf);
+   printf("r==%s\n", buf);
+   mp_tohex(&tx, buf);
+   printf("Gx==%s\n", buf);
+   mp_tohex(&ty, buf);
+   printf("Gy==%s\n", buf);
+
+   mp_clear_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL);
+}
+
+#endif
+
+static int is_valid_idx(int n)
+{
+   int x;
+
+   for (x = 0; sets[x].size; x++);
+   if ((n < 0) || (n >= x)) {
+      return 0;
+   }
+   return 1;
+}
+
+static ecc_point *new_point(void)
+{
+   ecc_point *p;
+   p = XMALLOC(sizeof(ecc_point));
+   if (p == NULL) {
+      return NULL;
+   }
+   if (mp_init_multi(&p->x, &p->y, NULL) != MP_OKAY) {
+      XFREE(p);
+      return NULL;
+   }
+   return p;
+}
+
+static void del_point(ecc_point *p)
+{
+   mp_clear_multi(&p->x, &p->y, NULL);
+   XFREE(p);
+}
+
+
+/* double a point R = 2P, R can be P*/
+static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus)
+{
+   mp_int s, tmp, tmpx;
+   int res;
+
+   if (mp_init_multi(&s, &tmp, &tmpx, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* s = (3Xp^2 + a) / (2Yp) */
+   if (mp_mul_2(&P->y, &tmp) != MP_OKAY)                   { goto error; } /* tmp = 2*y */
+   if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY)          { goto error; } /* tmp = 1/tmp mod modulus */
+   if (mp_sqr(&P->x,  &s) != MP_OKAY)                      { goto error; } /* s = x^2  */
+   if (mp_mul_d(&s, 3, &s) != MP_OKAY)                     { goto error; } /* s = 3*(x^2) */
+   if (mp_sub_d(&s, 3, &s) != MP_OKAY)                     { goto error; } /* s = 3*(x^2) - 3 */
+   if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY)        { goto error; } /* s = tmp * s mod modulus */
+
+   /* Xr = s^2 - 2Xp */
+   if (mp_sqr(&s,  &tmpx) != MP_OKAY)                      { goto error; } /* tmpx = s^2  */
+   if (mp_sub(&tmpx, &P->x, &tmpx) != MP_OKAY)             { goto error; } /* tmpx = tmpx - x */
+   if (mp_submod(&tmpx, &P->x, modulus, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmpx - x mod modulus */
+
+   /* Yr = -Yp + s(Xp - Xr)  */
+   if (mp_sub(&P->x, &tmpx, &tmp) != MP_OKAY)              { goto error; } /* tmp = x - tmpx */
+   if (mp_mul(&tmp, &s, &tmp) != MP_OKAY)                  { goto error; } /* tmp = tmp * s */
+   if (mp_submod(&tmp, &P->y, modulus, &R->y) != MP_OKAY)  { goto error; } /* y = tmp - y mod modulus */
+   if (mp_copy(&tmpx, &R->x) != MP_OKAY)                   { goto error; } /* x = tmpx */
+
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmpx, &tmp, &s, NULL);
+   return res;
+}
+
+/* add two different points over Z/pZ, R = P + Q, note R can equal either P or Q */
+static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus)
+{
+   mp_int s, tmp, tmpx;
+   int res;
+
+   if (mp_init(&tmp) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   /* is P==Q or P==-Q? */
+   mp_neg(&Q->y, &tmp);
+   mp_mod(&tmp, modulus, &tmp);
+   if (!mp_cmp(&P->x, &Q->x))
+      if (!mp_cmp(&P->y, &Q->y) || !mp_cmp(&P->y, &tmp)) {
+         mp_clear(&tmp);
+         return dbl_point(P, R, modulus);
+      }
+
+   if (mp_init_multi(&tmpx, &s, NULL) != MP_OKAY) { 
+      mp_clear(&tmp);
+      return CRYPT_MEM;
+   }
+
+   /* get s = (Yp - Yq)/(Xp-Xq) mod p */
+   if (mp_submod(&P->x, &Q->x, modulus, &tmp) != MP_OKAY)     { goto error; } /* tmp = Px - Qx mod modulus */
+   if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY)             { goto error; } /* tmp = 1/tmp mod modulus */
+   if (mp_sub(&P->y, &Q->y, &s) != MP_OKAY)                   { goto error; } /* s = Py - Qy mod modulus */
+   if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY)           { goto error; } /* s = s * tmp mod modulus */
+
+   /* Xr = s^2 - Xp - Xq */
+   if (mp_sqrmod(&s, modulus, &tmp) != MP_OKAY)               { goto error; } /* tmp = s^2 mod modulus */
+   if (mp_sub(&tmp, &P->x, &tmp) != MP_OKAY)                  { goto error; } /* tmp = tmp - Px */
+   if (mp_sub(&tmp, &Q->x, &tmpx) != MP_OKAY)                 { goto error; } /* tmpx = tmp - Qx */
+
+   /* Yr = -Yp + s(Xp - Xr) */
+   if (mp_sub(&P->x, &tmpx, &tmp) != MP_OKAY)                 { goto error; } /* tmp = Px - tmpx */
+   if (mp_mul(&tmp, &s, &tmp) != MP_OKAY)                     { goto error; } /* tmp = tmp * s */
+   if (mp_submod(&tmp, &P->y, modulus, &R->y) != MP_OKAY)     { goto error; } /* Ry = tmp - Py mod modulus */
+   if (mp_mod(&tmpx, modulus, &R->x) != MP_OKAY)              { goto error; } /* Rx = tmpx mod modulus */
+
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&s, &tmpx, &tmp, NULL);
+   return res;
+}
+
+/* perform R = kG where k == integer and G == ecc_point */
+static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus, int idx)
+{
+   ecc_point *tG;
+   int i, j, z, first, res;
+   mp_digit d;
+   unsigned char bits[768];
+   
+   /* get bits of k */
+   for (z = i = 0; z < (int)USED(k); z++) {
+       d = DIGIT(k, z);
+       
+#define DO1 bits[i++] = d&1; d >>= 1;
+#define DO2 DO1 DO1
+#define DO4 DO2 DO2
+
+       DO4; DO4; DO4; DO4
+
+#undef DO4
+#undef DO2
+#undef DO1
+   }
+
+   /* make a copy of G incase R==G */
+   tG = new_point();
+   if (tG == NULL) { 
+      return CRYPT_MEM;
+   }
+
+   /* tG = G */
+   if (mp_copy(&G->x, &tG->x) != MP_OKAY)     { goto error; }
+   if (mp_copy(&G->y, &tG->y) != MP_OKAY)     { goto error; }
+
+   /* set result to G, R = G */
+   if (mp_copy(&G->x, &R->x) != MP_OKAY)      { goto error; }
+   if (mp_copy(&G->y, &R->y) != MP_OKAY)      { goto error; }
+   first = 0;
+
+   /* now do dbl+add through all the bits */
+   for (j = i-1; j >= 0; j--) {
+       if (first) {
+           if (dbl_point(R, R, modulus) != CRYPT_OK)       { goto error; }
+       }
+       if (bits[j] == 1) {
+          if (first) {
+             if (add_point(R, tG, R, modulus) != CRYPT_OK) { goto error; }
+          }
+          first = 1;
+       }
+   }
+   res = CRYPT_OK; 
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   del_point(tG);
+#ifdef CLEAN_STACK
+   zeromem(bits, sizeof(bits)); 
+#endif
+   return res;
+}
+
+int ecc_test(void)
+{
+   mp_int     modulus, order;
+   ecc_point  *G, *GG;
+   int i, res, primality;
+
+   if (mp_init_multi(&modulus, &order, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+
+   G   = new_point();
+   if (G == NULL) { 
+      mp_clear_multi(&modulus, &order, NULL);
+      return CRYPT_MEM;
+   }
+
+   GG  = new_point();
+   if (GG == NULL) { 
+      mp_clear_multi(&modulus, &order, NULL);
+      del_point(G);
+      return CRYPT_MEM;
+   }
+
+   for (i = 0; sets[i].size; i++) {
+       if (mp_read_radix(&modulus, (unsigned char *)sets[i].prime, 10) != MP_OKAY)   { goto error; }
+       if (mp_read_radix(&order, (unsigned char *)sets[i].order, 10) != MP_OKAY)     { goto error; }
+
+       /* is prime actually prime? */
+       if (is_prime(&modulus, &primality) != CRYPT_OK)           { goto error; }
+       if (primality == 0) {
+          res = CRYPT_FAIL_TESTVECTOR;
+          goto done1;
+       }
+  
+       /* is order prime ? */
+       if (is_prime(&order, &primality) != CRYPT_OK)             { goto error; }
+       if (primality == 0) {
+          res = CRYPT_FAIL_TESTVECTOR;
+          goto done1;
+       }
+
+       if (mp_read_radix(&G->x, (unsigned char *)sets[i].Gx, 16) != MP_OKAY) { goto error; }
+       if (mp_read_radix(&G->y, (unsigned char *)sets[i].Gy, 16) != MP_OKAY) { goto error; }
+
+       /* then we should have G == (order + 1)G */
+       if (mp_add_d(&order, 1, &order) != MP_OKAY)                  { goto error; }
+       if (ecc_mulmod(&order, G, GG, &modulus, i) != CRYPT_OK)      { goto error; }
+       if (mp_cmp(&G->x, &GG->x) || mp_cmp(&G->y, &GG->y)) {
+          res = CRYPT_FAIL_TESTVECTOR;
+          goto done1;
+       }
+   }
+   res = CRYPT_OK;
+   goto done1;
+error:
+   res = CRYPT_MEM;
+done1:
+   del_point(GG);
+   del_point(G);
+   mp_clear_multi(&order, &modulus, NULL);
+   return res;
+}
+
+void ecc_sizes(int *low, int *high)
+{
+ int i;
+ _ARGCHK(low != NULL);
+ _ARGCHK(high != NULL);
+
+ *low = INT_MAX;
+ *high = 0;
+ for (i = 0; sets[i].size; i++) {
+     if (sets[i].size < *low)  { 
+        *low  = sets[i].size; 
+     }
+     if (sets[i].size > *high) { 
+        *high = sets[i].size; 
+     }
+ }
+}
+
+int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key)
+{
+   int x, res, errno;
+   ecc_point *base;
+   mp_int prime;
+   unsigned char buf[4096];
+
+   _ARGCHK(key != NULL);
+
+   /* good prng? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* find key size */
+   for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++);
+   keysize = sets[x].size;
+
+   if (sets[x].size == 0) { 
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   key->idx = x;
+
+   /* make up random string */
+   buf[0] = 0;
+   if (prng_descriptor[wprng].read(buf+1, keysize, prng) != (unsigned long)keysize) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   /* setup the key variables */
+   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL) != MP_OKAY) { 
+      return CRYPT_MEM;
+   }
+   base = new_point();
+   if (base == NULL) {
+      mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL);
+      return CRYPT_MEM;
+   }
+
+   /* read in the specs for this key */
+   if (mp_read_radix(&prime, (unsigned char *)sets[x].prime, 10) != MP_OKAY)  { goto error; }
+   if (mp_read_radix(&base->x, (unsigned char *)sets[x].Gx, 16) != MP_OKAY)   { goto error; }
+   if (mp_read_radix(&base->y, (unsigned char *)sets[x].Gy, 16) != MP_OKAY)   { goto error; }
+   if (mp_read_raw(&key->k, (unsigned char *)buf, keysize+1) != MP_OKAY)      { goto error; }
+
+   /* make the public key */
+   if (ecc_mulmod(&key->k, base, &key->pubkey, &prime, x) != CRYPT_OK) { goto error; }
+   key->type = PK_PRIVATE;
+
+   /* free up ram */
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   del_point(base);
+   mp_clear(&prime);
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return res;
+}
+
+void ecc_free(ecc_key *key)
+{
+   _ARGCHK(key != NULL);
+   mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL);
+}
+
+static int compress_y_point(ecc_point *pt, int idx, int *result)
+{
+   mp_int tmp, tmp2, p;
+   int res;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(result != NULL);
+
+   if (mp_init_multi(&tmp, &tmp2, &p, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+
+   /* get x^3 - 3x + b */
+   if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 16) != 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, 10) != MP_OKAY)  { goto error; } /* p = prime */
+   if (mp_mod(&tmp, &p, &tmp) != MP_OKAY)                  { goto error; } /* tmp = tmp mod p */
+
+   /* now find square root */
+   if (mp_add_d(&p, 1, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = p + 1 */
+   if (mp_div_2(&tmp2, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = tmp2/2 */
+   if (mp_div_2(&tmp2, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = (p+1)/4 */
+   if (mp_exptmod(&tmp, &tmp2, &p, &tmp) != MP_OKAY)       { goto error; } /* tmp  = (x^3 - 3x + b)^((p+1)/4) mod p */
+
+   /* if tmp equals the y point give a 0, otherwise 1 */
+   if (mp_cmp(&tmp, &pt->y) == 0)
+      *result = 0;
+   else
+      *result = 1;
+   
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&p, &tmp, &tmp2, NULL);
+   return res;
+}
+
+static int expand_y_point(ecc_point *pt, int idx, int result)
+{
+   mp_int tmp, tmp2, p;
+   int res;
+
+   _ARGCHK(pt != NULL);
+ 
+   if (mp_init_multi(&tmp, &tmp2, &p, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+
+   /* get x^3 - 3x + b */
+   if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 16) != 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, 10) != MP_OKAY)  { goto error; } /* p = prime */
+   if (mp_mod(&tmp, &p, &tmp) != MP_OKAY)                  { goto error; } /* tmp = tmp mod p */
+
+   /* now find square root */
+   if (mp_add_d(&p, 1, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = p + 1 */
+   if (mp_div_2(&tmp2, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = tmp2/2 */
+   if (mp_div_2(&tmp2, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = (p+1)/4 */
+   if (mp_exptmod(&tmp, &tmp2, &p, &tmp) != MP_OKAY)       { goto error; } /* tmp  = (x^3 - 3x + b)^((p+1)/4) mod p */
+
+   /* if result==0, then y==tmp, otherwise y==p-tmp */
+   if (result == 0) {
+      if (mp_copy(&tmp, &pt->y) != MP_OKAY) { goto error; }
+   } else {
+      if (mp_sub(&p, &tmp, &pt->y) != MP_OKAY) { goto error; }
+   }
+   
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&p, &tmp, &tmp2, NULL);
+   return res;
+}
+
+#define OUTPUT_BIGNUM(num, buf2, y, z)         \
+{                                              \
+      z = mp_raw_size(num);                    \
+      STORE32L(z, buf2+y);                     \
+      y += 4;                                  \
+      mp_toraw(num, buf2+y);                   \
+      y += z;                                  \
+}
+
+
+#define INPUT_BIGNUM(num, in, x, y)                              \
+{                                                                \
+     /* load value */                                            \
+     LOAD32L(x, in+y);                                           \
+     y += 4;                                                     \
+                                                                 \
+     /* sanity check... */                                       \
+     if (x > 1024) {                                             \
+        goto error;                                              \
+     }                                                           \
+                                                                 \
+     /* load it */                                               \
+     if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\
+        goto error;                                              \
+     }                                                           \
+     y += x;                                                     \
+}
+
+int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key)
+{
+   unsigned long y, z;
+   int res, errno;
+   unsigned char buf2[512];
+
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* type valid? */
+   if (key->type != PK_PRIVATE && type == PK_PRIVATE) { 
+      return CRYPT_PK_TYPE_MISMATCH; 
+   }
+
+   /* output type and magic byte */
+   y = PACKET_SIZE;
+   buf2[y++] = type;
+   buf2[y++] = key->idx;
+
+   /* output x coordinate */
+   OUTPUT_BIGNUM(&(key->pubkey.x), buf2, y, z);
+
+   /* compress y and output it  */
+   if ((errno = compress_y_point(&key->pubkey, key->idx, &res)) != CRYPT_OK) {
+      return errno;
+   }
+   buf2[y++] = res;
+
+   if (type == PK_PRIVATE) {
+      OUTPUT_BIGNUM(&key->k, buf2, y, z);
+   }
+
+   /* check size */
+   if (*outlen < y) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store header */
+   packet_store_header(buf2, PACKET_SECT_ECC, PACKET_SUB_KEY, y);
+
+   memcpy(out, buf2, y);
+   *outlen = y;
+
+   #ifdef CLEAN_STACK
+       zeromem(buf2, sizeof(buf2));
+   #endif
+   return CRYPT_OK;
+}
+
+int ecc_import(const unsigned char *in, ecc_key *key)
+{
+   unsigned long x, y;
+   int res, errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(key != NULL);
+
+   /* check type */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { 
+      return errno;
+   }
+
+   /* init key */
+   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+
+   y = PACKET_SIZE;
+   key->type = in[y++];
+   key->idx  = in[y++];
+
+   /* type check both values */
+   if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE))  {
+      res = CRYPT_INVALID_PACKET;
+      goto error2;
+   }
+
+   /* is the key idx valid? */
+   if (!is_valid_idx(key->idx)) {
+      res = CRYPT_INVALID_PACKET;
+      goto error2;
+   }
+
+   /* load x coordinate */
+   INPUT_BIGNUM(&key->pubkey.x, in, x, y);
+  
+   /* load y */
+   x = in[y++];
+   if ((errno = expand_y_point(&key->pubkey, key->idx, x)) != CRYPT_OK) { res = errno; goto error2; }
+
+   if (key->type == PK_PRIVATE) {
+      /* load private key */
+      INPUT_BIGNUM(&key->k, in, x, y);
+   }
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+error2:
+   mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL);
+done:
+   return res;
+}
+
+int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, 
+                      unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y;
+   ecc_point *result;
+   mp_int prime;
+   int res, errno;
+
+   _ARGCHK(private_key != NULL);
+   _ARGCHK(public_key != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* type valid? */
+   if (private_key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if (private_key->idx != public_key->idx) {
+      return CRYPT_PK_TYPE_MISMATCH;
+   }
+
+   /* make new point */
+   result = new_point();
+   if (result == NULL) { 
+      return CRYPT_MEM;
+   }
+
+   if (mp_init(&prime) != MP_OKAY) { 
+      del_point(result);
+      return CRYPT_MEM;
+   }
+
+   if (mp_read_radix(&prime, (unsigned char *)sets[private_key->idx].prime, 10) != MP_OKAY) { goto error; }
+   if ((errno = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime, private_key->idx)) != CRYPT_OK) { res = errno; goto done1; }
+
+   x = mp_raw_size(&result->x);
+   y = mp_raw_size(&result->y);
+
+   if (*outlen < (x+y)) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done1;
+   }
+   *outlen = x+y;
+   mp_toraw(&result->x, out);
+   mp_toraw(&result->y, out+x);
+
+   res = CRYPT_OK;
+   goto done1;
+error:
+   res = CRYPT_MEM;
+done1:
+   mp_clear(&prime);
+   del_point(result);
+   return res;
+}
+
+int ecc_get_size(ecc_key *key)
+{
+   _ARGCHK(key != NULL);
+   if (is_valid_idx(key->idx))
+      return sets[key->idx].size;
+   else
+      return INT_MAX; /* large value known to cause it to fail when passed to ecc_make_key() */
+}
+
+#include "ecc_sys.c"
+
+#endif
+
+

+ 862 - 0
ecc_sys.c

@@ -0,0 +1,862 @@
+#ifdef PK_PACKET
+
+int ecc_encrypt(const unsigned char *in,  unsigned long len, 
+                      unsigned char *out, unsigned long *outlen,
+                      prng_state *prng, int wprng, int cipher, int hash, 
+                      ecc_key *key)
+{
+    unsigned char pub_expt[512], ecc_shared[256], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE];
+    ecc_key pubkey;
+    unsigned long x, y, z, pubkeysize;
+    int keysize, blocksize, hashsize, errno;
+    symmetric_CTR ctr;
+
+    _ARGCHK(in != NULL);
+    _ARGCHK(out != NULL);
+    _ARGCHK(outlen != NULL);
+    _ARGCHK(key != NULL);
+
+    /* check that wprng/cipher/hash are not invalid */
+    if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* make a random key and export the public copy */
+    if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) {
+       return errno;
+    }
+
+    pubkeysize = sizeof(pub_expt);
+    if ((errno = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       return errno;
+    }
+    
+    /* now check if the out buffer is big enough */
+    if (*outlen < (10 + PACKET_SIZE + pubkeysize + 
+                   cipher_descriptor[cipher].block_length + len)) {
+       ecc_free(&pubkey);
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* make random key */
+    blocksize = cipher_descriptor[cipher].block_length;
+    hashsize  = hash_descriptor[hash].hashsize;
+    keysize = hashsize;
+    if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       return errno;
+    }
+    x = sizeof(ecc_shared);
+    if ((errno = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       return errno;
+    }
+    ecc_free(&pubkey);
+
+    z = sizeof(skey);
+    if ((errno = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* make up IV */
+    if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != 
+        (unsigned long)cipher_descriptor[cipher].block_length) {
+       return CRYPT_ERROR_READPRNG;
+    }
+
+    /* setup CTR mode */
+    if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* output header */
+    y = PACKET_SIZE;
+
+    /* size of cipher name and the name itself */
+    out[y++] = cipher_descriptor[cipher].ID;
+
+    /* size of hash name and the name itself */
+    out[y++] = hash_descriptor[hash].ID;
+
+    /* length of ECC pubkey and the key itself */
+    STORE32L(pubkeysize, out+y);
+    y += 4;
+    for (x = 0; x < (unsigned)pubkeysize; x++, y++) {
+        out[y] = pub_expt[x];
+    }
+
+    /* cipher IV */
+    for (x = 0; x < (unsigned)blocksize; x++, y++) {
+        out[y] = IV[x];
+    }
+
+    /* length of ciphertext */
+    STORE32L(len, out+y);
+    y += 4;
+
+    /* encrypt the message */
+    if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) {
+       return errno;
+    }
+    y += len;
+    
+    /* store header */
+    packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED, y);
+
+#ifdef CLEAN_STACK
+    /* clean up */
+    zeromem(pub_expt, sizeof(pub_expt));
+    zeromem(ecc_shared, sizeof(ecc_shared));
+    zeromem(skey, sizeof(skey));
+    zeromem(IV, sizeof(IV));
+    zeromem(&ctr, sizeof(ctr));
+#endif
+
+    *outlen = y;
+    return CRYPT_OK;
+}
+
+int ecc_decrypt(const unsigned char *in,  unsigned long len, 
+                      unsigned char *out, unsigned long *outlen, 
+                      ecc_key *key)
+{
+   unsigned char shared_secret[256], skey[MAXBLOCKSIZE];
+   unsigned long x, y, z, res, hashsize, blocksize;
+   int cipher, hash, keysize, errno;
+   ecc_key pubkey;
+   symmetric_CTR ctr;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* is header correct? */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* now lets get the cipher name */
+   y = PACKET_SIZE;
+   cipher = find_cipher_id(in[y++]);
+   if (cipher == -1) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* now lets get the hash name */
+   hash = find_hash_id(in[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* common values */
+   blocksize = cipher_descriptor[cipher].block_length;
+   hashsize  = hash_descriptor[hash].hashsize;
+   keysize = hashsize;
+   if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get public key */
+   LOAD32L(x, in+y);
+   y += 4;
+   if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* make shared key */
+   x = sizeof(shared_secret);
+   if ((errno = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      return errno;
+   }
+   ecc_free(&pubkey);
+
+   z = sizeof(skey);
+   if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+
+   /* setup CTR mode */
+   if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+   y += blocksize;
+
+   /* get length */
+   LOAD32L(len,in+y);
+   y += 4;
+   
+   /* buffer overflow? */
+   if (len > *outlen) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+
+   /* decrypt message */
+   if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) {
+      res = errno;
+      goto done;
+   }
+   *outlen = len;
+
+   res = CRYPT_OK;
+done:
+#ifdef CLEAN_STACK
+   zeromem(shared_secret, sizeof(shared_secret));
+   zeromem(skey, sizeof(skey));
+   zeromem(&ctr, sizeof(ctr));
+#endif
+   return res;
+}
+
+/* Signatures 
+ *
+ * Signatures are performed using a slightly modified ElGamal protocol.  
+ * In these notes uppercase letters are points and lowercase letters are 
+ * scalars.  The users private key is 'x' and public key is Y = xG.  
+ * The order of the curve is 'r'.
+ *
+ *
+ * To sign a message 'm' the user does this
+
+1.  Makes up a random 'k' and finds kG [basically makes up a ecc_key], we will let A = kG
+2.  Finds b such that b = (m - x)/k mod r
+3.  Outputs (A, b) as the signature
+
+To verify a user computes mG and compares that to (bA + Y).  Note that (bA + Y) is equal to
+
+= ((m - x)/k)(kG) + xG
+= (m - x)G + xG
+= mG
+
+In theory, assuming the ECC Discrete Log is a hard problem an attacker 
+cannot find 'x' from (A, b).  'b' is perfectly decorrelated and reveals no 
+information.  A reveals what kG is but not 'k' directly.  Therefore, 
+assuming finding 'k' given kG is hard, finding 'x' from b is hard too.
+
+*/
+
+int ecc_sign(const unsigned char *in,  unsigned long inlen, 
+                   unsigned char *out, unsigned long *outlen, 
+                   int hash, prng_state *prng, int wprng, 
+                   ecc_key *key)
+{
+   ecc_key pubkey;
+   mp_int b, p;
+   unsigned char epubkey[256], er[256], md[MAXBLOCKSIZE];
+   unsigned long x, y, z, pubkeysize, rsize;
+   int res, errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* is this a private key? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* make up a key and export the public copy */
+   if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK)  {
+      return errno;
+   }
+
+   pubkeysize = sizeof(epubkey);
+   if ((errno = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      return errno;
+   }
+
+   /* get the hash and load it as a bignum into 'b' */
+   md[0] = 0;
+   z = sizeof(md)-1;
+   if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      return errno;
+   }
+
+   /* init the bignums */
+   if (mp_init_multi(&b, &p, NULL) != MP_OKAY) { 
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   }
+   if (mp_read_radix(&p, sets[key->idx].order, 10) != MP_OKAY)            { goto error; }
+   if (mp_read_raw(&b, md, 1+hash_descriptor[hash].hashsize) != MP_OKAY)  { goto error; }
+
+   /* find b = (m - x)/k */
+   if (mp_invmod(&pubkey.k, &p, &pubkey.k) != MP_OKAY)                    { goto error; } /* k = 1/k */
+   if (mp_submod(&b, &key->k, &p, &b) != MP_OKAY)                         { goto error; } /* b = m - x */
+   if (mp_mulmod(&b, &pubkey.k, &p, &b) != MP_OKAY)                       { goto error; } /* b = (m - x)/k */
+
+   /* export it */
+   rsize = mp_raw_size(&b);
+   if (rsize > sizeof(er)) { 
+      goto error; 
+   }
+   mp_toraw(&b, er);
+
+   /* now lets check the outlen before we write */
+   if (*outlen < (9 + PACKET_SIZE + rsize + pubkeysize)) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done1;
+   }
+
+   /* lets output */
+   y = PACKET_SIZE;
+   
+   /* length of hash name plus NULL */
+   out[y++] = hash_descriptor[hash].ID;
+
+   /* size of public key */
+   STORE32L(pubkeysize, out+y);
+   y += 4;
+
+   /* copy the public key */
+   for (x = 0; x < pubkeysize; x++, y++) {
+       out[y] = epubkey[x];
+   }
+
+   /* size of 'r' */
+   STORE32L(rsize, out+y);
+   y += 4;
+
+   /* copy r */
+   for (x = 0; x < rsize; x++, y++) {
+       out[y] = er[x];
+   }
+
+   /* store header */
+   packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED, y);
+
+   /* clear memory */
+   *outlen = y;
+   res = CRYPT_OK;
+   goto done1;
+error:
+   res = CRYPT_MEM;
+done1:
+   mp_clear_multi(&b, &p, NULL);
+   ecc_free(&pubkey);
+#ifdef CLEAN_STACK
+   zeromem(er, sizeof(er));
+   zeromem(epubkey, sizeof(epubkey));
+   zeromem(md, sizeof(md));
+#endif
+   return res;   
+}
+
+/* verify that mG = (bA + Y) */
+int ecc_verify(const unsigned char *sig, const unsigned char *msg, 
+                     unsigned long inlen, int *stat, 
+                     ecc_key *key)
+{
+   ecc_point *mG;
+   ecc_key   pubkey;
+   mp_int b, p, m;
+   unsigned long x, y, z;
+   int hash, res, errno;
+   unsigned char md[MAXBLOCKSIZE];
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(msg != NULL);
+   _ARGCHK(stat != NULL);
+   _ARGCHK(key != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* is the message format correct? */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }     
+
+   /* get hash name */
+   y = PACKET_SIZE;
+   hash = find_hash_id(sig[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* get size of public key */
+   LOAD32L(x, sig+y);
+   y += 4;
+
+   /* load the public key */
+   if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* load size of 'b' */
+   LOAD32L(x, sig+y);
+   y += 4;
+
+   /* init values */
+   if (mp_init_multi(&b, &m, &p, NULL) != MP_OKAY) { 
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   }
+
+   mG = new_point();
+   if (mG == NULL) { 
+      mp_clear_multi(&b, &m, &p, NULL);
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   } 
+
+   /* load b */
+   if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY)                      { goto error; }
+   y += x;
+
+   /* get m in binary a bignum */
+   md[0] = 0;
+   z = sizeof(md)-1;
+   if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) {
+      res = errno;
+      goto done1;
+   }
+   if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY)         { goto error; }
+   
+   /* load prime */
+   if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY)                     { goto error; }
+
+   /* get bA */
+   if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p, key->idx) != CRYPT_OK)             { goto error; }
+   
+   /* get bA + Y */
+   if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK)    { goto error; }
+
+   /* get mG */
+   if (mp_read_radix(&mG->x, sets[key->idx].Gx, 16) != MP_OKAY)                    { goto error; }
+   if (mp_read_radix(&mG->y, sets[key->idx].Gy, 16) != MP_OKAY)                    { goto error; }
+   if (ecc_mulmod(&m, mG, mG, &p, key->idx) != CRYPT_OK)                                     { goto error; }
+
+   /* compare mG to bA + Y */
+   if (!mp_cmp(&mG->x, &pubkey.pubkey.x) && !mp_cmp(&mG->y, &pubkey.pubkey.y)) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   res = CRYPT_OK;
+   goto done1;
+error:
+   res = CRYPT_MEM;
+done1:
+   del_point(mG);
+   ecc_free(&pubkey);
+   mp_clear_multi(&p, &m, &b, NULL);
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                          unsigned char *out,  unsigned long *len, 
+                          prng_state *prng, int wprng, int hash, 
+                          ecc_key *key)
+{
+    unsigned char pub_expt[256], ecc_shared[256], skey[MAXBLOCKSIZE];
+    ecc_key pubkey;
+    unsigned long x, y, z, hashsize, pubkeysize;
+    int errno;
+
+    _ARGCHK(inkey != NULL);
+    _ARGCHK(out != NULL);
+    _ARGCHK(len != NULL);
+    _ARGCHK(key != NULL);
+
+    /* check that wprng/cipher/hash are not invalid */
+    if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if (keylen > hash_descriptor[hash].hashsize) {
+       return CRYPT_INVALID_HASH;
+    }
+
+    /* make a random key and export the public copy */
+    if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) {
+       return errno;
+    }
+
+    pubkeysize = sizeof(pub_expt);
+    if ((errno = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       return errno;
+    }
+    
+    /* now check if the out buffer is big enough */
+    if (*len < (9 + PACKET_SIZE + pubkeysize + hash_descriptor[hash].hashsize)) {
+       ecc_free(&pubkey);
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* make random key */
+    hashsize  = hash_descriptor[hash].hashsize;
+    x = sizeof(ecc_shared);
+    if ((errno = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       return errno;
+    }
+    ecc_free(&pubkey);
+    z = sizeof(skey);
+    if ((errno = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) {
+       return errno;
+    }
+
+    /* Encrypt the key */
+    for (x = 0; x < keylen; x++) {
+      skey[x] ^= inkey[x];
+    }
+
+    /* output header */
+    y = PACKET_SIZE;
+ 
+    /* size of hash name and the name itself */
+    out[y++] = hash_descriptor[hash].ID;
+
+    /* length of ECC pubkey and the key itself */
+    STORE32L(pubkeysize, out+y);
+    y += 4;
+
+    for (x = 0; x < pubkeysize; x++, y++) {
+        out[y] = pub_expt[x];
+    }
+
+    STORE32L(keylen, out+y);
+    y += 4;
+
+    /* Store the encrypted key */
+    for (x = 0; x < keylen; x++, y++) {
+      out[y] = skey[x];
+    }
+
+    /* store header */
+    packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY, y);
+
+#ifdef CLEAN_STACK
+    /* clean up */
+    zeromem(pub_expt, sizeof(pub_expt));
+    zeromem(ecc_shared, sizeof(ecc_shared));
+    zeromem(skey, sizeof(skey));
+#endif
+    *len = y;
+    return CRYPT_OK;
+}
+
+int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                          unsigned long *keylen, ecc_key *key)
+{
+   unsigned char shared_secret[256], skey[MAXBLOCKSIZE];
+   unsigned long x, y, z, res, hashsize, keysize;
+   int hash, errno;
+   ecc_key pubkey;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(outkey != NULL);
+   _ARGCHK(keylen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* is header correct? */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* now lets get the hash name */
+   y = PACKET_SIZE;
+   hash = find_hash_id(in[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+
+   /* common values */
+   hashsize  = hash_descriptor[hash].hashsize;
+
+   /* get public key */
+   LOAD32L(x, in+y);
+   y += 4;
+   if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* make shared key */
+   x = sizeof(shared_secret);
+   if ((errno = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      return errno;
+   }
+   ecc_free(&pubkey);
+
+   z = sizeof(skey);
+   if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   LOAD32L(keysize, in+y);
+   y += 4;
+
+   if (*keylen < keysize) {
+       res = CRYPT_BUFFER_OVERFLOW;
+       goto done;
+   }
+
+   /* Decrypt the key */
+   for (x = 0; x < keysize; x++, y++) {
+     outkey[x] = skey[x] ^ in[y];
+   }
+
+   *keylen = keysize;
+
+   res = CRYPT_OK;
+done:
+#ifdef CLEAN_STACK
+   zeromem(shared_secret, sizeof(shared_secret));
+   zeromem(skey, sizeof(skey));
+#endif
+   return res;
+}
+
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen, 
+                        unsigned char *out, unsigned long *outlen, 
+                        prng_state *prng, int wprng, ecc_key *key)
+{
+   ecc_key pubkey;
+   mp_int b, p;
+   unsigned char epubkey[256], er[256], md[MAXBLOCKSIZE];
+   unsigned long x, y, pubkeysize, rsize;
+   int res, errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* is this a private key? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* make up a key and export the public copy */
+   if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+
+   pubkeysize = sizeof(epubkey);
+   if ((errno = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      return errno;
+   }
+
+   /* get the hash and load it as a bignum into 'b' */
+   md[0] = 0;
+   memcpy(md+1, in, MIN(sizeof(md)-1,inlen));
+
+   /* init the bignums */
+   if (mp_init_multi(&b, &p, NULL) != MP_OKAY) { 
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   }
+   if (mp_read_radix(&p, (unsigned char *)sets[key->idx].order, 10) != MP_OKAY)            { goto error; }
+   if (mp_read_raw(&b, md, 1+MIN(sizeof(md)-1,inlen)) != MP_OKAY)         { goto error; }
+
+   /* find b = (m - x)/k */
+   if (mp_invmod(&pubkey.k, &p, &pubkey.k) != MP_OKAY)                    { goto error; } /* k = 1/k */
+   if (mp_submod(&b, &key->k, &p, &b) != MP_OKAY)                         { goto error; } /* b = m - x */
+   if (mp_mulmod(&b, &pubkey.k, &p, &b) != MP_OKAY)                       { goto error; } /* b = (m - x)/k */
+
+   /* export it */
+   rsize = mp_raw_size(&b);
+   if (rsize > sizeof(er)) { 
+      goto error; 
+   }
+   mp_toraw(&b, er);
+
+   /* now lets check the outlen before we write */
+   if (*outlen < (12 + rsize + pubkeysize)) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done1;
+   }
+
+   /* lets output */
+   y = PACKET_SIZE;
+   
+   /* size of public key */
+   STORE32L(pubkeysize, out+y);
+   y += 4;
+
+   /* copy the public key */
+   for (x = 0; x < pubkeysize; x++, y++) {
+       out[y] = epubkey[x];
+   }
+
+   /* size of 'r' */
+   STORE32L(rsize, out+y);
+   y += 4;
+
+   /* copy r */
+   for (x = 0; x < rsize; x++, y++) {
+       out[y] = er[x];
+   }
+
+   /* store header */
+   packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED, y);
+
+   /* clear memory */
+   *outlen = y;
+   res = CRYPT_OK;
+   goto done1;
+error:
+   res = CRYPT_MEM;
+done1:
+   mp_clear_multi(&b, &p, NULL);
+   ecc_free(&pubkey);
+#ifdef CLEAN_STACK
+   zeromem(er, sizeof(er));
+   zeromem(epubkey, sizeof(epubkey));
+   zeromem(md, sizeof(md));
+#endif
+   return res;   
+}
+
+/* verify that mG = (bA + Y) */
+int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                     unsigned long inlen, int *stat, 
+                     ecc_key *key)
+{
+   ecc_point *mG;
+   ecc_key   pubkey;
+   mp_int b, p, m;
+   unsigned long x, y;
+   int res, errno;
+   unsigned char md[MAXBLOCKSIZE];
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(hash != NULL);
+   _ARGCHK(hash != NULL);
+   _ARGCHK(key != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* is the message format correct? */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }     
+
+   /* get hash name */
+   y = PACKET_SIZE;
+
+   /* get size of public key */
+   LOAD32L(x, sig+y);
+   y += 4;
+
+   /* load the public key */
+   if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) {
+      return errno;
+   }
+   y += x;
+
+   /* load size of 'b' */
+   LOAD32L(x, sig+y);
+   y += 4;
+
+   /* init values */
+   if (mp_init_multi(&b, &m, &p, NULL) != MP_OKAY) { 
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   }
+
+   mG = new_point();
+   if (mG == NULL) { 
+      mp_clear_multi(&b, &m, &p, NULL);
+      ecc_free(&pubkey);
+      return CRYPT_MEM;
+   } 
+
+   /* load b */
+   if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY)                      { goto error; }
+   y += x;
+
+   /* get m in binary a bignum */
+   md[0] = 0;
+   memcpy(md+1,hash,MIN(sizeof(md)-1,inlen));
+   if (mp_read_raw(&m, md, 1+MIN(sizeof(md)-1,inlen)) != MP_OKAY)                  { goto error; }
+   
+   /* load prime */
+   if (mp_read_radix(&p, (unsigned char *)sets[key->idx].prime, 10) != MP_OKAY)    { goto error; }
+
+   /* get bA */
+   if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p, key->idx) != CRYPT_OK)   { goto error; }
+   
+   /* get bA + Y */
+   if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK)    { goto error; }
+
+   /* get mG */
+   if (mp_read_radix(&mG->x, (unsigned char *)sets[key->idx].Gx, 16) != MP_OKAY)   { goto error; }
+   if (mp_read_radix(&mG->y, (unsigned char *)sets[key->idx].Gy, 16) != MP_OKAY)   { goto error; }
+   if (ecc_mulmod(&m, mG, mG, &p, key->idx) != CRYPT_OK)                           { goto error; }
+
+   /* compare mG to bA + Y */
+   if (!mp_cmp(&mG->x, &pubkey.pubkey.x) && !mp_cmp(&mG->y, &pubkey.pubkey.y)) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_ERROR;
+done:
+   del_point(mG);
+   ecc_free(&pubkey);
+   mp_clear_multi(&p, &m, &b, NULL);
+#ifdef CLEAN_STACK
+   zeromem(md, sizeof(md));
+#endif
+   return CRYPT_OK;
+}
+

+ 295 - 0
gf.c

@@ -0,0 +1,295 @@
+/* polynomial basis GF(2^w) routines */
+#include "mycrypt.h"
+
+#ifdef GF
+
+#define FORLOOP for (i = 0; i < LSIZE; i++) 
+
+/* c = a + b */
+void gf_add(gf_intp a, gf_intp b, gf_intp c)
+{
+   int i;
+   FORLOOP c[i] = a[i]^b[i];
+}
+
+/* b = a */
+void gf_copy(gf_intp a, gf_intp b)
+{
+   int i;
+   FORLOOP b[i] = a[i];
+}
+
+/* a = 0 */
+void gf_zero(gf_intp a)
+{
+   int i;
+   FORLOOP a[i] = 0;
+}
+
+/* is a zero? */
+int gf_iszero(gf_intp a)
+{
+   int i;
+   FORLOOP if (a[i]) {
+      return 0;
+   }
+   return 1;
+}
+
+/* is a one? */
+int gf_isone(gf_intp a)
+{ 
+   int i;
+   for (i = 1; i < LSIZE; i++) {
+       if (a[i]) {
+          return 0;
+       }
+   }
+   return a[0] == 1;
+}
+
+/* b = a << 1*/
+void gf_shl(gf_intp a, gf_intp b)
+{
+   int i;
+   gf_int tmp;
+
+   gf_copy(a, tmp);
+   for (i = LSIZE-1; i > 0; i--) 
+       b[i] = ((tmp[i]<<1)|((tmp[i-1]&0xFFFFFFFFUL)>>31))&0xFFFFFFFFUL;
+   b[0] = (tmp[0] << 1)&0xFFFFFFFFUL;
+   gf_zero(tmp);
+}
+
+/* b = a >> 1 */
+void gf_shr(gf_intp a, gf_intp b)
+{
+   int i;
+   gf_int tmp;
+
+   gf_copy(a, tmp);
+   for (i = 0; i < LSIZE-1; i++)
+       b[i] = (((tmp[i]&0xFFFFFFFFUL)>>1)|(tmp[i+1]<<31))&0xFFFFFFFFUL;
+   b[LSIZE-1] = (tmp[LSIZE-1]&0xFFFFFFFFUL)>>1;
+   gf_zero(tmp);
+}
+
+/* returns -1 if its zero, otherwise degree of a */
+int gf_deg(gf_intp a)
+{
+   int i, ii;
+   unsigned long t;
+
+   ii = -1;
+   for (i = LSIZE-1; i >= 0; i--)
+       if (a[i]) {
+          for (t = a[i], ii = 0; t; t >>= 1, ++ii);
+          break;
+       }
+   if (i == -1) i = 0;
+   return (i<<5)+ii;
+}
+
+/* c = ab */
+void gf_mul(gf_intp a, gf_intp b, gf_intp c)
+{
+   gf_int ta, tb;
+   int i, n;
+
+   gf_copy(a, ta);
+   gf_copy(b, tb);
+   gf_zero(c);
+   n = gf_deg(ta)+1;
+   for (i = 0; i < n; i++) {
+       if (ta[i>>5]&(1<<(i&31)))
+          gf_add(c, tb, c);
+       gf_shl(tb, tb);
+   }
+   gf_zero(ta);
+   gf_zero(tb);
+}
+
+/* q = a/b, r = a%b */
+void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r)
+{
+   gf_int ta, tb, shifts[LSIZE*32];
+   int i, magb, mag;
+
+   mag  = gf_deg(a);
+   magb = gf_deg(b);
+
+   /* special cases */
+   if (magb > mag) {
+      gf_copy(a, r);
+      gf_zero(q);
+      return;
+   }
+   if (magb == -1) {
+      return;
+   }
+
+   /* copy locally */
+   gf_copy(a, ta);
+   gf_copy(b, tb);
+   gf_zero(q);
+
+   /* make shifted versions of "b" */
+   gf_copy(tb, shifts[0]);
+   for (i = 1; i <= (mag-magb); i++) 
+       gf_shl(shifts[i-1], shifts[i]);
+
+   while (mag >= magb) {
+       i = (mag - magb);
+       q[i>>5] |= (1<<(i&31));
+       gf_add(ta, shifts[i], ta);
+       mag = gf_deg(ta);
+   }
+   gf_copy(ta, r);
+   gf_zero(ta);
+   gf_zero(tb);
+   zeromem(shifts, sizeof(shifts));
+}
+
+/* b = a mod m */
+void gf_mod(gf_intp a, gf_intp m, gf_intp b)
+{
+   gf_int tmp;
+   gf_div(a,m,tmp,b);
+   gf_zero(tmp);
+}
+
+/* c = ab (mod m) */
+void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c)
+{
+   gf_int tmp;
+   gf_mul(a, b, tmp);
+   gf_mod(tmp, m, c);
+   gf_zero(tmp);
+}
+
+/* B = 1/A mod M */
+void gf_invmod(gf_intp A, gf_intp M, gf_intp B)
+{
+  gf_int m, n, p0, p1, p2, r, q, tmp;
+
+  /* put all variables in known setup state */
+  gf_zero(p0);
+  gf_zero(p2);
+  gf_copy(M, m);
+  gf_copy(A, n);
+  p0[0] = 1;
+  gf_div(m, n, p1, r);
+  gf_copy(p1, q);
+
+  /* loop until r == 0 */
+  while (!gf_iszero(r)) {
+     gf_copy(n, m);
+     gf_copy(r, n);
+     gf_div(m, n, q, r);
+     gf_mul(q, p1, tmp);
+     gf_add(tmp, p0, p2);
+     gf_copy(p1, p0);
+     gf_copy(p2, p1);
+  }
+  gf_copy(p0, B);
+  gf_zero(p0);
+}
+
+/* find a square root modulo a prime.  Note the number of 
+ * elements is 2^k - 1, so we must square k-2 times to get the
+ * square root.. 
+ */
+void gf_sqrt(gf_intp a, gf_intp M, gf_intp b)
+{
+   int k;
+   k = gf_deg(M)-2;
+   gf_copy(a, b);
+   while (k--)
+      gf_mulmod(b, b, M, b);
+}
+
+/* c = gcd(A,B) */
+void gf_gcd(gf_intp A, gf_intp B, gf_intp c)
+{
+   gf_int a, b, r;
+   int n;
+
+   gf_add(A, B, r);
+   n = gf_deg(r);
+   if (gf_deg(A) > n) {
+      gf_copy(A, a);
+      gf_copy(B, b);
+   } else {
+      gf_copy(A, b);
+      gf_copy(B, a);
+   }
+
+   do {
+      gf_mod(a, b, r);
+      gf_copy(b, a);
+      gf_copy(r, b);
+   } while (!gf_iszero(r));
+   gf_copy(a, c);
+   gf_zero(a);
+   gf_zero(b);
+}
+
+/* returns non-zero if 'a' is irreducible */
+int gf_is_prime(gf_intp a)
+{
+   gf_int u, tmp;
+   int m, n;
+
+   gf_zero(u);
+   u[0] = 2;			/* u(x) = x */
+   m = gf_deg(a);
+   for (n = 0; n < (m/2); n++) { 
+       gf_mulmod(u, u, a, u);   /* u(x) = u(x)^2 mod a(x) */
+       gf_copy(u, tmp);
+       tmp[0] ^= 2;		/* tmp(x) = u(x) - x */
+       gf_gcd(tmp, a, tmp);     /* tmp(x) = gcd(a(x), u(x) - x) */
+       if (!gf_isone(tmp)) {
+          return 0;
+       }
+   }
+   return 1;
+}  
+
+/* returns bytes required to store a gf_int */
+int gf_size(gf_intp a)
+{
+   int n;
+
+   n = gf_deg(a);
+   if (n == -1) {
+      return 4;
+   }
+   n = n + (32 - (n&31));
+   return n/8;
+}
+
+/* store a gf_int */
+void gf_toraw(gf_intp a, unsigned char *dst)
+{
+   int x, n;
+   n = gf_size(a)/4;
+   for (x = 0; x < n; x++) {
+       STORE32L(a[x], dst);
+       dst += 4;
+   }
+}
+
+/* read a gf_int (len == in bytes) */
+void gf_readraw(gf_intp a, unsigned char *str, int len)
+{
+   int x;
+   gf_zero(a);
+   for (x = 0; x < len/4; x++) {
+       LOAD32L(a[x], str);
+       str += 4;
+   }
+}
+
+#endif
+
+

+ 93 - 0
hash.c

@@ -0,0 +1,93 @@
+#include "mycrypt.h"
+
+int hash_memory(int hash, const unsigned char *data, unsigned long len, unsigned char *dst, unsigned long *outlen)
+{
+    hash_state md;
+    int errno;
+
+    _ARGCHK(data != NULL);
+    _ARGCHK(dst != NULL);
+    _ARGCHK(outlen != NULL);
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+        return errno;
+    }
+
+    if (*outlen < hash_descriptor[hash].hashsize) {
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+    *outlen = hash_descriptor[hash].hashsize;
+
+    hash_descriptor[hash].init(&md);
+    hash_descriptor[hash].process(&md, data, len);
+    hash_descriptor[hash].done(&md, dst);
+    return CRYPT_OK;
+}
+
+int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen)
+{
+#ifdef NO_FILE
+    return CRYPT_ERROR;
+#else
+    hash_state md;
+    unsigned char buf[512];
+    int x, errno;
+
+    _ARGCHK(dst != NULL);
+    _ARGCHK(outlen != NULL);
+    _ARGCHK(in != NULL);
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+        return errno;
+    }
+
+    if (*outlen < hash_descriptor[hash].hashsize) {
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+    *outlen = hash_descriptor[hash].hashsize;
+
+    hash_descriptor[hash].init(&md);
+    do {
+        x = fread(buf, 1, sizeof(buf), in);
+        hash_descriptor[hash].process(&md, buf, x);
+    } while (x == sizeof(buf));
+    hash_descriptor[hash].done(&md, dst);
+
+#ifdef CLEAN_STACK
+    zeromem(buf, sizeof(buf));
+#endif
+    return CRYPT_OK;
+#endif
+}
+
+
+int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen)
+{
+#ifdef NO_FILE
+    return CRYPT_ERROR;
+#else
+    FILE *in;
+    int errno;
+    _ARGCHK(fname != NULL);
+    _ARGCHK(dst != NULL);
+    _ARGCHK(outlen != NULL);
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+        return errno;
+    }
+
+    in = fopen(fname, "rb");
+    if (in == NULL) { 
+       return CRYPT_INVALID_ARG;
+    }
+
+    if ((errno = hash_filehandle(hash, in, dst, outlen)) != CRYPT_OK) {
+       fclose(in);
+       return errno;
+    }
+    fclose(in);
+
+    return CRYPT_OK;
+#endif
+}
+

+ 478 - 0
hmac.c

@@ -0,0 +1,478 @@
+/* Submited by Dobes Vandermeer  ([email protected]) */
+
+#include "mycrypt.h"
+
+/*
+    (1) append zeros to the end of K to create a B byte string
+        (e.g., if K is of length 20 bytes and B=64, then K will be
+         appended with 44 zero bytes 0x00)
+    (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+        (1) with ipad (ipad = the byte 0x36 repeated B times)
+    (3) append the stream of data 'text' to the B byte string resulting
+        from step (2)
+    (4) apply H to the stream generated in step (3)
+    (5) XOR (bitwise exclusive-OR) the B byte string computed in
+        step (1) with opad (opad = the byte 0x5C repeated B times.)
+    (6) append the H result from step (4) to the B byte string
+        resulting from step (5)
+    (7) apply H to the stream generated in step (6) and output
+        the result
+*/
+
+#ifdef HMAC
+
+#define HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
+
+int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
+{
+    unsigned char buf[MAXBLOCKSIZE];
+    unsigned long hashsize;
+    unsigned long i, z;
+    int errno;
+
+    _ARGCHK(hmac != NULL);
+    _ARGCHK(key != NULL);
+
+    if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+        return errno;
+    }
+
+    if(key == NULL || keylen == 0) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    hmac->hash = hash;
+
+    // (1) make sure we have a large enough key
+    hmac->hashsize = hashsize = hash_descriptor[hash].hashsize;
+    if(keylen > HMAC_BLOCKSIZE) {
+        z = sizeof(hmac->key);
+        if ((errno = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
+           return errno;
+        }
+        if(hashsize < HMAC_BLOCKSIZE) {
+            zeromem(hmac->key+hashsize, HMAC_BLOCKSIZE - hashsize);
+        }
+    } else {
+        memcpy(hmac->key, key, keylen);
+        if(keylen < HMAC_BLOCKSIZE) {
+            zeromem(hmac->key + keylen, HMAC_BLOCKSIZE - keylen);
+        }
+    }
+
+    // Create the initial vector for step (3)
+    for(i=0; i < keylen;   i++) {
+       buf[i] = hmac->key[i] ^ 0x36;
+    }
+
+    for(   ; i < HMAC_BLOCKSIZE; i++) { 
+       buf[i] = 0x36;
+    }
+
+    // Pre-pend that to the hash data
+    hash_descriptor[hash].init(&hmac->md);
+    hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE);
+
+    return CRYPT_OK;
+}
+
+int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len)
+{
+    int errno;
+    _ARGCHK(hmac != NULL);
+    _ARGCHK(buf != NULL);
+    if ((errno = hash_is_valid(hmac->hash)) != CRYPT_OK) {
+        return errno;
+    }
+    hash_descriptor[hmac->hash].process(&hmac->md, buf, len);
+    return CRYPT_OK;
+}
+
+int hmac_done(hmac_state *hmac, unsigned char *hashOut)
+{
+    unsigned char buf[MAXBLOCKSIZE];
+    unsigned char isha[MAXBLOCKSIZE];
+    unsigned long hashsize, i;
+    int hash, errno;
+
+    _ARGCHK(hmac != NULL);
+    _ARGCHK(hashOut != NULL);
+
+    hash = hmac->hash;
+    if((errno = hash_is_valid(hash)) != CRYPT_OK) {
+        return errno;
+    }
+
+    // Get the hash of the first HMAC vector plus the data
+    hash_descriptor[hash].done(&hmac->md, isha);
+
+    // Create the second HMAC vector vector for step (3)
+    hashsize = hash_descriptor[hash].hashsize;
+    for(i=0; i < HMAC_BLOCKSIZE; i++) {
+        buf[i] = hmac->key[i] ^ 0x5C;
+    }
+
+    // Now calculate the "outer" hash for step (5), (6), and (7)
+    hash_descriptor[hash].init(&hmac->md);
+    hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE);
+    hash_descriptor[hash].process(&hmac->md, isha, hashsize);
+    hash_descriptor[hash].done(&hmac->md, hashOut);
+
+#ifdef CLEAN_STACK
+    zeromem(hmac->key, sizeof(hmac->key));
+#endif
+    return CRYPT_OK;
+}
+
+int hmac_memory(int hash, const unsigned char *key, unsigned long keylen,
+                const unsigned char *data, unsigned long len, unsigned char *dst)
+{
+    hmac_state hmac;
+    int errno;
+
+    _ARGCHK(key != NULL);
+    _ARGCHK(data != NULL);
+    _ARGCHK(dst != NULL);
+
+    if ((errno = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) {
+        return errno;
+    }
+  
+    if ((errno = hmac_process(&hmac, data, len)) != CRYPT_OK) {
+       return errno;
+    }
+
+    if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) {
+       return errno;
+    }
+    return CRYPT_OK;
+}
+
+/* hmac_file added by Tom St Denis */
+int hmac_file(int hash, const char *fname, const unsigned char *key,
+                unsigned long keylen, unsigned char *dst)
+{
+#ifdef NO_FILE
+    return CRYPT_ERROR;
+#else
+   hmac_state hmac;
+   FILE *in;
+   unsigned char buf[512];
+   int x, errno;
+
+   _ARGCHK(fname != NULL);
+   _ARGCHK(key != NULL);
+   _ARGCHK(dst != NULL);
+
+   if ((errno = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) {
+       return errno;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* process the file contents */
+   do {
+      x = fread(buf, 1, sizeof(buf), in);
+      if ((errno = hmac_process(&hmac, buf, x)) != CRYPT_OK) { 
+         fclose(in);
+         return errno;
+      }
+   } while (x == sizeof(buf));
+   fclose(in);
+
+   /* get final hmac */
+   if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) {
+      return errno;
+   }
+
+#ifdef CLEAN_STACK
+   /* clear memory */
+   zeromem(buf, sizeof(buf));
+#endif   
+   return CRYPT_OK;
+#endif
+}
+
+/*
+
+    TEST CASES SOURCE:
+
+Network Working Group                                          P. Cheng
+Request for Comments: 2202                                          IBM
+Category: Informational                                        R. Glenn
+                                                                   NIST
+                                                         September 1997
+
+                 Test Cases for HMAC-MD5 and HMAC-SHA-1
+*/
+
+
+int hmac_test(void)
+{
+    unsigned char digest[MAXBLOCKSIZE];
+    int i;
+
+    struct hmac_test_case {
+        int num;
+        char *algo;
+        unsigned char key[128];
+        int keylen;
+        unsigned char data[128];
+        int datalen;
+        unsigned char digest[MAXBLOCKSIZE];
+    } cases[] = {
+        /*
+        3. Test Cases for HMAC-SHA-1
+
+        test_case =     1
+        key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+        key_len =       20
+        data =          "Hi Ther     20
+        digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+        digest-96 =     0x4c1a03424b55e07fe7f27be1
+        */
+        { 5, "sha1",
+            {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 
+             0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 
+             0x0c, 0x0c, 0x0c, 0x0c}, 20,
+            "Test With Truncation", 20,
+            {0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+             0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04} },
+
+        /*
+        test_case =     6
+        key =           0xaa repeated 80 times
+        key_len =       80
+        data =          "Test Using Larger Than Block-Size Key - Hash Key First"
+        data_len =      54
+        digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112
+        */
+        { 6, "sha1",
+            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
+            "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+            {0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
+             0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, 
+             0xed, 0x40, 0x21, 0x12} },
+
+        /*
+        test_case =     7
+        key =           0xaa repeated 80 times
+        key_len =       80
+        data =          "Test Using Larger Than Block-Size Key and Larger
+                        Than One Block-Size Data"
+        data_len =      73
+        digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
+        */
+        { 7, "sha1",
+            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
+            "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73,
+            {0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d,
+             0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91} },
+
+        /*
+        2. Test Cases for HMAC-MD5
+
+        test_case =     1
+        key =           0x0b 0b 0b 0b 
+                          0b 0b 0b 0b
+                          0b 0b 0b 0b
+                          0b 0b 0b 0b
+        key_len =       16
+        data =          "Hi There"
+        data_len =      8
+        digest =        0x92 94 72 7a 
+                          36 38 bb 1c 
+                          13 f4 8e f8 
+                          15 8b fc 9d
+        */
+        { 1, "md5",
+            {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 16,
+            "Hi There", 8,
+            {0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, 
+             0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d}  },
+        /*
+        test_case =     2
+        key =           "Jefe"
+        key_len =       4
+        data =          "what do ya want for nothing?"
+        data_len =      28
+        digest =        0x750c783e6ab0b503eaa86e310a5db738
+        */
+        { 2, "md5",
+            "Jefe", 4,
+            "what do ya want for nothing?", 28,
+            {0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, 
+             0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38} },
+
+        /*
+        test_case =     3
+        key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+        key_len         16
+        data =          0xdd repeated 50 times
+        data_len =      50
+        digest =        0x56be34521d144c88dbb8c733f0e8b3f6
+        */
+        { 3, "md5",
+            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 16,
+            {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+             0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+             0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+             0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+             0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}, 50,
+            {0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
+             0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6} },
+        /*
+
+        test_case =     4
+        key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
+        key_len         25
+        data =          0xcd repeated 50 times
+        data_len =      50
+        digest =        0x697eaf0aca3a3aea3a75164746ffaa79
+        */
+        { 4, "md5",
+            {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+             0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+             0x15, 0x16, 0x17, 0x18, 0x19}, 25,
+            {0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+             0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+             0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+             0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+             0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd}, 50,
+            {0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, 
+             0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79} },
+
+
+        /*
+ 
+        test_case =     5
+        key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+        key_len =       16
+        data =          "Test With Truncation"
+        data_len =      20
+        digest =        0x56461ef2342edc00f9bab995690efd4c
+        digest-96       0x56461ef2342edc00f9bab995
+        */
+        { 5, "md5",
+            {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 
+             0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, 16,
+            "Test With Truncation", 20,
+            {0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00, 
+             0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c} },
+
+        /*
+
+        test_case =     6
+        key =           0xaa repeated 80 times
+        key_len =       80
+        data =          "Test Using Larger Than Block-Size Key - Hash 
+Key First"
+        data_len =      54
+        digest =        0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
+        */
+        { 6, "md5",
+            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
+            "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+            {0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, 
+             0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd} },
+
+        /*
+
+        test_case =     7
+        key =           0xaa repeated 80 times
+        key_len =       80
+        data =          "Test Using Larger Than Block-Size Key and Larger
+                        Than One Block-Size Data"
+        data_len =      73
+        digest =        0x6f630fad67cda0ee1fb1f562db3aa53e
+        */
+        { 7, "md5",
+            {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
+            "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73,
+            {0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
+             0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e} }
+    };
+
+    int errno;
+    int failed=0;
+    for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
+        int hash = find_hash(cases[i].algo);
+        if((errno = hmac_memory(hash, cases[i].key, cases[i].keylen, cases[i].data, cases[i].datalen, digest)) != CRYPT_OK) {
+#if 0
+            printf("HMAC-%s test #%d\n", cases[i].algo, cases[i].num);
+#endif
+            return errno;
+        }
+
+        if(memcmp(digest, cases[i].digest, hash_descriptor[hash].hashsize) != 0)  {
+#if 0
+            unsigned int j;
+            printf("\nHMAC-%s test #%d:\n", cases[i].algo, cases[i].num);
+            printf(  "Result:  0x");
+            for(j=0; j < hash_descriptor[hash].hashsize; j++) {
+                printf("%2x ", digest[j]);
+            }
+            printf("\nCorrect: 0x");
+            for(j=0; j < hash_descriptor[hash].hashsize; j++) {
+               printf("%2x ", cases[i].digest[j]);
+            }
+            printf("\n");
+#endif
+            failed++;
+            //return CRYPT_ERROR;
+        } else {
+            /* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */
+        }
+    }
+
+    if(failed) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    return CRYPT_OK;
+}
+
+#endif
+

+ 840 - 0
keyring.c

@@ -0,0 +1,840 @@
+/* Provides keyring functionality for libtomcrypt, Tom St Denis */
+#include <mycrypt.h>
+
+#ifdef KR
+
+static const unsigned char key_magic[4]  = { 0x12, 0x34, 0x56, 0x78 };
+static const unsigned char file_magic[4] = { 0x9A, 0xBC, 0xDE, 0xF0 };
+static const unsigned char sign_magic[4] = { 0x87, 0x56, 0x43, 0x21 };
+static const unsigned char enc_magic[4]  = { 0x0F, 0xED, 0xCB, 0xA9 };
+
+static const unsigned long crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+static unsigned long crc32 (unsigned long crc, const unsigned char *buf, unsigned long len)
+{
+  crc = crc ^ 0xffffffffL;
+  while (len >= 8)
+    {
+      DO8 (buf);
+      len -= 8;
+    }
+  if (len)
+    do
+      {
+	DO1 (buf);
+      }
+    while (--len);
+  return crc ^ 0xffffffffUL;
+}
+
+int kr_init(pk_key **pk)
+{
+   _ARGCHK(pk != NULL);
+
+   *pk = XCALLOC(1, sizeof(pk_key));
+   if (*pk == NULL) {
+      return CRYPT_MEM;
+   }
+   (*pk)->system = NON_KEY;
+   return CRYPT_OK;
+}
+
+unsigned long kr_crc(const unsigned char *name, const unsigned char *email, const unsigned char *description)
+{
+   unsigned long crc;
+   _ARGCHK(name != NULL);
+   _ARGCHK(email != NULL);
+   _ARGCHK(description != NULL);
+   crc = crc32(0, NULL, 0);
+   crc = crc32(crc, name,  MIN(MAXLEN, strlen((char *)name)));
+   crc = crc32(crc, email, MIN(MAXLEN, strlen((char *)email)));
+   return crc32(crc, description, MIN(MAXLEN, strlen((char *)description)));
+}
+
+pk_key *kr_find(pk_key *pk, unsigned long ID)
+{
+   _ARGCHK(pk != NULL);
+
+   while (pk != NULL) {
+        if (pk->system != NON_KEY && pk->ID == ID) {
+           return pk;
+        }
+        pk = pk->next;
+   }
+   return NULL;
+}
+
+pk_key *kr_find_name(pk_key *pk, const char *name)
+{
+   _ARGCHK(pk != NULL);
+   _ARGCHK(name != NULL);
+
+   while (pk != NULL) {
+        if (pk->system != NON_KEY && !strncmp((char *)pk->name, (char *)name, sizeof(pk->name)-1)) {
+           return pk;
+        }
+        pk = pk->next;
+   }
+   return NULL;
+}
+ 
+
+int kr_add(pk_key *pk, int key_type, int system, const unsigned char *name, 
+           const unsigned char *email, const unsigned char *description, const _pk_key *key)
+{
+   _ARGCHK(pk != NULL);
+   _ARGCHK(name != NULL);
+   _ARGCHK(email != NULL);
+   _ARGCHK(description != NULL);
+   _ARGCHK(key != NULL);
+
+   /* check parameters */
+   if (key_type != PK_PRIVATE && key_type != PK_PRIVATE_OPTIMIZED && key_type != PK_PUBLIC) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+ 
+   if (system != RSA_KEY && system != DH_KEY && system != ECC_KEY) {
+      return CRYPT_PK_INVALID_SYSTEM;
+   }
+
+   /* see if its a dupe  */
+   if (kr_find(pk, kr_crc(name, email, description)) != NULL) {
+      return CRYPT_PK_DUP;
+   }
+   
+   /* find spot in key ring */
+   while (pk->system != NON_KEY) {
+         if (pk->next == NULL) {
+            return CRYPT_ERROR;
+         }
+         pk = pk->next;
+   }
+
+   /* now we have a spot make a next spot */
+   pk->next = XCALLOC(1, sizeof(pk_key));
+   if (pk->next == NULL) {
+      return CRYPT_MEM;
+   }
+   pk->next->system = NON_KEY;
+
+   /* now add this new data to this ring spot */
+   pk->key_type = key_type;
+   pk->system   = system;
+   strncpy((char *)pk->name, (char *)name, sizeof(pk->name)-1);
+   strncpy((char *)pk->email, (char *)email, sizeof(pk->email)-1);
+   strncpy((char *)pk->description, (char *)description, sizeof(pk->description)-1);
+   pk->ID       = kr_crc(pk->name, pk->email, pk->description);
+
+   /* clear the memory area */
+   zeromem(&(pk->key), sizeof(pk->key));
+
+   /* copy the key */
+   switch (system) {
+         case RSA_KEY:
+              memcpy(&(pk->key.rsa), &(key->rsa), sizeof(key->rsa));
+              break;
+         case DH_KEY:
+              memcpy(&(pk->key.dh), &(key->dh), sizeof(key->dh));
+              break;
+         case ECC_KEY:
+              memcpy(&(pk->key.ecc), &(key->ecc), sizeof(key->ecc));
+              break;
+   }
+   return CRYPT_OK;
+}
+
+int kr_del(pk_key **_pk, unsigned long ID)
+{
+   pk_key *ppk, *pk;
+
+   _ARGCHK(_pk != NULL);
+
+   pk  = *_pk;
+   ppk = NULL;
+   while (pk->system != NON_KEY && pk->ID != ID) {
+        ppk = pk;
+        pk  = pk->next;
+        if (pk == NULL) {
+           return CRYPT_PK_NOT_FOUND;
+        }
+   }
+
+   switch (pk->system) {
+        case RSA_KEY:
+            rsa_free(&(pk->key.rsa));
+            break;
+        case DH_KEY:
+            dh_free(&(pk->key.dh));
+            break;
+        case ECC_KEY:
+            ecc_free(&(pk->key.ecc));
+            break;
+   }
+
+   if (ppk == NULL) {       /* the first element matches the ID */
+      ppk = pk->next;       /* get the 2nd element */
+      XFREE(pk);             /* free the first */
+      *_pk = ppk;           /* make the first element the second */
+   } else {                 /* (not) first element matches the ID */
+      ppk->next = pk->next; /* make the previous'es next point to the current next */
+      XFREE(pk);             /* free the element */
+   }
+   return CRYPT_OK;
+}
+
+int kr_clear(pk_key **pk)
+{
+   int errno;
+   _ARGCHK(pk != NULL);
+
+   while ((*pk)->system != NON_KEY) {
+       if ((errno = kr_del(pk, (*pk)->ID)) != CRYPT_OK) { 
+          return errno;
+       }
+   }       
+   XFREE(*pk);
+   *pk = NULL;
+   return CRYPT_OK;
+}
+
+static unsigned long _write(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr)
+{
+#ifdef NO_FILE
+   return 0;
+#else
+   _ARGCHK(buf != NULL);
+   _ARGCHK(f   != NULL);
+   if (ctr != NULL) {
+      if (ctr_encrypt(buf, buf, len, ctr) != CRYPT_OK) {
+         return 0;
+      }
+   }
+   return fwrite(buf, 1, len, f);
+#endif
+}
+
+static unsigned long _read(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr)
+{
+#ifdef NO_FILE
+    return 0;
+#else
+   unsigned long y;
+   _ARGCHK(buf != NULL);
+   _ARGCHK(f   != NULL);
+   y = fread(buf, 1, len, f);
+   if (ctr != NULL) {
+      if (ctr_decrypt(buf, buf, y, ctr) != CRYPT_OK) {
+         return 0;
+      }
+   }
+   return y;
+#endif
+}
+
+int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen)
+{
+   unsigned char buf[8192], *obuf;
+   pk_key *ppk;
+   unsigned long len;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* find the desired key */
+   ppk = kr_find(pk, ID);
+   if (ppk == NULL) {
+      return CRYPT_PK_NOT_FOUND;
+   }
+
+   if (ppk->key_type == PK_PUBLIC && key_type != PK_PUBLIC) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* this makes PK_PRIVATE an alias for PK_PRIVATE_OPTIMIZED type */
+   if (ppk->key_type == PK_PRIVATE_OPTIMIZED && key_type == PK_PRIVATE) {
+      key_type = PK_PRIVATE_OPTIMIZED;
+   }
+
+   /* now copy the header and various other details */
+   memcpy(buf, key_magic, 4);                              /* magic info */
+   buf[4] = key_type;                                      /* key type */
+   buf[5] = ppk->system;                                   /* system */
+   STORE32L(ppk->ID, buf+6);                               /* key ID */
+   memcpy(buf+10, ppk->name, MAXLEN);                      /* the name */
+   memcpy(buf+10+MAXLEN, ppk->email, MAXLEN);              /* the email */
+   memcpy(buf+10+MAXLEN+MAXLEN, ppk->description, MAXLEN); /* the description */
+   
+   /* export key */
+   len = sizeof(buf) - (6 + 4 + MAXLEN*3);
+   obuf = buf+6+4+MAXLEN*3;
+   switch (ppk->system) {
+       case RSA_KEY:
+           if ((errno = rsa_export(obuf, &len, key_type, &(ppk->key.rsa))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case DH_KEY:
+           if ((errno = dh_export(obuf, &len, key_type, &(ppk->key.dh))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case ECC_KEY:
+           if ((errno = ecc_export(obuf, &len, key_type, &(ppk->key.ecc))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+   }
+
+   /* get the entire length of the packet */
+   len += 6 + 4 + 3*MAXLEN;
+
+   if (*outlen < len) {
+      #ifdef CLEAN_STACK
+          zeromem(buf, sizeof(buf));
+      #endif
+      return CRYPT_BUFFER_OVERFLOW;
+   } else {
+      *outlen = len;
+      memcpy(out, buf, len);
+      #ifdef CLEAN_STACK
+          zeromem(buf, sizeof(buf));
+      #endif
+      return CRYPT_OK;
+   }
+}
+
+int kr_import(pk_key *pk, const unsigned char *in)
+{
+   _pk_key key;
+   int system, key_type, errno;
+   unsigned long ID;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+
+   if (memcmp(in, key_magic, 4)) {
+      return CRYPT_INVALID_PACKET;
+   }
+   key_type = in[4];                                 /* get type */
+   system   = in[5];                                 /* get system */
+   LOAD32L(ID,in+6);                                 /* the ID */
+
+   if (ID != kr_crc(in+10, in+10+MAXLEN, in+10+MAXLEN+MAXLEN)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   zeromem(&key, sizeof(key));
+   switch (system) {
+        case RSA_KEY:
+            if ((errno = rsa_import(in+10+3*MAXLEN, &(key.rsa))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case DH_KEY:
+            if ((errno = dh_import(in+10+3*MAXLEN, &(key.dh))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case ECC_KEY:
+            if ((errno = ecc_import(in+10+3*MAXLEN, &(key.ecc))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+   }
+   return kr_add(pk, key_type, system, 
+                 in+10,                           /* the name */
+                 in+10+MAXLEN,                    /* email address */
+                 in+10+MAXLEN+MAXLEN,             /* description */
+                 &key);
+}
+
+
+int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr)
+{
+   unsigned char buf[8192], blen[4];
+   unsigned long len;
+   int res, errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+
+   /* init keyring */
+   if ((errno = kr_init(pk)) != CRYPT_OK) { 
+      return errno; 
+   }
+
+   /* read in magic bytes */
+   if (_read(buf, 6, in, ctr) != 6)           { goto done2; }
+
+   if (memcmp(buf, file_magic, 4)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   len = (unsigned long)buf[4] | ((unsigned long)buf[5] << 8);
+   if (len > CRYPT) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* while there are lengths to read... */
+   while (_read(blen, 4, in, ctr) == 4) {
+      /* get length */
+      LOAD32L(len, blen);
+
+      if (len > sizeof(buf)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      if (_read(buf, len, in, ctr) != len)           { goto done2; }
+      if ((errno = kr_import(*pk, buf)) != CRYPT_OK) { 
+         return errno; 
+      }
+   }
+
+   res = CRYPT_OK;
+   goto done;
+done2:
+   res = CRYPT_ERROR;
+done:
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return res;
+}
+
+int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr)
+{
+   unsigned char buf[8192], blen[4];
+   unsigned long len;
+   int res, errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(out != NULL);
+
+   /* write out magic bytes */
+   memcpy(buf, file_magic, 4);
+   buf[4] = CRYPT&255;
+   buf[5] = (CRYPT>>8)&255;
+   if (_write(buf, 6, out, ctr) != 6)           { goto done2; }
+
+   while (pk->system != NON_KEY) {
+         len = sizeof(buf);
+         if ((errno = kr_export(pk, pk->ID, pk->key_type, buf, &len)) != CRYPT_OK) { 
+            return errno;
+         }
+          
+         STORE32L(len, blen);
+         if (_write(blen, 4, out, ctr) != 4)    { goto done2; }
+         if (_write(buf, len, out, ctr) != len) { goto done2; }
+
+         pk = pk->next;
+   }
+         
+   res = CRYPT_OK;
+   goto done;
+done2:
+   res = CRYPT_ERROR;
+done:
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return res;
+}
+
+int kr_make_key(pk_key *pk, prng_state *prng, int wprng, 
+                int system, int keysize, const unsigned char *name,
+                const unsigned char *email, const unsigned char *description)
+{
+   _pk_key key;
+   int key_type, errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(name != NULL);
+   _ARGCHK(email != NULL);
+   _ARGCHK(description != NULL);
+
+   /* valid PRNG? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* make the key first */
+   zeromem(&key, sizeof(key));
+   switch (system) {
+      case RSA_KEY: 
+          if ((errno = rsa_make_key(prng, wprng, keysize, 65537, &(key.rsa))) != CRYPT_OK) {
+             return errno;
+          }
+          key_type = key.rsa.type;
+          break;
+      case DH_KEY: 
+          if ((errno = dh_make_key(prng, wprng, keysize, &(key.dh))) != CRYPT_OK) {
+             return errno;
+          }
+          key_type = key.dh.type;
+          break;
+      case ECC_KEY: 
+          if ((errno = ecc_make_key(prng, wprng, keysize, &(key.ecc))) != CRYPT_OK) {
+             return errno;
+          }
+          key_type = key.ecc.type;
+          break;
+      default:
+          return CRYPT_PK_INVALID_SYSTEM;
+   }
+
+   /* now add the key */
+   if ((errno = kr_add(pk, key_type, system, name, email, description, &key)) != CRYPT_OK) {
+      return errno;
+   }
+
+#ifdef CLEAN_STACK
+   zeromem(&key, sizeof(key));
+#endif
+   return CRYPT_OK;
+}
+
+int kr_encrypt_key(pk_key *pk, unsigned long ID, 
+                   const unsigned char *in, unsigned long inlen,
+                   unsigned char *out, unsigned long *outlen,
+                   prng_state *prng, int wprng, int hash)
+{
+   unsigned char buf[8192];
+   unsigned long len;
+   pk_key *kr;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* find the key */
+   kr = kr_find(pk, ID);
+   if (kr == NULL) {
+      return CRYPT_PK_NOT_FOUND;
+   }
+
+   /* store the header */
+   memcpy(buf, enc_magic, 4);
+
+   /* now store the ID */
+   STORE32L(kr->ID,buf+4);
+
+   /* now encrypt it */
+   len = sizeof(buf)-8;
+   switch (kr->system) {
+        case RSA_KEY:
+            if ((errno = rsa_encrypt_key(in, inlen, buf+8, &len, prng, wprng, &(kr->key.rsa))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case DH_KEY:
+            if ((errno = dh_encrypt_key(in, inlen, buf+8, &len, prng, wprng, hash, &(kr->key.dh))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case ECC_KEY:
+            if ((errno = ecc_encrypt_key(in, inlen, buf+8, &len, prng, wprng, hash, &(kr->key.ecc))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+    }
+    len += 8;
+
+    if (len > *outlen) {
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       return CRYPT_BUFFER_OVERFLOW;
+    } else {
+       memcpy(out, buf, len);
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       *outlen = len;
+       return CRYPT_OK;
+    }
+}
+
+int kr_decrypt_key(pk_key *pk, const unsigned char *in,
+                   unsigned char *out, unsigned long *outlen)
+{
+   unsigned char buf[8192];
+   unsigned long len, ID;
+   pk_key *kr;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* check magic header */
+   if (memcmp(in, enc_magic, 4)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* now try to find key */
+   LOAD32L(ID,in+4);
+   kr = kr_find(pk, ID);
+   if (kr == NULL) {
+      return CRYPT_PK_NOT_FOUND;
+   }
+
+   /* is it public? */
+   if (kr->key_type == PK_PUBLIC) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* now try and decrypt it */
+   len = sizeof(buf);
+   switch (kr->system) {
+       case RSA_KEY:
+           if ((errno = rsa_decrypt_key(in+8, buf, &len, &(kr->key.rsa))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case DH_KEY:
+           if ((errno = dh_decrypt_key(in+8, buf, &len, &(kr->key.dh))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case ECC_KEY:
+           if ((errno = ecc_decrypt_key(in+8, buf, &len, &(kr->key.ecc))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+   }
+
+    if (len > *outlen) {
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       return CRYPT_BUFFER_OVERFLOW;
+    } else {
+       memcpy(out, buf, len);
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       *outlen = len;
+       return CRYPT_OK;
+    }
+}
+
+int kr_sign_hash(pk_key *pk, unsigned long ID, 
+                 const unsigned char *in, unsigned long inlen,
+                 unsigned char *out, unsigned long *outlen,
+                 prng_state *prng, int wprng)
+{
+   unsigned char buf[8192];
+   unsigned long len;
+   pk_key *kr;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* find the key */
+   kr = kr_find(pk, ID);
+   if (kr == NULL) {
+      return CRYPT_PK_NOT_FOUND;
+   }
+
+   /* is it public? */
+   if (kr->key_type == PK_PUBLIC) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* store the header */
+   memcpy(buf, sign_magic, 4);
+
+   /* now store the ID */
+   STORE32L(kr->ID,buf+4);
+
+   /* now sign it */
+   len = sizeof(buf)-12;
+   switch (kr->system) {
+        case RSA_KEY:
+            if ((errno = rsa_sign_hash(in, inlen, buf+12, &len, &(kr->key.rsa))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case DH_KEY:
+            if ((errno = dh_sign_hash(in, inlen, buf+12, &len, prng, wprng, &(kr->key.dh))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+        case ECC_KEY:
+            if ((errno = ecc_sign_hash(in, inlen, buf+12, &len, prng, wprng, &(kr->key.ecc))) != CRYPT_OK) {
+               return errno;
+            }
+            break;
+    }
+    STORE32L(inlen,buf+8);
+    len += 12;
+
+    if (len > *outlen) {
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       return CRYPT_BUFFER_OVERFLOW;
+    } else {
+       memcpy(out, buf, len);
+       #ifdef CLEAN_STACK
+           zeromem(buf, sizeof(buf));
+       #endif
+       *outlen = len;
+       return CRYPT_OK;
+    }
+}
+
+int kr_verify_hash(pk_key *pk, const unsigned char *in, const unsigned char *hash, 
+                   unsigned long hashlen, int *stat)
+{
+   unsigned long inlen, ID;
+   pk_key *kr;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(in != NULL);
+   _ARGCHK(hash != NULL);
+   _ARGCHK(stat != NULL);
+
+   /* default to not match */
+   *stat = 0;
+
+   /* check magic header */
+   if (memcmp(in, sign_magic, 4)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* now try to find key */
+   LOAD32L(ID,in+4);
+   kr = kr_find(pk, ID);
+   if (kr == NULL) {
+      return CRYPT_PK_NOT_FOUND;
+   }
+
+   /* now try and verify it */
+   LOAD32L(inlen,in+8);         /* this is the length of the original inlen */
+   if (inlen != hashlen) {      /* size doesn't match means the signature is invalid */
+      return CRYPT_OK;
+   }
+
+   switch (kr->system) {
+       case RSA_KEY:
+           if ((errno = rsa_verify_hash(in+12, hash, stat, &(kr->key.rsa))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case DH_KEY:
+           if ((errno = dh_verify_hash(in+12, hash, inlen, stat, &(kr->key.dh))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+       case ECC_KEY:
+           if ((errno = ecc_verify_hash(in+12, hash, inlen, stat, &(kr->key.ecc))) != CRYPT_OK) {
+              return errno;
+           }
+           break;
+   }
+   return CRYPT_OK;
+}
+
+int kr_fingerprint(pk_key *pk, unsigned long ID, int hash,
+                   unsigned char *out, unsigned long *outlen)
+{
+   unsigned char buf[8192];
+   unsigned long len;
+   int errno;
+
+   _ARGCHK(pk != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* valid hash? */
+   if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   len = sizeof(buf);
+   if ((errno = kr_export(pk, ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) {
+      return errno;
+   }
+   
+   /* now hash it */
+   if ((errno = hash_memory(hash, buf, len, out, outlen)) != CRYPT_OK) {
+      return errno;
+   }
+
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+

+ 262 - 0
makefile

@@ -0,0 +1,262 @@
+# MAKEFILE for linux GCC
+#
+# Tom St Denis
+# Modified by Clay Culver
+#
+# NOTE: This should later be replaced by autoconf/automake scripts, but for
+# the time being this is actually pretty clean. The only ugly part is
+# handling CFLAGS so that the x86 specific optimizations don't break
+# a build. This is easy to remedy though, for those that have problems.
+
+# The version
+VERSION=0.75
+
+#Compiler and Linker Names
+CC=gcc
+LD=ld
+
+#Archiver [makes .a files]
+AR=ar
+ARFLAGS=rs
+
+#here you can set the malloc/calloc/free functions you want
+XMALLOC=malloc
+XCALLOC=calloc
+XFREE=free
+
+#you can redefine the clock
+XCLOCK=clock
+XCLOCKS_PER_SEC=CLOCKS_PER_SEC
+
+#Compilation flags. Note the += does not write over the user's CFLAGS!
+CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror  \
+   -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) -DXCLOCK=$(XCLOCK) \
+   -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC)
+
+#optimize for SPEED (comment out SIZE/DEBUG line as well)
+#CFLAGS += -O3 -fomit-frame-pointer -funroll-loops
+
+#optimize for SIZE (comment out SPEED/DEBUG line as well)
+CFLAGS += -O2
+
+#compile for DEBUGGING 
+#CFLAGS += -g3
+
+#These flags control how the library gets built.
+
+#no file support, when defined the library will not have any functions that can read/write files 
+#(comment out to have file support)
+#CFLAGS += -DNO_FILE
+
+#Support the UNIX /dev/random or /dev/urandom
+CFLAGS += -DDEVRANDOM
+
+# Use /dev/urandom first on devices where /dev/random is too slow */
+#CFLAGS += -DTRY_URANDOM_FIRST
+
+# Clean the stack after sensitive functions.  Not always required... 
+# With this defined most of the ciphers and hashes will clean their stack area
+# after usage with a (sometimes) huge penalty in speed.  Normally this is not
+# required if you simply lock your stack and wipe it when your program is done.
+#
+#CFLAGS += -DCLEAN_STACK
+
+# What algorithms to include? comment out and rebuild to remove em
+CFLAGS += -DBLOWFISH
+CFLAGS += -DRC2
+CFLAGS += -DRC5
+CFLAGS += -DRC6
+CFLAGS += -DSERPENT
+CFLAGS += -DSAFERP
+CFLAGS += -DSAFER
+CFLAGS += -DRIJNDAEL
+CFLAGS += -DXTEA
+CFLAGS += -DTWOFISH
+CFLAGS += -DDES
+CFLAGS += -DCAST5
+
+#You can also customize the Twofish code.  All four combinations 
+#of the flags are possible but only three of them make sense.
+#
+#Both undefined:  Very fast, requires ~4.2KB of ram per scheduled key
+#Both defined  :  Slow, requires only ~100 bytes of ram per scheduled key
+#
+#If defined on their own
+#_SMALL defined:  Very Slow, small code only ~100 bytes of ram
+#_TABLES defined: Very fast, not faster than if both were undefined.  Code is ~1KB bigger
+#                 faster keysetup though...
+
+# Small Ram Variant of Twofish.  For this you must have TWOFISH defined.  This
+# variant requires about 4kb less memory but is considerably slower.  It is ideal
+# when high throughput is less important than conserving memory. By default it is
+# not defined which means the larger ram (about 4.2Kb used) variant is built.
+#CFLAGS += -DTWOFISH_SMALL
+
+# Tell Twofish to use precomputed tables.  If you want to use the small table
+# variant of Twofish you may want to turn this on.  Essentially it tells Twofish to use
+# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS].
+# This speeds up the cipher somewhat.
+#CFLAGS += -DTWOFISH_TABLES 
+
+#Small code variant of the SAFER+ cipher, uses same RAM but less code space
+#With this defined the cipher is slower.  On my x86 with GCC 3.2 it required 50KB less space
+CFLAGS += -DSAFERP_SMALL
+
+#Small Rijndael [saves 13KB on an x86]
+#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP)
+CFLAGS += -DRIJNDAEL_SMALL
+
+#Use fast PK routines.  Basically this limits the size of the private key in the
+#DH system to 256 bits.  The group order remains unchanged so the best
+#attacks are still GNFS (for DH upto 2560-bits)
+#
+#This will only speed up the key generation and encryption routines.  It lowers the
+#security so its by default not turned on.  USE AT YOUR RISK!
+#CFLAGS += -DFAST_PK
+
+#Include the PK Packet functions (e.g. dh_encrypt)
+#Does not affect the key/hash routines (e.g. ecc_sign_hash)
+#CFLAGS += -DPK_PACKET
+
+# Chaining modes
+CFLAGS += -DCFB
+CFLAGS += -DOFB
+CFLAGS += -DECB
+CFLAGS += -DCBC
+CFLAGS += -DCTR
+
+#One-way hashes
+CFLAGS += -DSHA512
+CFLAGS += -DSHA384
+CFLAGS += -DSHA256
+CFLAGS += -DTIGER
+CFLAGS += -DSHA1
+CFLAGS += -DMD5
+CFLAGS += -DMD4
+CFLAGS += -DMD2
+
+# base64 
+CFLAGS += -DBASE64
+
+# prngs 
+CFLAGS += -DYARROW
+CFLAGS += -DSPRNG
+CFLAGS += -DRC4
+
+# PK code 
+CFLAGS += -DMRSA
+CFLAGS += -DMDH
+CFLAGS += -DMECC
+CFLAGS += -DKR
+
+# include GF math routines?  (not currently used by anything internally)
+#CFLAGS += -DGF
+
+# include large integer math routines? (required by the PK code)
+CFLAGS += -DMPI
+
+# Use a small prime table?  It greatly reduces the size of prime.c at a little impact
+# in speed.
+#
+CFLAGS += -DSMALL_PRIME_TAB
+
+# include HMAC support
+CFLAGS += -DHMAC
+
+#Output filenames for various targets.
+LIBNAME=libtomcrypt.a
+TEST=test
+HASH=hashsum
+CRYPT=encrypt
+SMALL=small
+
+#LIBPATH-The directory for libtomcrypt to be installed to.
+#INCPATH-The directory to install the header files for libtomcrypt.
+LIBPATH=/usr/lib
+INCPATH=/usr/include
+
+#List of objects to compile.
+OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \
+bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \
+md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \
+safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \
+ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o
+
+TESTOBJECTS=demos/test.o
+HASHOBJECTS=demos/hashsum.o
+CRYPTOBJECTS=demos/encrypt.o
+SMALLOBJECTS=demos/small.o
+
+#Files left over from making the crypt.pdf.
+LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind
+
+#Compressed filenames
+COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz
+
+#Header files used by libtomcrypt.
+HEADERS=mpi-types.h mpi-config.h mpi.h \
+mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \
+mycrypt_misc.h  mycrypt_prng.h mycrypt_cipher.h  mycrypt_hash.h \
+mycrypt_macros.h  mycrypt_pk.h mycrypt.h mycrypt_argchk.h
+
+#The default rule for make builds the libtomcrypt library.
+default:library mycrypt.h mycrypt_cfg.h
+
+#These are the rules to make certain object files.
+rsa.o: rsa.c rsa_sys.c
+ecc.o: ecc.c ecc_sys.c
+dh.o: dh.c dh_sys.c
+aes.o: aes.c aes_tab.c
+sha512.o: sha512.c sha384.c
+
+#This rule makes the libtomcrypt library.
+library: $(OBJECTS) 
+	$(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS)
+
+#This rule makes the test program included with libtomcrypt
+test: library $(TESTOBJECTS)
+	$(CC) $(TESTOBJECTS) $(LIBNAME) -o $(TEST) $(WARN)
+
+#This rule makes the hash program included with libtomcrypt
+hashsum: library $(HASHOBJECTS)
+	$(CC) $(HASHOBJECTS) $(LIBNAME) -o $(HASH) $(WARN)
+
+#makes the crypt program
+crypt: library $(CRYPTOBJECTS)
+	$(CC) $(CRYPTOBJECTS) $(LIBNAME) -o $(CRYPT) $(WARN)
+
+#makes the small program
+small: library $(SMALLOBJECTS)
+	$(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN)
+
+#This rule installs the library and the header files. This must be run
+#as root in order to have a high enough permission to write to the correct
+#directories and to set the owner and group to root.
+install: library
+	install -g root -o root $(LIBNAME) $(LIBPATH)
+	install -g root -o root $(HEADERS) $(INCPATH)
+
+#This rule cleans the source tree of all compiled code, not including the pdf
+#documentation.
+clean:
+	rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME)
+	rm -f $(TEST) $(HASH) $(COMPRESSED)
+	rm -f *stackdump *.lib *.exe *.obj demos/*.obj zlib/*.obj *.bat
+
+#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed
+#from the clean command! This is because most people would like to keep the
+#nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to
+#delete it if we are rebuilding it.
+docs: crypt.tex
+	rm -f crypt.pdf
+	rm -f $(LEFTOVERS)
+	latex crypt > /dev/null
+	makeindex crypt > /dev/null
+	pdflatex crypt > /dev/null
+	rm -f $(LEFTOVERS)
+
+#zipup the project (take that!)
+zipup: clean docs
+	chdir .. ; rm -rf crypt* libtomcrypt-$(VERSION) ; mkdir libtomcrypt-$(VERSION) ; \
+	cp -R ./libtomcrypt/* ./libtomcrypt-$(VERSION)/ ; tar -c libtomcrypt-$(VERSION)/* > crypt-$(VERSION).tar ; \
+	bzip2 -9vv crypt-$(VERSION).tar ; zip -9 -r crypt-$(VERSION).zip libtomcrypt-$(VERSION)/*

+ 293 - 0
makefile.ps2

@@ -0,0 +1,293 @@
+# MAKEFILE for linux GCC
+#
+# Tom St Denis
+# Modified by Clay Culver
+#
+# NOTE: This should later be replaced by autoconf/automake scripts, but for
+# the time being this is actually pretty clean. The only ugly part is
+# handling CFLAGS so that the x86 specific optimizations don't break
+# a build. This is easy to remedy though, for those that have problems.
+
+#Compiler and Linker Names
+CC=ee-gcc
+LD=ee-ld
+
+# PlayStation(tm) 2 specifics
+TOP       = /usr/local/sce/ee
+LIBDIR    = $(TOP)/lib
+INCDIR    = $(TOP)/include/
+COMMONDIR = $(TOP)/../common/include/
+LCFILE    = $(LIBDIR)/app.cmd
+LDFLAGS   = -DSONY_PS2 -DSONY_PS2_EE -Wl,-Map,$(@).map -mno-crt0 -L$(LIBDIR) -lm
+AS        = ee-gcc
+ASFLAGS   = -DSONY_PS2 -DSONY_PS2_EE -c -xassembler-with-cpp -Wa,-al
+EXT       = .elf
+CFLAGS   += -DSONY_PS2 -DSONY_PS2_EE -Wa,-al -Wno-unused -Werror \
+		-fno-common -fno-strict-aliasing -I$(INCDIR) -I$(COMMONDIR)
+
+#Archiver [makes .a files]
+AR=ee-ar
+ARFLAGS=rs
+
+#here you can set the malloc/calloc/free functions you want
+XMALLOC=malloc
+XCALLOC=calloc
+XFREE=free
+
+#you can redefine the clock
+XCLOCK=TIMER_clock
+XCLOCKS_PER_SEC=576000
+
+#Compilation flags. Note the += does not write over the user's CFLAGS!
+CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror  \
+   -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) -DXCLOCK=$(XCLOCK) \
+   -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC)
+
+#no file support, when defined the library will not have any functions that can read/write files 
+#(comment out to have file support)
+CFLAGS += -DNO_FILE
+
+#optimize for SPEED (comment out SIZE line as well)
+#CFLAGS += -O3 -fomit-frame-pointer -funroll-loops
+
+#optimize for SIZE (comment out SPEED line as well)
+CFLAGS += -O2
+
+#These flags control how the library gets built.
+
+# Clean the stack after sensitive functions.  Not always required... 
+# With this defined most of the ciphers and hashes will clean their stack area
+# after usage with a (sometimes) huge penalty in speed.  Normally this is not
+# required if you simply lock your stack and wipe it when your program is done.
+#
+#CFLAGS += -DCLEAN_STACK
+
+# What algorithms to include? comment out and rebuild to remove em
+CFLAGS += -DBLOWFISH
+CFLAGS += -DRC2
+#CFLAGS += -DRC5
+#CFLAGS += -DRC6
+CFLAGS += -DSERPENT
+CFLAGS += -DSAFERP
+CFLAGS += -DSAFER
+CFLAGS += -DRIJNDAEL
+CFLAGS += -DXTEA
+CFLAGS += -DTWOFISH
+CFLAGS += -DDES
+CFLAGS += -DCAST5
+
+#You can also customize the Twofish code.  All four combinations 
+#of the flags are possible but only three of them make sense.
+#
+#Both undefined:  Very fast, requires ~4.2KB of ram per scheduled key
+#Both defined  :  Slow, requires only ~100 bytes of ram per scheduled key
+#
+#If defined on their own
+#_SMALL defined:  Very Slow, small code only ~100 bytes of ram
+#_TABLES defined: Very fast, not faster than if both were undefined.  Code is ~1KB bigger
+#                 faster keysetup though...
+
+# Small Ram Variant of Twofish.  For this you must have TWOFISH defined.  This
+# variant requires about 4kb less memory but is considerably slower.  It is ideal
+# when high throughput is less important than conserving memory. By default it is
+# not defined which means the larger ram (about 4.2Kb used) variant is built.
+# CFLAGS += -DTWOFISH_SMALL
+
+# Tell Twofish to use precomputed tables.  If you want to use the small table
+# variant of Twofish you may want to turn this on.  Essentially it tells Twofish to use
+# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS].
+# This speeds up the cipher somewhat.
+# CFLAGS += -DTWOFISH_TABLES 
+
+#Small code variant of the SAFER+ cipher, uses same RAM but less code space
+#With this defined the cipher is slower.  On my x86 with GCC 3.2 it required 50KB less space
+CFLAGS += -DSAFERP_SMALL
+
+#Small Rijndael [saves 13KB on an x86]
+#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP)
+CFLAGS += -DRIJNDAEL_SMALL
+
+#Use fast PK routines.  Basically this limits the size of the private key in the
+#DH system to 256 bits.  The group order remains unchanged so the best
+#attacks are still GNFS (for DH upto 2560-bits)
+#
+#This will only speed up the key generation and encryption routines.  It lowers the
+#security so its by default not turned on.  USE AT YOUR RISK!
+#CFLAGS += -DFAST_PK
+
+#Include the PK Packet functions (e.g. dh_encrypt)
+#Does not affect the key/hash routines (e.g. ecc_sign_hash)
+#CFLAGS += -DPK_PACKET
+
+# Chaining modes
+CFLAGS += -DCFB
+CFLAGS += -DOFB
+CFLAGS += -DECB
+CFLAGS += -DCBC
+CFLAGS += -DCTR
+
+#One-way hashes
+CFLAGS += -DSHA512
+CFLAGS += -DSHA384
+CFLAGS += -DSHA256
+CFLAGS += -DTIGER
+CFLAGS += -DSHA1
+CFLAGS += -DMD5
+CFLAGS += -DMD4
+CFLAGS += -DMD2
+
+# base64 
+CFLAGS += -DBASE64
+
+# prngs 
+CFLAGS += -DYARROW
+CFLAGS += -DSPRNG
+CFLAGS += -DRC4
+
+# PK code 
+CFLAGS += -DMRSA
+CFLAGS += -DMDH
+CFLAGS += -DMECC
+CFLAGS += -DKR
+
+# include GF math routines?  (not currently used by anything internally)
+#CFLAGS += -DGF
+
+# include large integer math routines? (required by the PK code)
+CFLAGS += -DMPI
+
+# Use a small prime table?  It greatly reduces the size of prime.c at a little impact
+# in speed.
+#
+CFLAGS += -DSMALL_PRIME_TAB
+
+# include HMAC support
+CFLAGS += -DHMAC
+
+# Have /dev/random or /dev/urandom?
+#CFLAGS += -DDEVRANDOM
+
+#Output filenames for various targets.
+LIBNAME=libtomcrypt.a
+TEST=test$(EXT)
+HASH=hashsum$(EXT)
+CRYPT=encrypt$(EXT)
+SMALL=small$(EXT)
+
+#LIBPATH-The directory for libtomcrypt to be installed to.
+#INCPATH-The directory to install the header files for libtomcrypt.
+LIBPATH=/usr/lib
+INCPATH=/usr/include
+
+#List of objects to compile.
+OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \
+bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \
+md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \
+safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \
+ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o
+
+# PlayStation(tm) 2 C run-time startup module
+PS2CRT0=crt0.o
+
+TESTOBJECTS=$(PS2CRT0) demos/test.o demos/timer.o
+HASHOBJECTS=$(PS2CRT0) demos/hashsum.o
+CRYPTOBJECTS=$(PS2CRT0) demos/encrypt.o
+SMALLOBJECTS=$(PS2CRT0) demos/small.o
+
+#Files left over from making the crypt.pdf.
+LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind
+
+#Compressed filenames
+COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz
+
+#Header files used by libtomcrypt.
+HEADERS=mpi-types.h mpi-config.h mpi.h \
+mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \
+mycrypt_misc.h  mycrypt_prng.h mycrypt_cipher.h  mycrypt_hash.h \
+mycrypt_macros.h  mycrypt_pk.h mycrypt.h mycrypt_argchk.h
+
+#The default rule for make builds the libtomcrypt library.
+default:library mycrypt.h mycrypt_cfg.h
+
+#These are the rules to make certain object files.
+rsa.o: rsa.c rsa_sys.c
+ecc.o: ecc.c ecc_sys.c
+dh.o: dh.c dh_sys.c
+aes.o: aes.c aes_tab.c
+sha512.o: sha512.c sha384.c
+
+#This rule makes the libtomcrypt library.
+library: $(OBJECTS) 
+	$(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS)
+
+#This rule makes the test program included with libtomcrypt
+test: library $(TESTOBJECTS)
+	$(CC) -o $(TEST) -T $(LCFILE) $(LDFLAGS) $(TESTOBJECTS) $(LIBNAME) 
+
+#This rule makes the hash program included with libtomcrypt
+hashsum: library $(HASHOBJECTS)
+	$(CC) -o $(HASH) -T $(LCFILE) $(LDFLAGS) $(HASHOBJECTS) $(LIBNAME)
+
+#makes the crypt program
+crypt: library $(CRYPTOBJECTS)
+	$(CC) -o $(CRYPT) -T $(LCFILE) $(LDFLAGS) $(CRYPTOBJECTS) $(LIBNAME)
+
+#makes the small program
+small: library $(SMALLOBJECTS)
+	$(CC) -o $(SMALL) -T $(LCFILE) $(LDFLAGS) $(SMALLOBJECTS) $(LIBNAME)
+
+# makes the PlayStation(tm) 2 CRT 0 module
+$(PS2CRT0): $(LIBDIR)/crt0.s
+	$(AS) $(ASFLAGS) $(TMPFLAGS) -o $@ $< > $*.lst
+
+#This rule installs the library and the header files. This must be run
+#as root in order to have a high enough permission to write to the correct
+#directories and to set the owner and group to root.
+install: library
+	install -g root -o root $(LIBNAME) $(LIBPATH)
+	install -g root -o root $(HEADERS) $(INCPATH)
+
+#This rule cleans the source tree of all compiled code, not including the pdf
+#documentation.
+clean:
+	rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME)
+	rm -f $(TEST) $(HASH) $(COMPRESSED)
+	rm -f *stackdump *.lib *.exe *.obj demos/*.obj zlib/*.obj
+	rm -f *.o *.lst demos/*.o demos/*.lst
+
+#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed
+#from the clean command! This is because most people would like to keep the
+#nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to
+#delete it if we are rebuilding it.
+docs: crypt.tex
+	rm -f crypt.pdf
+	rm -f $(LEFTOVERS)
+	latex crypt > /dev/null
+	makeindex crypt > /dev/null
+	pdflatex crypt > /dev/null
+	rm -f $(LEFTOVERS)
+
+#This used to be the zipup target. I have split it into two seperate targets:
+#bz and zip. bz builds a crypt.tar.bz2 package, while zip builds a crypt.zip
+#package. I have removed the dos2unix commands, as this is a Linux makefile,
+#and these should not be needed. I also made it output the target to the
+#current directory instead of the root (/) directory. (Bad Tom!) We are
+#almost assured write permission in the current directory, but not in the root
+#directory. This means any user can now build a BZ image or a zip.
+#NOTE: This removes all pre-built compressed archives during clean.
+bz: clean docs
+	chdir .. ; rm -f crypt.tar.bz2 ; tar -c libtomcrypt/* > crypt.tar ; bzip2 -9v crypt.tar
+
+zip: clean docs
+	chdir .. ; rm -f crypt.zip ; zip -9 -r crypt.zip libtomcrypt/*
+
+#Makes a tar/gz archive of the library.
+gz: clean docs
+	chdir .. ; rm -f crypt.tar.gz ; tar -c libtomcrypt/* > crypt.tar ; gzip -9v crypt.tar
+
+#makes a tar/SZIP archive [slightly better than bzip2]
+szip: clean docs
+	chdir .. ; rm -f crypt.tar.szp ; tar -c libtomcrypt/* > crypt.tar ; szip -b41o64v255 crypt.tar crypt.tar.szp
+
+.c.o:
+	$(CC) $(CFLAGS) $(TMPFLAGS) -c $< -o $*.o > $*.lst

+ 254 - 0
makefile.vc

@@ -0,0 +1,254 @@
+# MAKEFILE for MSVC 6.0 SP5
+#
+# Tom St Denis, [email protected]
+#
+CC=cl
+AR=lib
+
+#here you can set the malloc/calloc/free functions you want
+XMALLOC=malloc
+XCALLOC=calloc
+XFREE=free
+
+#you can redefine the clock
+XCLOCK=clock
+XCLOCKS_PER_SEC=CLOCKS_PER_SEC
+
+CFLAGS = /c /Ogisy1 /Gs /I. /W3 /DWIN32 /DXMALLOC=$(XMALLOC) /DXCALLOC=$(XCALLOC) /DXFREE=$(XFREE) /DXCLOCK=$(XCLOCK) /DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC)
+
+#These flags control how the library gets built.
+
+#no file support, when defined the library will not have any functions that can read/write files 
+#(comment out to have file support)
+#CFLAGS += /DNO_FILE
+
+#Support the UNIX /dev/random or /dev/urandom
+#CFLAGS += /DDEVRANDOM
+
+# Use /dev/urandom first on devices where /dev/random is too slow */
+#CFLAGS += /DTRY_URANDOM_FIRST
+
+# Clean the stack after sensitive functions.  Not always required... 
+# With this defined most of the ciphers and hashes will clean their stack area
+# after usage with a (sometimes) huge penalty in speed.  Normally this is not
+# required if you simply lock your stack and wipe it when your program is done.
+#
+#CFLAGS += /DCLEAN_STACK
+
+# What algorithms to include? comment out and rebuild to remove em
+CFLAGS += /DBLOWFISH
+CFLAGS += /DRC2
+CFLAGS += /DRC5
+CFLAGS += /DRC6
+CFLAGS += /DSERPENT
+CFLAGS += /DSAFERP
+CFLAGS += /DSAFER
+CFLAGS += /DRIJNDAEL
+CFLAGS += /DXTEA
+CFLAGS += /DTWOFISH
+CFLAGS += /DDES
+CFLAGS += /DCAST5
+
+#You can also customize the Twofish code.  All four combinations 
+#of the flags are possible but only three of them make sense.
+#
+#Both undefined:  Very fast, requires ~4.2KB of ram per scheduled key
+#Both defined  :  Slow, requires only ~100 bytes of ram per scheduled key
+#
+#If defined on their own
+#_SMALL defined:  Very Slow, small code only ~100 bytes of ram
+#_TABLES defined: Very fast, not faster than if both were undefined.  Code is ~1KB bigger
+#                 faster keysetup though...
+
+# Small Ram Variant of Twofish.  For this you must have TWOFISH defined.  This
+# variant requires about 4kb less memory but is considerably slower.  It is ideal
+# when high throughput is less important than conserving memory. By default it is
+# not defined which means the larger ram (about 4.2Kb used) variant is built.
+# CFLAGS += /DTWOFISH_SMALL
+
+# Tell Twofish to use precomputed tables.  If you want to use the small table
+# variant of Twofish you may want to turn this on.  Essentially it tells Twofish to use
+# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS].
+# This speeds up the cipher somewhat.
+# CFLAGS += /DTWOFISH_TABLES 
+
+#Small code variant of the SAFER+ cipher, uses same RAM but less code space
+#With this defined the cipher is slower.  On my x86 with GCC 3.2 it required 50KB less space
+CFLAGS += /DSAFERP_SMALL
+
+#Small Rijndael [saves 13KB on an x86]
+#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP)
+CFLAGS += /DRIJNDAEL_SMALL
+
+#Use fast PK routines.  Basically this limits the size of the private key in the
+#DH system to 256 bits.  The group order remains unchanged so the best
+#attacks are still GNFS (for DH upto 2560-bits)
+#
+#This will only speed up the key generation and encryption routines.  It lowers the
+#security so its by default not turned on.  USE AT YOUR RISK!
+#CFLAGS += /DFAST_PK
+
+#Include the PK Packet functions (e.g. dh_encrypt)
+#Does not affect the key/hash routines (e.g. ecc_sign_hash)
+#CFLAGS += /DPK_PACKET
+
+# Chaining modes
+CFLAGS += /DCFB
+CFLAGS += /DOFB
+CFLAGS += /DECB
+CFLAGS += /DCBC
+CFLAGS += /DCTR
+
+#One-way hashes
+CFLAGS += /DSHA512
+CFLAGS += /DSHA384
+CFLAGS += /DSHA256
+CFLAGS += /DTIGER
+CFLAGS += /DSHA1
+CFLAGS += /DMD5
+CFLAGS += /DMD4
+CFLAGS += /DMD2
+
+# base64 
+CFLAGS += /DBASE64
+
+# prngs 
+CFLAGS += /DYARROW
+CFLAGS += /DSPRNG
+CFLAGS += /DRC4
+
+# PK code 
+CFLAGS += /DMRSA
+CFLAGS += /DMDH
+CFLAGS += /DMECC
+CFLAGS += /DKR
+
+# include GF math routines?  (not currently used by anything internally)
+#CFLAGS += /DGF
+
+# include large integer math routines? (required by the PK code)
+CFLAGS += /DMPI
+
+# Use a small prime table?  It greatly reduces the size of prime.c at a little impact
+# in speed.
+#
+CFLAGS += /DSMALL_PRIME_TAB
+
+# include HMAC support
+CFLAGS += /DHMAC
+
+default: tomcrypt.lib
+
+keyring.obj: keyring.c
+	$(CC) $(CFLAGS) keyring.c
+ampi.obj: ampi.c
+	$(CC) $(CFLAGS) ampi.c
+mpi.obj: mpi.c
+	$(CC) $(CFLAGS) mpi.c
+blowfish.obj: blowfish.c
+	$(CC) $(CFLAGS) blowfish.c
+crypt.obj: crypt.c
+	$(CC) $(CFLAGS) crypt.c
+sha512.obj: sha512.c sha384.c
+	$(CC) $(CFLAGS) sha512.c
+sha256.obj: sha256.c
+	$(CC) $(CFLAGS) sha256.c
+hash.obj: hash.c
+	$(CC) $(CFLAGS) hash.c
+md5.obj: md5.c
+	$(CC) $(CFLAGS) md5.c
+md4.obj: md4.c
+	$(CC) $(CFLAGS) md4.c
+sha1.obj: sha1.c
+	$(CC) $(CFLAGS) sha1.c
+cfb.obj: cfb.c
+	$(CC) $(CFLAGS) cfb.c
+ofb.obj: ofb.c
+	$(CC) $(CFLAGS) ofb.c
+ecb.obj: ecb.c
+	$(CC) $(CFLAGS) ecb.c
+ctr.obj: ctr.c
+	$(CC) $(CFLAGS) ctr.c
+prime.obj: prime.c
+	$(CC) $(CFLAGS) prime.c
+base64.obj: base64.c
+	$(CC) $(CFLAGS) base64.c
+sprng.obj: sprng.c
+	$(CC) $(CFLAGS) sprng.c
+mem.obj: mem.c
+	$(CC) $(CFLAGS) mem.c
+gf.obj: gf.c
+	$(CC) $(CFLAGS) gf.c
+ecc.obj: ecc.c ecc_sys.c
+	$(CC) $(CFLAGS) ecc.c
+yarrow.obj: yarrow.c
+	$(CC) $(CFLAGS) yarrow.c
+bits.obj: bits.c
+	$(CC) $(CFLAGS) bits.c
+rsa.obj: rsa.c
+	$(CC) $(CFLAGS) rsa.c
+rc6.obj: rc6.c
+	$(CC) $(CFLAGS) rc6.c
+des.obj: des.c
+	$(CC) $(CFLAGS) des.c
+tiger.obj: tiger.c
+	$(CC) $(CFLAGS) tiger.c
+dh.obj: dh.c dh_sys.c
+	$(CC) $(CFLAGS) dh.c
+serpent.obj: serpent.c
+	$(CC) $(CFLAGS) serpent.c
+aes.obj: aes.c aes_tab.c
+	$(CC) $(CFLAGS) aes.c
+rc5.obj: rc5.c
+	$(CC) $(CFLAGS) rc5.c
+rc2.obj: rc2.c
+	$(CC) $(CFLAGS) rc2.c
+cbc.obj: cbc.c
+	$(CC) $(CFLAGS) cbc.c
+safer+.obj: safer+.c
+	$(CC) $(CFLAGS) safer+.c
+safer.obj: safer.c
+	$(CC) $(CFLAGS) safer.c
+safer_tab.obj: safer_tab.c
+	$(CC) $(CFLAGS) safer_tab.c
+xtea.obj: xtea.c
+	$(CC) $(CFLAGS) xtea.c
+twofish.obj: twofish.c
+	$(CC) $(CFLAGS) twofish.c
+packet.obj: packet.c
+	$(CC) $(CFLAGS) packet.c
+pack.obj: pack.c
+	$(CC) $(CFLAGS) pack.c
+hmac.obj: hmac.c
+	$(CC) $(CFLAGS) hmac.c
+strings.obj: strings.c
+	$(CC) $(CFLAGS) strings.c
+md2.obj: md2.c
+	$(CC) $(CFLAGS) md2.c
+cast5.obj: cast5.c
+	$(CC) $(CFLAGS) cast5.c
+
+demos/test.obj: demos/test.c
+	$(CC) $(CFLAGS) demos/test.c
+
+demos/hashsum.obj: demos/hashsum.c
+	$(CC) $(CFLAGS) demos/hashsum.c
+
+tomcrypt.lib: keyring.obj gf.obj mem.obj sprng.obj ecc.obj  base64.obj dh.obj rsa.obj bits.obj hmac.obj  \
+yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj sha512.obj xtea.obj \
+aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj blowfish.obj crypt.obj ampi.obj \
+strings.obj mpi.obj prime.obj twofish.obj packet.obj
+	$(AR) /out:tomcrypt.lib keyring.obj gf.obj mem.obj sprng.obj ecc.obj  base64.obj dh.obj rsa.obj hmac.obj \
+bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj \
+strings.obj sha512.obj xtea.obj aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj \
+blowfish.obj crypt.obj ampi.obj mpi.obj prime.obj twofish.obj packet.obj
+
+
+test.exe: tomcrypt.lib demos/test.obj
+	link /OUT:test.exe test.obj tomcrypt.lib advapi32.lib
+
+hashsum.exe: tomcrypt.lib demos/hashsum.obj
+	link /OUT:hashsum.exe hashsum.obj tomcrypt.lib advapi32.lib
+
+clean:
+	rm -f demos/*.obj *.obj *.exe *.lib

+ 203 - 0
md2.c

@@ -0,0 +1,203 @@
+/* MD2 (RFC 1319) hash function implementation by Tom St Denis */
+#include "mycrypt.h"
+
+#ifdef MD2
+
+const struct _hash_descriptor md2_desc =
+{
+    "md2",
+    7,
+    16,
+    16,
+    &md2_init,
+    &md2_process,
+    &md2_done,
+    &md2_test
+};
+
+static const unsigned char PI_SUBST[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+/* adds 16 bytes to the checksum */
+static void md2_update_chksum(hash_state *md)
+{
+   int j;
+   unsigned char L;
+   L = md->md2.chksum[15];
+   for (j = 0; j < 16; j++) {
+
+/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say 
+   otherwise.
+*/
+       L = (md->md2.chksum[j] ^= PI_SUBST[md->md2.buf[j] ^ L]);
+   }
+}
+
+static void md2_compress(hash_state *md)
+{
+   int j, k;
+   unsigned char t;
+
+   /* copy block */
+   for (j = 0; j < 16; j++) {
+       md->md2.X[16+j] = md->md2.buf[j];
+       md->md2.X[32+j] = md->md2.X[j] ^ md->md2.X[16+j];
+   }
+
+   t = 0;
+
+   /* do 18 rounds */
+   for (j = 0; j < 18; j++) {
+       for (k = 0; k < 48; k++) {
+           t = (md->md2.X[k] ^= PI_SUBST[t]);
+       }
+       t = (t + j) & 255;
+   }
+}
+
+void md2_init(hash_state *md)
+{
+   _ARGCHK(md != NULL);
+
+   /* MD2 uses a zero'ed state... */
+   zeromem(md->md2.X, sizeof(md->md2.X));
+   zeromem(md->md2.chksum, sizeof(md->md2.chksum));
+   zeromem(md->md2.buf, sizeof(md->md2.buf));
+   md->md2.curlen = 0;
+}
+
+void md2_process(hash_state *md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+    while (len) {
+        n = MIN(len, (16 - md->md2.curlen));
+        memcpy(md->md2.buf + md->md2.curlen, buf, n);
+        md->md2.curlen += n;
+        buf            += n;
+        len            -= n;
+
+        /* is 16 bytes full? */
+        if (md->md2.curlen == 16) {
+            md2_compress(md);
+            md2_update_chksum(md);
+            md->md2.curlen = 0;
+        }
+    }
+}
+
+void md2_done(hash_state * md, unsigned char *hash)
+{
+    int i, k;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* pad the message */
+    k = 16 - md->md2.curlen;
+    for (i = md->md2.curlen; i < 16; i++) {
+        md->md2.buf[i] = k;
+    }
+
+    /* hash and update */
+    md2_compress(md);
+    md2_update_chksum(md);
+
+    /* hash checksum */
+    memcpy(md->md2.buf, md->md2.chksum, 16);
+    md2_compress(md);
+
+    /* output is lower 16 bytes of X */
+    memcpy(hash, md->md2.X, 16);
+
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int md2_test(void)
+{
+   static const struct {
+        unsigned char *msg;
+        unsigned char md[16];
+   } tests[] = {
+      { "",
+        {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,
+         0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73
+        }
+      },
+      { "a",
+        {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,
+         0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1
+        }
+      },
+      { "message digest",
+        {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,
+         0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0
+        }
+      },
+      { "abcdefghijklmnopqrstuvwxyz",
+        {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,
+         0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b
+        }
+      },
+      { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+        {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,
+         0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd
+        }
+      },
+      { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+        {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,
+         0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8
+        }
+      }
+   };
+   int i;
+   hash_state md;
+   unsigned char buf[16];
+
+   for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+       md2_init(&md);
+       md2_process(&md, tests[i].msg, strlen(tests[i].msg));
+       md2_done(&md, buf);
+       if (memcmp(buf, tests[i].md, 16)) {
+#if 0
+          int j;
+          printf("\n\nFailed test %d\n\n", i);
+          for (j = 0; j < 16; j++) {
+              printf("%02x ", buf[j]);
+          }
+          printf("\n");
+          printf("Should have been\n");
+          for (j = 0; j < 16; j++) {
+              printf("%02x ", tests[i].md[j]);
+          }
+          printf("\n");
+#endif
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;        
+}
+
+#endif
+

+ 290 - 0
md4.c

@@ -0,0 +1,290 @@
+/* Submitted by Dobes Vandermeer  ([email protected]) */
+#include "mycrypt.h"
+
+#ifdef MD4
+
+const struct _hash_descriptor md4_desc =
+{
+    "md4",
+    6,
+    16,
+    64,
+    &md4_init,
+    &md4_process,
+    &md4_done,
+    &md4_test
+};
+
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+/* F, G and H are basic MD4 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) ROL(x, n)
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ 
+/* Rotation is separate from addition to prevent recomputation */ 
+
+#define FF(a, b, c, d, x, s) { \
+    (a) += F ((b), (c), (d)) + (x); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define GG(a, b, c, d, x, s) { \
+    (a) += G ((b), (c), (d)) + (x) + 0x5a827999UL; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define HH(a, b, c, d, x, s) { \
+    (a) += H ((b), (c), (d)) + (x) + 0x6ed9eba1UL; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+
+#ifdef CLEAN_STACK
+static void _md4_compress(hash_state *md)
+#else
+static void md4_compress(hash_state *md)
+#endif
+{
+    unsigned long x[16], a, b, c, d;
+    int i;
+
+    _ARGCHK(md != NULL);
+
+    /* copy state */
+    a = md->md4.state[0];
+    b = md->md4.state[1];
+    c = md->md4.state[2];
+    d = md->md4.state[3];
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32L(x[i], md->md4.buf + (4*i));
+    }
+ 
+    /* Round 1 */ 
+    FF (a, b, c, d, x[ 0], S11); /* 1 */ 
+    FF (d, a, b, c, x[ 1], S12); /* 2 */ 
+    FF (c, d, a, b, x[ 2], S13); /* 3 */ 
+    FF (b, c, d, a, x[ 3], S14); /* 4 */ 
+    FF (a, b, c, d, x[ 4], S11); /* 5 */ 
+    FF (d, a, b, c, x[ 5], S12); /* 6 */ 
+    FF (c, d, a, b, x[ 6], S13); /* 7 */ 
+    FF (b, c, d, a, x[ 7], S14); /* 8 */ 
+    FF (a, b, c, d, x[ 8], S11); /* 9 */ 
+    FF (d, a, b, c, x[ 9], S12); /* 10 */
+    FF (c, d, a, b, x[10], S13); /* 11 */ 
+    FF (b, c, d, a, x[11], S14); /* 12 */
+    FF (a, b, c, d, x[12], S11); /* 13 */
+    FF (d, a, b, c, x[13], S12); /* 14 */ 
+    FF (c, d, a, b, x[14], S13); /* 15 */ 
+    FF (b, c, d, a, x[15], S14); /* 16 */ 
+    
+    /* Round 2 */ 
+    GG (a, b, c, d, x[ 0], S21); /* 17 */ 
+    GG (d, a, b, c, x[ 4], S22); /* 18 */ 
+    GG (c, d, a, b, x[ 8], S23); /* 19 */ 
+    GG (b, c, d, a, x[12], S24); /* 20 */ 
+    GG (a, b, c, d, x[ 1], S21); /* 21 */ 
+    GG (d, a, b, c, x[ 5], S22); /* 22 */ 
+    GG (c, d, a, b, x[ 9], S23); /* 23 */ 
+    GG (b, c, d, a, x[13], S24); /* 24 */ 
+    GG (a, b, c, d, x[ 2], S21); /* 25 */ 
+    GG (d, a, b, c, x[ 6], S22); /* 26 */ 
+    GG (c, d, a, b, x[10], S23); /* 27 */ 
+    GG (b, c, d, a, x[14], S24); /* 28 */ 
+    GG (a, b, c, d, x[ 3], S21); /* 29 */ 
+    GG (d, a, b, c, x[ 7], S22); /* 30 */ 
+    GG (c, d, a, b, x[11], S23); /* 31 */ 
+    GG (b, c, d, a, x[15], S24); /* 32 */ 
+    
+    /* Round 3 */
+    HH (a, b, c, d, x[ 0], S31); /* 33 */ 
+    HH (d, a, b, c, x[ 8], S32); /* 34 */ 
+    HH (c, d, a, b, x[ 4], S33); /* 35 */ 
+    HH (b, c, d, a, x[12], S34); /* 36 */ 
+    HH (a, b, c, d, x[ 2], S31); /* 37 */ 
+    HH (d, a, b, c, x[10], S32); /* 38 */ 
+    HH (c, d, a, b, x[ 6], S33); /* 39 */ 
+    HH (b, c, d, a, x[14], S34); /* 40 */ 
+    HH (a, b, c, d, x[ 1], S31); /* 41 */ 
+    HH (d, a, b, c, x[ 9], S32); /* 42 */ 
+    HH (c, d, a, b, x[ 5], S33); /* 43 */ 
+    HH (b, c, d, a, x[13], S34); /* 44 */ 
+    HH (a, b, c, d, x[ 3], S31); /* 45 */ 
+    HH (d, a, b, c, x[11], S32); /* 46 */ 
+    HH (c, d, a, b, x[ 7], S33); /* 47 */ 
+    HH (b, c, d, a, x[15], S34); /* 48 */ 
+    
+
+    /* Update our state */
+    md->md4.state[0] = md->md4.state[0] + a;
+    md->md4.state[1] = md->md4.state[1] + b;
+    md->md4.state[2] = md->md4.state[2] + c;
+    md->md4.state[3] = md->md4.state[3] + d;
+}
+
+#ifdef CLEAN_STACK
+static void md4_compress(hash_state *md)
+{
+   _md4_compress(md);
+   burn_stack(sizeof(unsigned long) * 20 + sizeof(int));
+}
+#endif
+
+void md4_init(hash_state * md)
+{
+   _ARGCHK(md != NULL);
+   md->md4.state[0] = 0x67452301UL;
+   md->md4.state[1] = 0xefcdab89UL;
+   md->md4.state[2] = 0x98badcfeUL;
+   md->md4.state[3] = 0x10325476UL;
+   md->md4.length  = 0;
+   md->md4.curlen = 0;
+}
+
+void md4_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+    while (len) {
+        n = MIN(len, (64 - md->md4.curlen));
+        memcpy(md->md4.buf + md->md4.curlen, buf, n);
+        md->md4.curlen += n;
+        buf            += n;
+        len            -= n;
+
+        /* is 64 bytes full? */
+        if (md->md4.curlen == 64) {
+            md4_compress(md);
+            md->md4.length += 512;
+            md->md4.curlen = 0;
+        }
+    }
+}
+
+void md4_done(hash_state * md, unsigned char *hash)
+{
+    int i;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->md4.length += md->md4.curlen * 8;
+
+    /* append the '1' bit */
+    md->md4.buf[md->md4.curlen++] = 0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->md4.curlen > 56) {
+        while (md->md4.curlen < 64) {
+            md->md4.buf[md->md4.curlen++] = 0;
+        }
+        md4_compress(md);
+        md->md4.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->md4.curlen < 56) {
+        md->md4.buf[md->md4.curlen++] = 0;
+    }
+
+    /* store length */
+    STORE64L(md->md4.length, md->md4.buf+56);
+    md4_compress(md);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->md4.state[i], hash+(4*i));
+    }
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int md4_test(void)
+{
+    static const struct md4_test_case {
+        int num;
+        unsigned char input[128];
+        int inputlen;
+        unsigned char digest[16];
+    } cases[] = {
+        { 1, "", 0,
+          {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
+           0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0} },
+        { 2, "a", 1,
+          {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46,
+           0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24} },
+        { 3, "abc", 3, 
+          {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, 
+           0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d} },
+        { 4, "message digest", 14, 
+          {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, 
+           0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b} },
+        { 5, "abcdefghijklmnopqrstuvwxyz", 26, 
+          {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, 
+           0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9} },
+        { 6, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, 
+          {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, 
+           0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4} },
+        { 7, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 80, 
+          {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, 
+           0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36} },
+    };
+    int i, failed;
+    hash_state md;
+    unsigned char digest[16];
+
+    failed = 0;
+    for(i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
+        md4_init(&md);
+        md4_process(&md, cases[i].input, cases[i].inputlen);
+        md4_done(&md, digest);
+        if(memcmp(digest, cases[i].digest, 16) != 0) {
+#if 0
+            int j;
+            printf("\nMD4 test #%d failed\n", cases[i].num);
+            printf(  "Result:  0x"); 
+            for(j=0; j < 16; j++) {
+               printf("%2x", digest[j]);
+            }
+            printf("\nCorrect: 0x");
+            for(j=0; j < 16; j++) {
+               printf("%2x", cases[i].digest[j]);
+            }
+            printf("\n");
+#endif 
+            failed++;
+        } else {
+/*            printf("MD4 test #%d succeeded.\n", cases[i].num); */
+        }
+    }
+
+    if (failed) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    return CRYPT_OK;
+}
+
+#endif
+
+

+ 268 - 0
md5.c

@@ -0,0 +1,268 @@
+#include "mycrypt.h"
+
+#ifdef MD5
+
+const struct _hash_descriptor md5_desc =
+{
+    "md5",
+    3,
+    16,
+    64,
+    &md5_init,
+    &md5_process,
+    &md5_done,
+    &md5_test
+};
+
+#define F(x,y,z)  ( (x&y)|((~x)&z) )
+#define G(x,y,z)  ( (x&z)|(y&(~z)) )
+#define H(x,y,z)  (x^y^z)
+#define I(x,y,z)  (y ^ (x | (~z)))
+
+#define FF(a,b,c,d,M,s,t) \
+    a = (a + F(b,c,d) + M + t); a = ROL(a, s); a = (b + a);
+
+#define GG(a,b,c,d,M,s,t) \
+    a = (a + G(b,c,d) + M + t); a = ROL(a, s); a = (b + a);
+
+#define HH(a,b,c,d,M,s,t) \
+    a = (a + H(b,c,d) + M + t); a = ROL(a, s); a = (b + a);
+
+#define II(a,b,c,d,M,s,t) \
+    a = (a + I(b,c,d) + M + t); a = ROL(a, s); a = (b + a);
+
+#ifdef CLEAN_STACK
+static void _md5_compress(hash_state *md)
+#else
+static void md5_compress(hash_state *md)
+#endif
+{
+    unsigned long i, W[16], a, b, c, d;
+
+    _ARGCHK(md != NULL);
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32L(W[i], md->md5.buf + (4*i));
+    }
+ 
+    /* copy state */
+    a = md->md5.state[0];
+    b = md->md5.state[1];
+    c = md->md5.state[2];
+    d = md->md5.state[3];
+
+    FF(a,b,c,d,W[0],7,0xd76aa478UL)
+    FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+    FF(c,d,a,b,W[2],17,0x242070dbUL)
+    FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+    FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+    FF(d,a,b,c,W[5],12,0x4787c62aUL)
+    FF(c,d,a,b,W[6],17,0xa8304613UL)
+    FF(b,c,d,a,W[7],22,0xfd469501UL)
+    FF(a,b,c,d,W[8],7,0x698098d8UL)
+    FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+    FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+    FF(b,c,d,a,W[11],22,0x895cd7beUL)
+    FF(a,b,c,d,W[12],7,0x6b901122UL)
+    FF(d,a,b,c,W[13],12,0xfd987193UL)
+    FF(c,d,a,b,W[14],17,0xa679438eUL)
+    FF(b,c,d,a,W[15],22,0x49b40821UL)
+    GG(a,b,c,d,W[1],5,0xf61e2562UL)
+    GG(d,a,b,c,W[6],9,0xc040b340UL)
+    GG(c,d,a,b,W[11],14,0x265e5a51UL)
+    GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+    GG(a,b,c,d,W[5],5,0xd62f105dUL)
+    GG(d,a,b,c,W[10],9,0x02441453UL)
+    GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+    GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+    GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+    GG(d,a,b,c,W[14],9,0xc33707d6UL)
+    GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+    GG(b,c,d,a,W[8],20,0x455a14edUL)
+    GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+    GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+    GG(c,d,a,b,W[7],14,0x676f02d9UL)
+    GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+    HH(a,b,c,d,W[5],4,0xfffa3942UL)
+    HH(d,a,b,c,W[8],11,0x8771f681UL)
+    HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+    HH(b,c,d,a,W[14],23,0xfde5380cUL)
+    HH(a,b,c,d,W[1],4,0xa4beea44UL)
+    HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+    HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+    HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+    HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+    HH(d,a,b,c,W[0],11,0xeaa127faUL)
+    HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+    HH(b,c,d,a,W[6],23,0x04881d05UL)
+    HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+    HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+    HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+    HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+    II(a,b,c,d,W[0],6,0xf4292244UL)
+    II(d,a,b,c,W[7],10,0x432aff97UL)
+    II(c,d,a,b,W[14],15,0xab9423a7UL)
+    II(b,c,d,a,W[5],21,0xfc93a039UL)
+    II(a,b,c,d,W[12],6,0x655b59c3UL)
+    II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+    II(c,d,a,b,W[10],15,0xffeff47dUL)
+    II(b,c,d,a,W[1],21,0x85845dd1UL)
+    II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+    II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+    II(c,d,a,b,W[6],15,0xa3014314UL)
+    II(b,c,d,a,W[13],21,0x4e0811a1UL)
+    II(a,b,c,d,W[4],6,0xf7537e82UL)
+    II(d,a,b,c,W[11],10,0xbd3af235UL)
+    II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+    II(b,c,d,a,W[9],21,0xeb86d391UL)
+
+    md->md5.state[0] = md->md5.state[0] + a;
+    md->md5.state[1] = md->md5.state[1] + b;
+    md->md5.state[2] = md->md5.state[2] + c;
+    md->md5.state[3] = md->md5.state[3] + d;
+}
+
+#ifdef CLEAN_STACK
+static void md5_compress(hash_state *md)
+{
+   _md5_compress(md);
+   burn_stack(sizeof(unsigned long) * 21);
+}
+#endif
+
+void md5_init(hash_state * md)
+{
+   _ARGCHK(md != NULL);
+   md->md5.state[0] = 0x67452301UL;
+   md->md5.state[1] = 0xefcdab89UL;
+   md->md5.state[2] = 0x98badcfeUL;
+   md->md5.state[3] = 0x10325476UL;
+   md->md5.curlen = 0;
+   md->md5.length = 0;
+}
+
+void md5_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+    while (len) {
+        n = MIN(len, (64 - md->md5.curlen));
+        memcpy(md->md5.buf + md->md5.curlen, buf, n);
+        md->md5.curlen += n;
+        buf            += n;
+        len            -= n;
+
+        /* is 64 bytes full? */
+        if (md->md5.curlen == 64) {
+            md5_compress(md);
+            md->md5.length += 512;
+            md->md5.curlen = 0;
+        }
+    }
+}
+
+void md5_done(hash_state * md, unsigned char *hash)
+{
+    int i;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->md5.length += md->md5.curlen * 8;
+
+    /* append the '1' bit */
+    md->md5.buf[md->md5.curlen++] = 0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->md5.curlen > 56) {
+        while (md->md5.curlen < 64) {
+            md->md5.buf[md->md5.curlen++] = 0;
+        }
+        md5_compress(md);
+        md->md5.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->md5.curlen < 56) {
+        md->md5.buf[md->md5.curlen++] = 0;
+    }
+
+    /* store length */
+    STORE64L(md->md5.length, md->md5.buf+56);
+    md5_compress(md);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->md5.state[i], hash+(4*i));
+    }
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int  md5_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[16];
+  } tests[] = {
+    { "",
+      { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 
+        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+    { "a",
+      {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 
+       0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+    { "abc",
+      { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 
+        0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+    { "message digest", 
+      { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 
+        0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, 
+    { "abcdefghijklmnopqrstuvwxyz",
+      { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 
+        0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+      { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 
+        0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+      { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 
+        0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, 
+    { NULL, { 0 } }
+  };
+
+  int failed, i;
+  unsigned char tmp[16];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      md5_init(&md);
+      md5_process(&md, tests[i].msg, strlen(tests[i].msg));
+      md5_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 16)) {
+#if 0
+         int j;
+         printf("MD5 Test %d (len == %d) failed\nGot (as a result): ", i, strlen(tests[i].msg));
+         for (j = 0; j < 16; j++) { 
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+#endif
+
+

+ 19 - 0
mem.c

@@ -0,0 +1,19 @@
+#include "mycrypt.h"
+
+void zeromem(void *dst, unsigned long len)
+{
+ unsigned char *mem = (unsigned char *)dst;
+ _ARGCHK(dst != NULL);
+ while (len--)
+    *mem++ = 0;
+}
+
+void burn_stack(unsigned long len)
+{
+   unsigned char buf[32];
+   zeromem(buf, sizeof(buf));
+   if (len > sizeof(buf))
+      burn_stack(len - sizeof(buf));
+}
+
+

+ 87 - 0
mpi-config.h

@@ -0,0 +1,87 @@
+/* Default configuration for MPI library */
+/* $ID$ */
+
+#ifndef MPI_CONFIG_H_
+#define MPI_CONFIG_H_
+
+/*
+  For boolean options, 
+  0 = no
+  1 = yes
+
+  Other options are documented individually.
+
+ */
+
+#ifndef MP_IOFUNC
+#define MP_IOFUNC     1  /* include mp_print() ?                */
+#endif
+
+#ifndef MP_MODARITH
+#define MP_MODARITH   1  /* include modular arithmetic ?        */
+#endif
+
+#ifndef MP_NUMTH
+#define MP_NUMTH      1  /* include number theoretic functions? */
+#endif
+
+#ifndef MP_LOGTAB
+#define MP_LOGTAB     1  /* use table of logs instead of log()? */
+#endif
+
+#ifndef MP_MEMSET
+#define MP_MEMSET     1  /* use memset() to zero buffers?       */
+#endif
+
+#ifndef MP_MEMCPY
+#define MP_MEMCPY     1  /* use memcpy() to copy buffers?       */
+#endif
+
+#ifndef MP_CRYPTO
+#define MP_CRYPTO     1  /* erase memory on free?               */
+#endif
+
+#ifndef MP_ARGCHK
+/*
+  0 = no parameter checks
+  1 = runtime checks, continue execution and return an error to caller
+  2 = assertions; dump core on parameter errors
+ */
+#define MP_ARGCHK     1  /* how to check input arguments        */
+#endif
+
+#ifndef MP_DEBUG
+#define MP_DEBUG      0  /* print diagnostic output?            */
+#endif
+
+#ifndef MP_DEFPREC
+#define MP_DEFPREC    8  /* default precision, in digits        */
+#endif
+
+#ifndef MP_MACRO
+#define MP_MACRO      1  /* use macros for frequent calls?      */
+#endif
+
+#ifndef MP_SQUARE
+#define MP_SQUARE     1  /* use separate squaring code?         */
+#endif
+
+#ifndef MP_PTAB_SIZE
+/*
+  When building mpprime.c, we build in a table of small prime
+  values to use for primality testing.  The more you include,
+  the more space they take up.  See primes.c for the possible
+  values (currently 16, 32, 64, 128, 256, and 6542)
+ */
+#define MP_PTAB_SIZE  128  /* how many built-in primes?         */
+#endif
+
+#ifndef MP_COMPAT_MACROS
+#define MP_COMPAT_MACROS 1   /* define compatibility macros?    */
+#endif
+
+#endif /* ifndef MPI_CONFIG_H_ */
+
+
+
+

+ 16 - 0
mpi-types.h

@@ -0,0 +1,16 @@
+/* Type definitions generated by 'types.pl' */
+typedef char               mp_sign;
+typedef unsigned short     mp_digit;  /* 2 byte type */
+typedef unsigned int       mp_word;   /* 4 byte type */
+typedef unsigned int       mp_size;
+typedef int                mp_err;
+
+#define MP_DIGIT_BIT       (CHAR_BIT*sizeof(mp_digit))
+#define MP_DIGIT_MAX       USHRT_MAX
+#define MP_WORD_BIT        (CHAR_BIT*sizeof(mp_word))
+#define MP_WORD_MAX        UINT_MAX
+
+#define MP_DIGIT_SIZE      2
+#define DIGIT_FMT          "%04X"
+#define RADIX              (MP_DIGIT_MAX+1)
+

+ 4009 - 0
mpi.c

@@ -0,0 +1,4009 @@
+ /*
+    mpi.c
+
+    by Michael J. Fromberger <[email protected]>
+    Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
+
+    Arbitrary precision integer arithmetic library
+
+    $ID$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "mycrypt.h"
+
+#ifdef MPI
+
+#if MP_DEBUG
+#include <stdio.h>
+
+#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);}
+#else
+#define DIAG(T,V)
+#endif
+
+/* 
+   If MP_LOGTAB is not defined, use the math library to compute the
+   logarithms on the fly.  Otherwise, use the static table below.
+   Pick which works best for your system.
+ */
+#if MP_LOGTAB
+
+/* {{{ s_logv_2[] - log table for 2 in various bases */
+
+/*
+  A table of the logs of 2 for various bases (the 0 and 1 entries of
+  this table are meaningless and should not be referenced).  
+
+  This table is used to compute output lengths for the mp_toradix()
+  function.  Since a number n in radix r takes up about log_r(n)
+  digits, we estimate the output size by taking the least integer
+  greater than log_r(n), where:
+
+  log_r(n) = log_2(n) * log_r(2)
+
+  This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+  which are the output bases supported.  
+ */
+const float s_logv_2[] = {
+   0.000000000, 0.000000000, 1.000000000, 0.630929754, 	/*  0  1  2  3 */
+   0.500000000, 0.430676558, 0.386852807, 0.356207187, 	/*  4  5  6  7 */
+   0.333333333, 0.315464877, 0.301029996, 0.289064826, 	/*  8  9 10 11 */
+   0.278942946, 0.270238154, 0.262649535, 0.255958025, 	/* 12 13 14 15 */
+   0.250000000, 0.244650542, 0.239812467, 0.235408913, 	/* 16 17 18 19 */
+   0.231378213, 0.227670249, 0.224243824, 0.221064729, 	/* 20 21 22 23 */
+   0.218104292, 0.215338279, 0.212746054, 0.210309918, 	/* 24 25 26 27 */
+   0.208014598, 0.205846832, 0.203795047, 0.201849087, 	/* 28 29 30 31 */
+   0.200000000, 0.198239863, 0.196561632, 0.194959022, 	/* 32 33 34 35 */
+   0.193426404, 0.191958720, 0.190551412, 0.189200360, 	/* 36 37 38 39 */
+   0.187901825, 0.186652411, 0.185449023, 0.184288833, 	/* 40 41 42 43 */
+   0.183169251, 0.182087900, 0.181042597, 0.180031327, 	/* 44 45 46 47 */
+   0.179052232, 0.178103594, 0.177183820, 0.176291434, 	/* 48 49 50 51 */
+   0.175425064, 0.174583430, 0.173765343, 0.172969690, 	/* 52 53 54 55 */
+   0.172195434, 0.171441601, 0.170707280, 0.169991616, 	/* 56 57 58 59 */
+   0.169293808, 0.168613099, 0.167948779, 0.167300179, 	/* 60 61 62 63 */
+   0.166666667
+};
+/* }}} */
+#define LOG_V_2(R)  s_logv_2[(R)]
+
+#else
+
+#include <math.h>
+#define LOG_V_2(R)  (log(2.0)/log(R))
+
+#endif
+
+/* Default precision for newly created mp_int's      */
+static unsigned int s_mp_defprec = MP_DEFPREC;
+
+/* {{{ Digit arithmetic macros */
+
+/*
+  When adding and multiplying digits, the results can be larger than
+  can be contained in an mp_digit.  Thus, an mp_word is used.  These
+  macros mask off the upper and lower digits of the mp_word (the
+  mp_word may be more than 2 mp_digits wide, but we only concern
+  ourselves with the low-order 2 mp_digits)
+
+  If your mp_word DOES have more than 2 mp_digits, you need to
+  uncomment the first line, and comment out the second.
+ */
+
+/* #define  CARRYOUT(W)  (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */
+#define  CARRYOUT(W)  ((W)>>DIGIT_BIT)
+#define  ACCUM(W)     ((W)&MP_DIGIT_MAX)
+
+/* }}} */
+
+/* {{{ Comparison constants */
+
+
+/* }}} */
+
+/* {{{ Constant strings */
+
+/* Constant strings returned by mp_strerror() */
+static const char *mp_err_string[] = {
+  "unknown result code",     /* say what?            */
+  "boolean true",            /* MP_OKAY, MP_YES      */
+  "boolean false",           /* MP_NO                */
+  "out of memory",           /* MP_MEM               */
+  "argument out of range",   /* MP_RANGE             */
+  "invalid input parameter", /* MP_BADARG            */
+  "result is undefined"      /* MP_UNDEF             */
+};
+
+/* Value to digit maps for radix conversion   */
+
+/* s_dmap_1 - standard digits and letters */
+static const char *s_dmap_1 = 
+  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+#if 0
+/* s_dmap_2 - base64 ordering for digits  */
+static const char *s_dmap_2 =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#endif
+
+/* }}} */
+
+/* {{{ Static function declarations */
+
+/* 
+   If MP_MACRO is false, these will be defined as actual functions;
+   otherwise, suitable macro definitions will be used.  This works
+   around the fact that ANSI C89 doesn't support an 'inline' keyword
+   (although I hear C9x will ... about bloody time).  At present, the
+   macro definitions are identical to the function bodies, but they'll
+   expand in place, instead of generating a function call.
+
+   I chose these particular functions to be made into macros because
+   some profiling showed they are called a lot on a typical workload,
+   and yet they are primarily housekeeping.
+ */
+#if MP_MACRO == 0
+ void     s_mp_setz(mp_digit *dp, mp_size count); /* zero digits           */
+ void     s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy    */
+ void    *s_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
+ void     s_mp_free(void *ptr);                   /* general free function */
+#else
+
+ /* Even if these are defined as macros, we need to respect the settings
+    of the MP_MEMSET and MP_MEMCPY configuration options...
+  */
+ #if MP_MEMSET == 0
+  #define  s_mp_setz(dp, count) \
+       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
+ #else
+  #define  s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMSET */
+
+ #if MP_MEMCPY == 0
+  #define  s_mp_copy(sp, dp, count) \
+       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
+ #else
+  #define  s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMCPY */
+
+ #define  s_mp_alloc(nb, ni)  XCALLOC(nb, ni)
+ #define  s_mp_free(ptr) {if(ptr) XFREE(ptr);}
+#endif /* MP_MACRO */
+
+mp_err   s_mp_grow(mp_int *mp, mp_size min);   /* increase allocated size */
+mp_err   s_mp_pad(mp_int *mp, mp_size min);    /* left pad with zeroes    */
+
+void     s_mp_clamp(mp_int *mp);               /* clip leading zeroes     */
+
+void     s_mp_exch(mp_int *a, mp_int *b);      /* swap a and b in place   */
+
+mp_err   s_mp_lshd(mp_int *mp, mp_size p);     /* left-shift by p digits  */
+void     s_mp_rshd(mp_int *mp, mp_size p);     /* right-shift by p digits */
+void     s_mp_div_2d(mp_int *mp, mp_digit d);  /* divide by 2^d in place  */
+void     s_mp_mod_2d(mp_int *mp, mp_digit d);  /* modulo 2^d in place     */
+mp_err   s_mp_mul_2d(mp_int *mp, mp_digit d);  /* multiply by 2^d in place*/
+void     s_mp_div_2(mp_int *mp);               /* divide by 2 in place    */
+mp_err   s_mp_mul_2(mp_int *mp);               /* multiply by 2 in place  */
+mp_digit s_mp_norm(mp_int *a, mp_int *b);      /* normalize for division  */
+mp_err   s_mp_add_d(mp_int *mp, mp_digit d);   /* unsigned digit addition */
+mp_err   s_mp_sub_d(mp_int *mp, mp_digit d);   /* unsigned digit subtract */
+mp_err   s_mp_mul_d(mp_int *mp, mp_digit d);   /* unsigned digit multiply */
+mp_err   s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r);
+		                               /* unsigned digit divide   */
+mp_err   s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu);
+                                               /* Barrett reduction       */
+mp_err   s_mp_add(mp_int *a, mp_int *b);       /* magnitude addition      */
+mp_err   s_mp_sub(mp_int *a, mp_int *b);       /* magnitude subtract      */
+mp_err   s_mp_mul(mp_int *a, mp_int *b);       /* magnitude multiply      */
+#if 0
+void     s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len);
+                                               /* multiply buffers in place */
+#endif
+#if MP_SQUARE
+mp_err   s_mp_sqr(mp_int *a);                  /* magnitude square        */
+#else
+#define  s_mp_sqr(a) s_mp_mul(a, a)
+#endif
+mp_err   s_mp_div(mp_int *a, mp_int *b);       /* magnitude divide        */
+mp_err   s_mp_2expt(mp_int *a, mp_digit k);    /* a = 2^k                 */
+int      s_mp_cmp(mp_int *a, mp_int *b);       /* magnitude comparison    */
+int      s_mp_cmp_d(mp_int *a, mp_digit d);    /* magnitude digit compare */
+int      s_mp_ispow2(mp_int *v);               /* is v a power of 2?      */
+int      s_mp_ispow2d(mp_digit d);             /* is d a power of 2?      */
+
+int      s_mp_tovalue(char ch, int r);          /* convert ch to value    */
+char     s_mp_todigit(int val, int r, int low); /* convert val to digit   */
+int      s_mp_outlen(int bits, int r);          /* output length in bytes */
+
+/* }}} */
+
+/* {{{ Default precision manipulation */
+
+unsigned int mp_get_prec(void)
+{
+  return s_mp_defprec;
+
+} /* end mp_get_prec() */
+
+void         mp_set_prec(unsigned int prec)
+{
+  if(prec == 0)
+    s_mp_defprec = MP_DEFPREC;
+  else
+    s_mp_defprec = prec;
+
+} /* end mp_set_prec() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_init(mp) */
+
+/*
+  mp_init(mp)
+
+  Initialize a new zero-valued mp_int.  Returns MP_OKAY if successful,
+  MP_MEM if memory could not be allocated for the structure.
+ */
+
+mp_err mp_init(mp_int *mp)
+{
+  return mp_init_size(mp, s_mp_defprec);
+
+} /* end mp_init() */
+
+/* }}} */
+
+/* {{{ mp_init_array(mp[], count) */
+
+mp_err mp_init_array(mp_int mp[], int count)
+{
+  mp_err  res;
+  int     pos;
+
+  ARGCHK(mp !=NULL && count > 0, MP_BADARG);
+
+  for(pos = 0; pos < count; ++pos) {
+    if((res = mp_init(&mp[pos])) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  return MP_OKAY;
+
+ CLEANUP:
+  while(--pos >= 0) 
+    mp_clear(&mp[pos]);
+
+  return res;
+
+} /* end mp_init_array() */
+
+/* }}} */
+
+/* {{{ mp_init_size(mp, prec) */
+
+/*
+  mp_init_size(mp, prec)
+
+  Initialize a new zero-valued mp_int with at least the given
+  precision; returns MP_OKAY if successful, or MP_MEM if memory could
+  not be allocated for the structure.
+ */
+
+mp_err mp_init_size(mp_int *mp, mp_size prec)
+{
+  ARGCHK(mp != NULL && prec > 0, MP_BADARG);
+
+  if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL)
+    return MP_MEM;
+
+  SIGN(mp) = MP_ZPOS;
+  USED(mp) = 1;
+  ALLOC(mp) = prec;
+
+  return MP_OKAY;
+
+} /* end mp_init_size() */
+
+/* }}} */
+
+/* {{{ mp_init_copy(mp, from) */
+
+/*
+  mp_init_copy(mp, from)
+
+  Initialize mp as an exact copy of from.  Returns MP_OKAY if
+  successful, MP_MEM if memory could not be allocated for the new
+  structure.
+ */
+
+mp_err mp_init_copy(mp_int *mp, mp_int *from)
+{
+  ARGCHK(mp != NULL && from != NULL, MP_BADARG);
+
+  if(mp == from)
+    return MP_OKAY;
+
+  if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL)
+    return MP_MEM;
+
+  s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
+  USED(mp) = USED(from);
+  ALLOC(mp) = USED(from);
+  SIGN(mp) = SIGN(from);
+
+  return MP_OKAY;
+
+} /* end mp_init_copy() */
+
+/* }}} */
+
+/* {{{ mp_copy(from, to) */
+
+/*
+  mp_copy(from, to)
+
+  Copies the mp_int 'from' to the mp_int 'to'.  It is presumed that
+  'to' has already been initialized (if not, use mp_init_copy()
+  instead). If 'from' and 'to' are identical, nothing happens.
+ */
+
+mp_err mp_copy(mp_int *from, mp_int *to)
+{
+  ARGCHK(from != NULL && to != NULL, MP_BADARG);
+
+  if(from == to)
+    return MP_OKAY;
+
+  { /* copy */
+    mp_digit   *tmp;
+
+    /*
+      If the allocated buffer in 'to' already has enough space to hold
+      all the used digits of 'from', we'll re-use it to avoid hitting
+      the memory allocater more than necessary; otherwise, we'd have
+      to grow anyway, so we just allocate a hunk and make the copy as
+      usual
+     */
+    if(ALLOC(to) >= USED(from)) {
+      s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
+      s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
+      
+    } else {
+      if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL)
+	return MP_MEM;
+
+      s_mp_copy(DIGITS(from), tmp, USED(from));
+
+      if(DIGITS(to) != NULL) {
+#if MP_CRYPTO
+	s_mp_setz(DIGITS(to), ALLOC(to));
+#endif
+	s_mp_free(DIGITS(to));
+      }
+
+      DIGITS(to) = tmp;
+      ALLOC(to) = USED(from);
+    }
+
+    /* Copy the precision and sign from the original */
+    USED(to) = USED(from);
+    SIGN(to) = SIGN(from);
+  } /* end copy */
+
+  return MP_OKAY;
+
+} /* end mp_copy() */
+
+/* }}} */
+
+/* {{{ mp_exch(mp1, mp2) */
+
+/*
+  mp_exch(mp1, mp2)
+
+  Exchange mp1 and mp2 without allocating any intermediate memory
+  (well, unless you count the stack space needed for this call and the
+  locals it creates...).  This cannot fail.
+ */
+
+void mp_exch(mp_int *mp1, mp_int *mp2)
+{
+#if MP_ARGCHK == 2
+  assert(mp1 != NULL && mp2 != NULL);
+#else
+  if(mp1 == NULL || mp2 == NULL)
+    return;
+#endif
+
+  s_mp_exch(mp1, mp2);
+
+} /* end mp_exch() */
+
+/* }}} */
+
+/* {{{ mp_clear(mp) */
+
+/*
+  mp_clear(mp)
+
+  Release the storage used by an mp_int, and void its fields so that
+  if someone calls mp_clear() again for the same int later, we won't
+  get tollchocked.
+ */
+
+void   mp_clear(mp_int *mp)
+{
+  if(mp == NULL)
+    return;
+
+  if(DIGITS(mp) != NULL) {
+#if MP_CRYPTO
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+    s_mp_free(DIGITS(mp));
+    DIGITS(mp) = NULL;
+  }
+
+  USED(mp) = 0;
+  ALLOC(mp) = 0;
+
+} /* end mp_clear() */
+
+/* }}} */
+
+/* {{{ mp_clear_array(mp[], count) */
+
+void   mp_clear_array(mp_int mp[], int count)
+{
+//  ARGCHK(mp != NULL && count > 0, MP_BADARG);
+
+  while(--count >= 0) 
+    mp_clear(&mp[count]);
+
+} /* end mp_clear_array() */
+
+/* }}} */
+
+/* {{{ mp_zero(mp) */
+
+/*
+  mp_zero(mp) 
+
+  Set mp to zero.  Does not change the allocated size of the structure,
+  and therefore cannot fail (except on a bad argument, which we ignore)
+ */
+void   mp_zero(mp_int *mp)
+{
+  if(mp == NULL)
+    return;
+
+  s_mp_setz(DIGITS(mp), ALLOC(mp));
+  USED(mp) = 1;
+  SIGN(mp) = MP_ZPOS;
+
+} /* end mp_zero() */
+
+/* }}} */
+
+/* {{{ mp_set(mp, d) */
+
+void   mp_set(mp_int *mp, mp_digit d)
+{
+  if(mp == NULL)
+    return;
+
+  mp_zero(mp);
+  DIGIT(mp, 0) = d;
+
+} /* end mp_set() */
+
+/* }}} */
+
+/* {{{ mp_set_int(mp, z) */
+
+mp_err mp_set_int(mp_int *mp, long z)
+{
+  int            ix;
+  unsigned long  v = abs(z);
+  mp_err         res;
+
+  ARGCHK(mp != NULL, MP_BADARG);
+
+  mp_zero(mp);
+  if(z == 0)
+    return MP_OKAY;  /* shortcut for zero */
+
+  for(ix = sizeof(long) - 1; ix >= 0; ix--) {
+
+/* --- bug in MSVC [first release] */
+  if (ix == -1) break;
+/* --- end of fix */
+
+    if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
+      return res;
+
+    res = s_mp_add_d(mp, 
+		     (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
+    if(res != MP_OKAY)
+      return res;
+  }
+
+  if(z < 0)
+    SIGN(mp) = MP_NEG;
+
+  return MP_OKAY;
+
+} /* end mp_set_int() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Digit arithmetic */
+
+/* {{{ mp_add_d(a, d, b) */
+
+/*
+  mp_add_d(a, d, b)
+
+  Compute the sum b = a + d, for a single digit d.  Respects the sign of
+  its primary addend (single digits are unsigned anyway).
+ */
+
+mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_err   res = MP_OKAY;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  if(SIGN(b) == MP_ZPOS) {
+    res = s_mp_add_d(b, d);
+  } else if(s_mp_cmp_d(b, d) >= 0) {
+    res = s_mp_sub_d(b, d);
+  } else {
+    SIGN(b) = MP_ZPOS;
+
+    DIGIT(b, 0) = d - DIGIT(b, 0);
+  }
+
+  return res;
+
+} /* end mp_add_d() */
+
+/* }}} */
+
+/* {{{ mp_sub_d(a, d, b) */
+
+/*
+  mp_sub_d(a, d, b)
+
+  Compute the difference b = a - d, for a single digit d.  Respects the
+  sign of its subtrahend (single digits are unsigned anyway).
+ */
+
+mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  if(SIGN(b) == MP_NEG) {
+    if((res = s_mp_add_d(b, d)) != MP_OKAY)
+      return res;
+
+  } else if(s_mp_cmp_d(b, d) >= 0) {
+    if((res = s_mp_sub_d(b, d)) != MP_OKAY)
+      return res;
+
+  } else {
+    mp_neg(b, b);
+
+    DIGIT(b, 0) = d - DIGIT(b, 0);
+    SIGN(b) = MP_NEG;
+  }
+
+  if(s_mp_cmp_d(b, 0) == 0)
+    SIGN(b) = MP_ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_sub_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_d(a, d, b) */
+
+/*
+  mp_mul_d(a, d, b)
+
+  Compute the product b = a * d, for a single digit d.  Respects the sign
+  of its multiplicand (single digits are unsigned anyway)
+ */
+
+mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if(d == 0) {
+    mp_zero(b);
+    return MP_OKAY;
+  }
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  res = s_mp_mul_d(b, d);
+
+  return res;
+
+} /* end mp_mul_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_2(a, c) */
+
+mp_err mp_mul_2(mp_int *a, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, c)) != MP_OKAY)
+    return res;
+
+  return s_mp_mul_2(c);
+
+} /* end mp_mul_2() */
+
+/* }}} */
+
+/* {{{ mp_div_d(a, d, q, r) */
+
+/*
+  mp_div_d(a, d, q, r)
+
+  Compute the quotient q = a / d and remainder r = a mod d, for a
+  single digit d.  Respects the sign of its divisor (single digits are
+  unsigned anyway).
+ */
+
+mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
+{
+  mp_err   res;
+  mp_digit rem;
+  int      pow;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  if(d == 0)
+    return MP_RANGE;
+
+  /* Shortcut for powers of two ... */
+  if((pow = s_mp_ispow2d(d)) >= 0) {
+    mp_digit  mask;
+
+    mask = (1 << pow) - 1;
+    rem = DIGIT(a, 0) & mask;
+
+    if(q) {
+      mp_copy(a, q);
+      s_mp_div_2d(q, (mp_digit)pow);
+    }
+
+    if(r)
+      *r = rem;
+
+    return MP_OKAY;
+  }
+
+  /*
+    If the quotient is actually going to be returned, we'll try to
+    avoid hitting the memory allocator by copying the dividend into it
+    and doing the division there.  This can't be any _worse_ than
+    always copying, and will sometimes be better (since it won't make
+    another copy)
+
+    If it's not going to be returned, we need to allocate a temporary
+    to hold the quotient, which will just be discarded.
+   */
+  if(q) {
+    if((res = mp_copy(a, q)) != MP_OKAY)
+      return res;
+
+    res = s_mp_div_d(q, d, &rem);
+    if(s_mp_cmp_d(q, 0) == MP_EQ)
+      SIGN(q) = MP_ZPOS;
+
+  } else {
+    mp_int  qp;
+
+    if((res = mp_init_copy(&qp, a)) != MP_OKAY)
+      return res;
+
+    res = s_mp_div_d(&qp, d, &rem);
+    if(s_mp_cmp_d(&qp, 0) == 0)
+      SIGN(&qp) = MP_ZPOS;
+
+    mp_clear(&qp);
+  }
+
+  if(r)
+    *r = rem;
+
+  return res;
+
+} /* end mp_div_d() */
+
+/* }}} */
+
+/* {{{ mp_div_2(a, c) */
+
+/*
+  mp_div_2(a, c)
+
+  Compute c = a / 2, disregarding the remainder.
+ */
+
+mp_err mp_div_2(mp_int *a, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, c)) != MP_OKAY)
+    return res;
+
+  s_mp_div_2(c);
+
+  return MP_OKAY;
+
+} /* end mp_div_2() */
+
+/* }}} */
+
+/* {{{ mp_expt_d(a, d, b) */
+
+mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  DIGIT(&s, 0) = 1;
+
+  while(d != 0) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d >>= 1;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_expt_d() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Full arithmetic */
+
+/* {{{ mp_abs(a, b) */
+
+/*
+  mp_abs(a, b)
+
+  Compute b = |a|.  'a' and 'b' may be identical.
+ */
+
+mp_err mp_abs(mp_int *a, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  SIGN(b) = MP_ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_abs() */
+
+/* }}} */
+
+/* {{{ mp_neg(a, b) */
+
+/*
+  mp_neg(a, b)
+
+  Compute b = -a.  'a' and 'b' may be identical.
+ */
+
+mp_err mp_neg(mp_int *a, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  if(s_mp_cmp_d(b, 0) == MP_EQ) 
+    SIGN(b) = MP_ZPOS;
+  else 
+    SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG;
+
+  return MP_OKAY;
+
+} /* end mp_neg() */
+
+/* }}} */
+
+/* {{{ mp_add(a, b, c) */
+
+/*
+  mp_add(a, b, c)
+
+  Compute c = a + b.  All parameters may be identical.
+ */
+
+mp_err mp_add(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_err  res;
+  int     cmp;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(SIGN(a) == SIGN(b)) { /* same sign:  add values, keep sign */
+
+    /* Commutativity of addition lets us do this in either order,
+       so we avoid having to use a temporary even if the result 
+       is supposed to replace the output
+     */
+    if(c == b) {
+      if((res = s_mp_add(c, a)) != MP_OKAY)
+	return res;
+    } else {
+      if(c != a && (res = mp_copy(a, c)) != MP_OKAY)
+	return res;
+
+      if((res = s_mp_add(c, b)) != MP_OKAY) 
+	return res;
+    }
+
+  } else if((cmp = s_mp_cmp(a, b)) > 0) {  /* different sign: a > b   */
+
+    /* If the output is going to be clobbered, we will use a temporary
+       variable; otherwise, we'll do it without touching the memory 
+       allocator at all, if possible
+     */
+    if(c == b) {
+      mp_int  tmp;
+
+      if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+	return res;
+      if((res = s_mp_sub(&tmp, b)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+
+      s_mp_exch(&tmp, c);
+      mp_clear(&tmp);
+
+    } else {
+
+      if(c != a && (res = mp_copy(a, c)) != MP_OKAY)
+	return res;
+      if((res = s_mp_sub(c, b)) != MP_OKAY)
+	return res;
+
+    }
+
+  } else if(cmp == 0) {             /* different sign, a == b   */
+
+    mp_zero(c);
+    return MP_OKAY;
+
+  } else {                          /* different sign: a < b    */
+
+    /* See above... */
+    if(c == a) {
+      mp_int  tmp;
+
+      if((res = mp_init_copy(&tmp, b)) != MP_OKAY)
+	return res;
+      if((res = s_mp_sub(&tmp, a)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+
+      s_mp_exch(&tmp, c);
+      mp_clear(&tmp);
+
+    } else {
+
+      if(c != b && (res = mp_copy(b, c)) != MP_OKAY)
+	return res;
+      if((res = s_mp_sub(c, a)) != MP_OKAY)
+	return res;
+
+    }
+  }
+
+  if(USED(c) == 1 && DIGIT(c, 0) == 0)
+    SIGN(c) = MP_ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_add() */
+
+/* }}} */
+
+/* {{{ mp_sub(a, b, c) */
+
+/*
+  mp_sub(a, b, c)
+
+  Compute c = a - b.  All parameters may be identical.
+ */
+
+mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_err  res;
+  int     cmp;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(SIGN(a) != SIGN(b)) {
+    if(c == a) {
+      if((res = s_mp_add(c, b)) != MP_OKAY)
+	return res;
+    } else {
+      if(c != b && ((res = mp_copy(b, c)) != MP_OKAY))
+	return res;
+      if((res = s_mp_add(c, a)) != MP_OKAY)
+	return res;
+      SIGN(c) = SIGN(a);
+    }
+
+  } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */
+    if(c == b) {
+      mp_int  tmp;
+
+      if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+	return res;
+      if((res = s_mp_sub(&tmp, b)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+      s_mp_exch(&tmp, c);
+      mp_clear(&tmp);
+
+    } else {
+      if(c != a && ((res = mp_copy(a, c)) != MP_OKAY))
+	return res;
+
+      if((res = s_mp_sub(c, b)) != MP_OKAY)
+	return res;
+    }
+
+  } else if(cmp == 0) {  /* Same sign, equal magnitude */
+    mp_zero(c);
+    return MP_OKAY;
+
+  } else {               /* Same sign, b > a */
+    if(c == a) {
+      mp_int  tmp;
+
+      if((res = mp_init_copy(&tmp, b)) != MP_OKAY)
+	return res;
+
+      if((res = s_mp_sub(&tmp, a)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+      s_mp_exch(&tmp, c);
+      mp_clear(&tmp);
+
+    } else {
+      if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) 
+	return res;
+
+      if((res = s_mp_sub(c, a)) != MP_OKAY)
+	return res;
+    }
+
+    SIGN(c) = !SIGN(b);
+  }
+
+  if(USED(c) == 1 && DIGIT(c, 0) == 0)
+    SIGN(c) = MP_ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_sub() */
+
+/* }}} */
+
+/* {{{ mp_mul(a, b, c) */
+
+/*
+  mp_mul(a, b, c)
+
+  Compute c = a * b.  All parameters may be identical.
+ */
+
+mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_err   res;
+  mp_sign  sgn;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG;
+
+  if(c == b) {
+    if((res = s_mp_mul(c, a)) != MP_OKAY)
+      return res;
+
+  } else {
+    if((res = mp_copy(a, c)) != MP_OKAY)
+      return res;
+
+    if((res = s_mp_mul(c, b)) != MP_OKAY)
+      return res;
+  }
+  
+  if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ)
+    SIGN(c) = MP_ZPOS;
+  else
+    SIGN(c) = sgn;
+  
+  return MP_OKAY;
+
+} /* end mp_mul() */
+
+/* }}} */
+
+/* {{{ mp_mul_2d(a, d, c) */
+
+/*
+  mp_mul_2d(a, d, c)
+
+  Compute c = a * 2^d.  a may be the same as c.
+ */
+
+mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, c)) != MP_OKAY)
+    return res;
+
+  if(d == 0)
+    return MP_OKAY;
+
+  return s_mp_mul_2d(c, d);
+
+} /* end mp_mul() */
+
+/* }}} */
+
+/* {{{ mp_sqr(a, b) */
+
+#if MP_SQUARE
+mp_err mp_sqr(mp_int *a, mp_int *b)
+{
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if((res = mp_copy(a, b)) != MP_OKAY)
+    return res;
+
+  if((res = s_mp_sqr(b)) != MP_OKAY)
+    return res;
+
+  SIGN(b) = MP_ZPOS;
+
+  return MP_OKAY;
+
+} /* end mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ mp_div(a, b, q, r) */
+
+/*
+  mp_div(a, b, q, r)
+
+  Compute q = a / b and r = a mod b.  Input parameters may be re-used
+  as output parameters.  If q or r is NULL, that portion of the
+  computation will be discarded (although it will still be computed)
+
+  Pay no attention to the hacker behind the curtain.
+ */
+
+mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r)
+{
+  mp_err   res;
+  mp_int   qtmp, rtmp;
+  int      cmp;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  if(mp_cmp_z(b) == MP_EQ)
+    return MP_RANGE;
+
+  /* If a <= b, we can compute the solution without division, and
+     avoid any memory allocation
+   */
+  if((cmp = s_mp_cmp(a, b)) < 0) {
+    if(r) {
+      if((res = mp_copy(a, r)) != MP_OKAY)
+	return res;
+    }
+
+    if(q) 
+      mp_zero(q);
+
+    return MP_OKAY;
+
+  } else if(cmp == 0) {
+
+    /* Set quotient to 1, with appropriate sign */
+    if(q) {
+      int qneg = (SIGN(a) != SIGN(b));
+
+      mp_set(q, 1);
+      if(qneg)
+	SIGN(q) = MP_NEG;
+    }
+
+    if(r)
+      mp_zero(r);
+
+    return MP_OKAY;
+  }
+
+  /* If we get here, it means we actually have to do some division */
+
+  /* Set up some temporaries... */
+  if((res = mp_init_copy(&qtmp, a)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&rtmp, b)) != MP_OKAY)
+    goto CLEANUP;
+
+  if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY)
+    goto CLEANUP;
+
+  /* Compute the signs for the output  */
+  SIGN(&rtmp) = SIGN(a); /* Sr = Sa              */
+  if(SIGN(a) == SIGN(b))
+    SIGN(&qtmp) = MP_ZPOS;  /* Sq = MP_ZPOS if Sa = Sb */
+  else
+    SIGN(&qtmp) = MP_NEG;   /* Sq = MP_NEG if Sa != Sb */
+
+  if(s_mp_cmp_d(&qtmp, 0) == MP_EQ)
+    SIGN(&qtmp) = MP_ZPOS;
+  if(s_mp_cmp_d(&rtmp, 0) == MP_EQ)
+    SIGN(&rtmp) = MP_ZPOS;
+
+  /* Copy output, if it is needed      */
+  if(q) 
+    s_mp_exch(&qtmp, q);
+
+  if(r) 
+    s_mp_exch(&rtmp, r);
+
+CLEANUP:
+  mp_clear(&rtmp);
+  mp_clear(&qtmp);
+
+  return res;
+
+} /* end mp_div() */
+
+/* }}} */
+
+/* {{{ mp_div_2d(a, d, q, r) */
+
+mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL, MP_BADARG);
+
+  if(q) {
+    if((res = mp_copy(a, q)) != MP_OKAY)
+      return res;
+
+    s_mp_div_2d(q, d);
+  }
+
+  if(r) {
+    if((res = mp_copy(a, r)) != MP_OKAY)
+      return res;
+
+    s_mp_mod_2d(r, d);
+  }
+
+  return MP_OKAY;
+
+} /* end mp_div_2d() */
+
+/* }}} */
+
+/* {{{ mp_expt(a, b, c) */
+
+/*
+  mp_expt(a, b, c)
+
+  Compute c = a ** b, that is, raise a to the b power.  Uses a
+  standard iterative square-and-multiply technique.
+ */
+
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+  mp_digit d;
+  int      dig, bit;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(b) < 0)
+    return MP_RANGE;
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+
+  mp_set(&s, 1);
+
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  /* Loop over low-order digits in ascending order */
+  for(dig = 0; dig < (int)(USED(b) - 1); dig++) {
+    d = DIGIT(b, dig);
+
+    /* Loop over bits of each non-maximal digit */
+    for(bit = 0; bit < (int)DIGIT_BIT; bit++) {
+      if(d & 1) {
+	if((res = s_mp_mul(&s, &x)) != MP_OKAY) 
+	  goto CLEANUP;
+      }
+
+      d >>= 1;
+      
+      if((res = s_mp_sqr(&x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+  }
+
+  /* Consider now the last digit... */
+  d = DIGIT(b, dig);
+
+  while(d) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d >>= 1;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+  
+  if(mp_iseven(b))
+    SIGN(&s) = SIGN(a);
+
+  res = mp_copy(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_expt() */
+
+/* }}} */
+
+/* {{{ mp_2expt(a, k) */
+
+/* Compute a = 2^k */
+
+mp_err mp_2expt(mp_int *a, mp_digit k)
+{
+  ARGCHK(a != NULL, MP_BADARG);
+
+  return s_mp_2expt(a, k);
+
+} /* end mp_2expt() */
+
+/* }}} */
+
+/* {{{ mp_mod(a, m, c) */
+
+/*
+  mp_mod(a, m, c)
+
+  Compute c = a (mod m).  Result will always be 0 <= c < m.
+ */
+
+mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c)
+{
+  mp_err  res;
+  int     mag;
+
+  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if(SIGN(m) == MP_NEG)
+    return MP_RANGE;
+
+  /*
+     If |a| > m, we need to divide to get the remainder and take the
+     absolute value.  
+
+     If |a| < m, we don't need to do any division, just copy and adjust
+     the sign (if a is negative).
+
+     If |a| == m, we can simply set the result to zero.
+
+     This order is intended to minimize the average path length of the
+     comparison chain on common workloads -- the most frequent cases are
+     that |a| != m, so we do those first.
+   */
+  if((mag = s_mp_cmp(a, m)) > 0) {
+    if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
+      return res;
+    
+    if(SIGN(c) == MP_NEG) {
+      if((res = mp_add(c, m, c)) != MP_OKAY)
+	return res;
+    }
+
+  } else if(mag < 0) {
+    if((res = mp_copy(a, c)) != MP_OKAY)
+      return res;
+
+    if(mp_cmp_z(a) < 0) {
+      if((res = mp_add(c, m, c)) != MP_OKAY)
+	return res;
+
+    }
+    
+  } else {
+    mp_zero(c);
+
+  }
+
+  return MP_OKAY;
+
+} /* end mp_mod() */
+
+/* }}} */
+
+/* {{{ mp_mod_d(a, d, c) */
+
+/*
+  mp_mod_d(a, d, c)
+
+  Compute c = a (mod d).  Result will always be 0 <= c < d
+ */
+mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c)
+{
+  mp_err   res;
+  mp_digit rem;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if(s_mp_cmp_d(a, d) > 0) {
+    if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
+      return res;
+
+  } else {
+    if(SIGN(a) == MP_NEG)
+      rem = d - DIGIT(a, 0);
+    else
+      rem = DIGIT(a, 0);
+  }
+
+  if(c)
+    *c = rem;
+
+  return MP_OKAY;
+
+} /* end mp_mod_d() */
+
+/* }}} */
+
+/* {{{ mp_sqrt(a, b) */
+
+/*
+  mp_sqrt(a, b)
+
+  Compute the integer square root of a, and store the result in b.
+  Uses an integer-arithmetic version of Newton's iterative linear
+  approximation technique to determine this value; the result has the
+  following two properties:
+
+     b^2 <= a
+     (b+1)^2 >= a
+
+  It is a range error to pass a negative value.
+ */
+mp_err mp_sqrt(mp_int *a, mp_int *b)
+{
+  mp_int   x, t;
+  mp_err   res;
+
+  ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+  /* Cannot take square root of a negative value */
+  if(SIGN(a) == MP_NEG)
+    return MP_RANGE;
+
+  /* Special cases for zero and one, trivial     */
+  if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) 
+    return mp_copy(a, b);
+    
+  /* Initialize the temporaries we'll use below  */
+  if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
+    return res;
+
+  /* Compute an initial guess for the iteration as a itself */
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  for(;;) {
+    /* t = (x * x) - a */
+    mp_copy(&x, &t);      /* can't fail, t is big enough for original x */
+    if((res = mp_sqr(&t, &t)) != MP_OKAY ||
+       (res = mp_sub(&t, a, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+    /* t = t / 2x       */
+    s_mp_mul_2(&x);
+    if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
+      goto CLEANUP;
+    s_mp_div_2(&x);
+
+    /* Terminate the loop, if the quotient is zero */
+    if(mp_cmp_z(&t) == MP_EQ)
+      break;
+
+    /* x = x - t       */
+    if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
+      goto CLEANUP;
+
+  }
+
+  /* Copy result to output parameter */
+  mp_sub_d(&x, 1, &x);
+  s_mp_exch(&x, b);
+
+ CLEANUP:
+  mp_clear(&x);
+ X:
+  mp_clear(&t); 
+
+  return res;
+
+} /* end mp_sqrt() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Modular arithmetic */
+
+#if MP_MODARITH
+/* {{{ mp_addmod(a, b, m, c) */
+
+/*
+  mp_addmod(a, b, m, c)
+
+  Compute c = (a + b) mod m
+ */
+
+mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_add(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_submod(a, b, m, c) */
+
+/*
+  mp_submod(a, b, m, c)
+
+  Compute c = (a - b) mod m
+ */
+
+mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_sub(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_mulmod(a, b, m, c) */
+
+/*
+  mp_mulmod(a, b, m, c)
+
+  Compute c = (a * b) mod m
+ */
+
+mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_mul(a, b, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_sqrmod(a, m, c) */
+
+#if MP_SQUARE
+mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c)
+{
+  mp_err  res;
+
+  ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_sqr(a, c)) != MP_OKAY)
+    return res;
+  if((res = mp_mod(c, m, c)) != MP_OKAY)
+    return res;
+
+  return MP_OKAY;
+
+} /* end mp_sqrmod() */
+#endif
+
+/* }}} */
+
+/* {{{ mp_exptmod(a, b, m, c) */
+
+/*
+  mp_exptmod(a, b, m, c)
+
+  Compute c = (a ** b) mod m.  Uses a standard square-and-multiply
+  method with modular reductions at each step. (This is basically the
+  same code as mp_expt(), except for the addition of the reductions)
+  
+  The modular reductions are done using Barrett's algorithm (see
+  s_mp_reduce() below for details)
+ */
+
+mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c)
+{
+  mp_int   s, x, mu;
+  mp_err   res;
+  mp_digit d, *db = DIGITS(b);
+  mp_size  ub = USED(b);
+  int      dig, bit;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
+    return MP_RANGE;
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+  if((res = mp_mod(&x, m, &x)) != MP_OKAY ||
+     (res = mp_init(&mu)) != MP_OKAY)
+    goto MU;
+
+  mp_set(&s, 1);
+
+  /* mu = b^2k / m */
+  s_mp_add_d(&mu, 1); 
+  s_mp_lshd(&mu, 2 * USED(m));
+  if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
+    goto CLEANUP;
+
+  /* Loop over digits of b in ascending order, except highest order */
+  for(dig = 0; dig < (int)(ub - 1); dig++) {
+    d = *db++;
+
+    /* Loop over the bits of the lower-order digits */
+    for(bit = 0; bit < (int)DIGIT_BIT; bit++) {
+      if(d & 1) {
+	if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	  goto CLEANUP;
+	if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+	  goto CLEANUP;
+      }
+
+      d >>= 1;
+
+      if((res = s_mp_sqr(&x)) != MP_OKAY)
+	goto CLEANUP;
+      if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+	goto CLEANUP;
+    }
+  }
+
+  /* Now do the last digit... */
+  d = *db;
+
+  while(d) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+	goto CLEANUP;
+      if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d >>= 1;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY)
+      goto CLEANUP;
+    if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+ CLEANUP:
+  mp_clear(&mu);
+ MU:
+  mp_clear(&x);
+ X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_exptmod() */
+
+/* }}} */
+
+/* {{{ mp_exptmod_d(a, d, m, c) */
+
+mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c)
+{
+  mp_int   s, x;
+  mp_err   res;
+
+  ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+  if((res = mp_init(&s)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&x, a)) != MP_OKAY)
+    goto X;
+
+  mp_set(&s, 1);
+
+  while(d != 0) {
+    if(d & 1) {
+      if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
+	 (res = mp_mod(&s, m, &s)) != MP_OKAY)
+	goto CLEANUP;
+    }
+
+    d /= 2;
+
+    if((res = s_mp_sqr(&x)) != MP_OKAY ||
+       (res = mp_mod(&x, m, &x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  s_mp_exch(&s, c);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&s);
+
+  return res;
+
+} /* end mp_exptmod_d() */
+
+/* }}} */
+#endif /* if MP_MODARITH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Comparison functions */
+
+/* {{{ mp_cmp_z(a) */
+
+/*
+  mp_cmp_z(a)
+
+  Compare a <=> 0.  Returns <0 if a<0, 0 if a=0, >0 if a>0.
+ */
+
+int    mp_cmp_z(mp_int *a)
+{
+  if(SIGN(a) == MP_NEG)
+    return MP_LT;
+  else if(USED(a) == 1 && DIGIT(a, 0) == 0)
+    return MP_EQ;
+  else
+    return MP_GT;
+
+} /* end mp_cmp_z() */
+
+/* }}} */
+
+/* {{{ mp_cmp_d(a, d) */
+
+/*
+  mp_cmp_d(a, d)
+
+  Compare a <=> d.  Returns <0 if a<d, 0 if a=d, >0 if a>d
+ */
+
+int    mp_cmp_d(mp_int *a, mp_digit d)
+{
+  ARGCHK(a != NULL, MP_EQ);
+
+  if(SIGN(a) == MP_NEG)
+    return MP_LT;
+
+  return s_mp_cmp_d(a, d);
+
+} /* end mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ mp_cmp(a, b) */
+
+int    mp_cmp(mp_int *a, mp_int *b)
+{
+  ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+  if(SIGN(a) == SIGN(b)) {
+    int  mag;
+
+    if((mag = s_mp_cmp(a, b)) == MP_EQ)
+      return MP_EQ;
+
+    if(SIGN(a) == MP_ZPOS)
+      return mag;
+    else
+      return -mag;
+
+  } else if(SIGN(a) == MP_ZPOS) {
+    return MP_GT;
+  } else {
+    return MP_LT;
+  }
+
+} /* end mp_cmp() */
+
+/* }}} */
+
+/* {{{ mp_cmp_mag(a, b) */
+
+/*
+  mp_cmp_mag(a, b)
+
+  Compares |a| <=> |b|, and returns an appropriate comparison result
+ */
+
+int    mp_cmp_mag(mp_int *a, mp_int *b)
+{
+  ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+  return s_mp_cmp(a, b);
+
+} /* end mp_cmp_mag() */
+
+/* }}} */
+
+/* {{{ mp_cmp_int(a, z) */
+
+/*
+  This just converts z to an mp_int, and uses the existing comparison
+  routines.  This is sort of inefficient, but it's not clear to me how
+  frequently this wil get used anyway.  For small positive constants,
+  you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
+ */
+int    mp_cmp_int(mp_int *a, long z)
+{
+  mp_int  tmp;
+  int     out;
+
+  ARGCHK(a != NULL, MP_EQ);
+  
+  mp_init(&tmp); mp_set_int(&tmp, z);
+  out = mp_cmp(a, &tmp);
+  mp_clear(&tmp);
+
+  return out;
+
+} /* end mp_cmp_int() */
+
+/* }}} */
+
+/* {{{ mp_isodd(a) */
+
+/*
+  mp_isodd(a)
+
+  Returns a true (non-zero) value if a is odd, false (zero) otherwise.
+ */
+int    mp_isodd(mp_int *a)
+{
+  ARGCHK(a != NULL, 0);
+
+  return (DIGIT(a, 0) & 1);
+
+} /* end mp_isodd() */
+
+/* }}} */
+
+/* {{{ mp_iseven(a) */
+
+int    mp_iseven(mp_int *a)
+{
+  return !mp_isodd(a);
+
+} /* end mp_iseven() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Number theoretic functions */
+
+#if MP_NUMTH
+/* {{{ mp_gcd(a, b, c) */
+
+/*
+  Like the old mp_gcd() function, except computes the GCD using the
+  binary algorithm due to Josef Stein in 1961 (via Knuth).
+ */
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_err   res;
+  mp_int   u, v, t;
+  mp_size  k = 0;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
+      return MP_RANGE;
+  if(mp_cmp_z(a) == MP_EQ) {
+    return mp_copy(b, c);
+  } else if(mp_cmp_z(b) == MP_EQ) {
+    return mp_copy(a, c);
+  }
+
+  if((res = mp_init(&t)) != MP_OKAY)
+    return res;
+  if((res = mp_init_copy(&u, a)) != MP_OKAY)
+    goto U;
+  if((res = mp_init_copy(&v, b)) != MP_OKAY)
+    goto V;
+
+  SIGN(&u) = MP_ZPOS;
+  SIGN(&v) = MP_ZPOS;
+
+  /* Divide out common factors of 2 until at least 1 of a, b is even */
+  while(mp_iseven(&u) && mp_iseven(&v)) {
+    s_mp_div_2(&u);
+    s_mp_div_2(&v);
+    ++k;
+  }
+
+  /* Initialize t */
+  if(mp_isodd(&u)) {
+    if((res = mp_copy(&v, &t)) != MP_OKAY)
+      goto CLEANUP;
+    
+    /* t = -v */
+    if(SIGN(&v) == MP_ZPOS)
+      SIGN(&t) = MP_NEG;
+    else
+      SIGN(&t) = MP_ZPOS;
+    
+  } else {
+    if((res = mp_copy(&u, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+  }
+
+  for(;;) {
+    while(mp_iseven(&t)) {
+      s_mp_div_2(&t);
+    }
+
+    if(mp_cmp_z(&t) == MP_GT) {
+      if((res = mp_copy(&t, &u)) != MP_OKAY)
+	goto CLEANUP;
+
+    } else {
+      if((res = mp_copy(&t, &v)) != MP_OKAY)
+	goto CLEANUP;
+
+      /* v = -t */
+      if(SIGN(&t) == MP_ZPOS)
+	SIGN(&v) = MP_NEG;
+      else
+	SIGN(&v) = MP_ZPOS;
+    }
+
+    if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+    if(s_mp_cmp_d(&t, 0) == MP_EQ)
+      break;
+  }
+
+  s_mp_2expt(&v, (mp_digit)k);       /* v = 2^k   */
+  res = mp_mul(&u, &v, c); /* c = u * v */
+
+ CLEANUP:
+  mp_clear(&v);
+ V:
+  mp_clear(&u);
+ U:
+  mp_clear(&t);
+
+  return res;
+
+} /* end mp_bgcd() */
+
+/* }}} */
+
+/* {{{ mp_lcm(a, b, c) */
+
+/* We compute the least common multiple using the rule:
+
+   ab = [a, b](a, b)
+
+   ... by computing the product, and dividing out the gcd.
+ */
+
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
+{
+  mp_int  gcd, prod;
+  mp_err  res;
+
+  ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+  /* Set up temporaries */
+  if((res = mp_init(&gcd)) != MP_OKAY)
+    return res;
+  if((res = mp_init(&prod)) != MP_OKAY)
+    goto GCD;
+
+  if((res = mp_mul(a, b, &prod)) != MP_OKAY)
+    goto CLEANUP;
+  if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
+    goto CLEANUP;
+
+  res = mp_div(&prod, &gcd, c, NULL);
+
+ CLEANUP:
+  mp_clear(&prod);
+ GCD:
+  mp_clear(&gcd);
+
+  return res;
+
+} /* end mp_lcm() */
+
+/* }}} */
+
+/* {{{ mp_xgcd(a, b, g, x, y) */
+
+/*
+  mp_xgcd(a, b, g, x, y)
+
+  Compute g = (a, b) and values x and y satisfying Bezout's identity
+  (that is, ax + by = g).  This uses the extended binary GCD algorithm
+  based on the Stein algorithm used for mp_gcd()
+ */
+
+mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y)
+{
+  mp_int   gx, xc, yc, u, v, A, B, C, D;
+  mp_int  *clean[9];
+  mp_err   res;
+  int      last = -1;
+
+  if(mp_cmp_z(b) == 0)
+    return MP_RANGE;
+
+  /* Initialize all these variables we need */
+  if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &u;
+  if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &v;
+  if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &gx;
+  if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &A;
+  if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &B;
+  if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &C;
+  if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &D;
+  if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &xc;
+  mp_abs(&xc, &xc);
+  if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP;
+  clean[++last] = &yc;
+  mp_abs(&yc, &yc);
+
+  mp_set(&gx, 1);
+
+  /* Divide by two until at least one of them is even */
+  while(mp_iseven(&xc) && mp_iseven(&yc)) {
+    s_mp_div_2(&xc);
+    s_mp_div_2(&yc);
+    if((res = s_mp_mul_2(&gx)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  mp_copy(&xc, &u);
+  mp_copy(&yc, &v);
+  mp_set(&A, 1); mp_set(&D, 1);
+
+  /* Loop through binary GCD algorithm */
+  for(;;) {
+    while(mp_iseven(&u)) {
+      s_mp_div_2(&u);
+
+      if(mp_iseven(&A) && mp_iseven(&B)) {
+	s_mp_div_2(&A); s_mp_div_2(&B);
+      } else {
+	if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP;
+	s_mp_div_2(&A);
+	if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP;
+	s_mp_div_2(&B);
+      }
+    }
+
+    while(mp_iseven(&v)) {
+      s_mp_div_2(&v);
+
+      if(mp_iseven(&C) && mp_iseven(&D)) {
+	s_mp_div_2(&C); s_mp_div_2(&D);
+      } else {
+	if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP;
+	s_mp_div_2(&C);
+	if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP;
+	s_mp_div_2(&D);
+      }
+    }
+
+    if(mp_cmp(&u, &v) >= 0) {
+      if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP;
+      if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP;
+      if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP;
+
+    } else {
+      if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP;
+      if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP;
+      if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP;
+
+    }
+
+    /* If we're done, copy results to output */
+    if(mp_cmp_z(&u) == 0) {
+      if(x)
+	if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP;
+
+      if(y)
+	if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP;
+      
+      if(g)
+	if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP;
+
+      break;
+    }
+  }
+
+ CLEANUP:
+  while(last >= 0)
+    mp_clear(clean[last--]);
+
+  return res;
+
+} /* end mp_xgcd() */
+
+/* }}} */
+
+/* {{{ mp_invmod(a, m, c) */
+
+/*
+  mp_invmod(a, m, c)
+
+  Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
+  This is equivalent to the question of whether (a, m) = 1.  If not,
+  MP_UNDEF is returned, and there is no inverse.
+ */
+
+mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c)
+{
+  mp_int  g, x;
+  mp_err  res;
+
+  ARGCHK(a && m && c, MP_BADARG);
+
+  if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+    return MP_RANGE;
+
+  if((res = mp_init(&g)) != MP_OKAY)
+    return res;
+  if((res = mp_init(&x)) != MP_OKAY)
+    goto X;
+
+  if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY)
+    goto CLEANUP;
+
+  if(mp_cmp_d(&g, 1) != MP_EQ) {
+    res = MP_UNDEF;
+    goto CLEANUP;
+  }
+
+  res = mp_mod(&x, m, c);
+  SIGN(c) = SIGN(a);
+
+CLEANUP:
+  mp_clear(&x);
+X:
+  mp_clear(&g);
+
+  return res;
+
+} /* end mp_invmod() */
+
+/* }}} */
+#endif /* if MP_NUMTH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_print(mp, ofp) */
+
+#if MP_IOFUNC
+/*
+  mp_print(mp, ofp)
+
+  Print a textual representation of the given mp_int on the output
+  stream 'ofp'.  Output is generated using the internal radix.
+ */
+
+void   mp_print(mp_int *mp, FILE *ofp)
+{
+  int   ix;
+
+  if(mp == NULL || ofp == NULL)
+    return;
+
+  fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp);
+
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
+  }
+
+} /* end mp_print() */
+
+#endif /* if MP_IOFUNC */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ More I/O Functions */
+
+/* {{{ mp_read_signed_bin(mp, str, len) */
+
+/* 
+   mp_read_signed_bin(mp, str, len)
+
+   Read in a raw value (base 256) into the given mp_int
+ */
+
+mp_err  mp_read_signed_bin(mp_int *mp, unsigned char *str, int len)
+{
+  mp_err         res;
+
+  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+  if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) {
+    /* Get sign from first byte */
+    if(str[0])
+      SIGN(mp) = MP_NEG;
+    else
+      SIGN(mp) = MP_ZPOS;
+  }
+
+  return res;
+
+} /* end mp_read_signed_bin() */
+
+/* }}} */
+
+/* {{{ mp_signed_bin_size(mp) */
+
+int    mp_signed_bin_size(mp_int *mp)
+{
+  ARGCHK(mp != NULL, 0);
+
+  return mp_unsigned_bin_size(mp) + 1;
+
+} /* end mp_signed_bin_size() */
+
+/* }}} */
+
+/* {{{ mp_to_signed_bin(mp, str) */
+
+mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str)
+{
+  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+  /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */
+  str[0] = (char)SIGN(mp);
+
+  return mp_to_unsigned_bin(mp, str + 1);
+
+} /* end mp_to_signed_bin() */
+
+/* }}} */
+
+/* {{{ mp_read_unsigned_bin(mp, str, len) */
+
+/*
+  mp_read_unsigned_bin(mp, str, len)
+
+  Read in an unsigned value (base 256) into the given mp_int
+ */
+
+mp_err  mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len)
+{
+  int     ix;
+  mp_err  res;
+
+  ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+  mp_zero(mp);
+
+  for(ix = 0; ix < len; ix++) {
+    if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY)
+      return res;
+
+    if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY)
+      return res;
+  }
+  
+  return MP_OKAY;
+  
+} /* end mp_read_unsigned_bin() */
+
+/* }}} */
+
+/* {{{ mp_unsigned_bin_size(mp) */
+
+int     mp_unsigned_bin_size(mp_int *mp) 
+{
+  mp_digit   topdig;
+  int        count;
+
+  ARGCHK(mp != NULL, 0);
+
+  /* Special case for the value zero */
+  if(USED(mp) == 1 && DIGIT(mp, 0) == 0)
+    return 1;
+
+  count = (USED(mp) - 1) * sizeof(mp_digit);
+  topdig = DIGIT(mp, USED(mp) - 1);
+
+  while(topdig != 0) {
+    ++count;
+    topdig >>= CHAR_BIT;
+  }
+
+  return count;
+
+} /* end mp_unsigned_bin_size() */
+
+/* }}} */
+
+/* {{{ mp_to_unsigned_bin(mp, str) */
+
+mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str)
+{
+  mp_digit      *dp, *end, d;
+  unsigned char *spos;
+
+  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+  dp = DIGITS(mp);
+  end = dp + USED(mp) - 1;
+  spos = str;
+
+  /* Special case for zero, quick test */
+  if(dp == end && *dp == 0) {
+    *str = '\0';
+    return MP_OKAY;
+  }
+
+  /* Generate digits in reverse order */
+  while(dp < end) {
+    int      ix;
+
+    d = *dp;
+    for(ix = 0; ix < (int)sizeof(mp_digit); ++ix) {
+      *spos = d & UCHAR_MAX;
+      d >>= CHAR_BIT;
+      ++spos;
+    }
+
+    ++dp;
+  }
+
+  /* Now handle last digit specially, high order zeroes are not written */
+  d = *end;
+  while(d != 0) {
+    *spos = d & UCHAR_MAX;
+    d >>= CHAR_BIT;
+    ++spos;
+  }
+
+  /* Reverse everything to get digits in the correct order */
+  while(--spos > str) {
+    unsigned char t = *str;
+    *str = *spos;
+    *spos = t;
+
+    ++str;
+  }
+
+  return MP_OKAY;
+
+} /* end mp_to_unsigned_bin() */
+
+/* }}} */
+
+/* {{{ mp_count_bits(mp) */
+
+int    mp_count_bits(mp_int *mp)
+{
+  int      len;
+  mp_digit d;
+
+  ARGCHK(mp != NULL, MP_BADARG);
+
+  len = DIGIT_BIT * (USED(mp) - 1);
+  d = DIGIT(mp, USED(mp) - 1);
+
+  while(d != 0) {
+    ++len;
+    d >>= 1;
+  }
+
+  return len;
+  
+} /* end mp_count_bits() */
+
+/* }}} */
+
+/* {{{ mp_read_radix(mp, str, radix) */
+
+/*
+  mp_read_radix(mp, str, radix)
+
+  Read an integer from the given string, and set mp to the resulting
+  value.  The input is presumed to be in base 10.  Leading non-digit
+  characters are ignored, and the function reads until a non-digit
+  character or the end of the string.
+ */
+
+mp_err  mp_read_radix(mp_int *mp, unsigned char *str, int radix)
+{
+  int     ix = 0, val = 0;
+  mp_err  res;
+  mp_sign sig = MP_ZPOS;
+
+  ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, 
+	 MP_BADARG);
+
+  mp_zero(mp);
+
+  /* Skip leading non-digit characters until a digit or '-' or '+' */
+  while(str[ix] && 
+	(s_mp_tovalue(str[ix], radix) < 0) && 
+	str[ix] != '-' &&
+	str[ix] != '+') {
+    ++ix;
+  }
+
+  if(str[ix] == '-') {
+    sig = MP_NEG;
+    ++ix;
+  } else if(str[ix] == '+') {
+    sig = MP_ZPOS; /* this is the default anyway... */
+    ++ix;
+  }
+
+  while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
+    if((res = s_mp_mul_d(mp, (mp_digit)radix)) != MP_OKAY)
+      return res;
+    if((res = s_mp_add_d(mp, (mp_digit)val)) != MP_OKAY)
+      return res;
+    ++ix;
+  }
+
+  if(s_mp_cmp_d(mp, 0) == MP_EQ)
+    SIGN(mp) = MP_ZPOS;
+  else
+    SIGN(mp) = sig;
+
+  return MP_OKAY;
+
+} /* end mp_read_radix() */
+
+/* }}} */
+
+/* {{{ mp_radix_size(mp, radix) */
+
+int    mp_radix_size(mp_int *mp, int radix)
+{
+  int  len;
+  ARGCHK(mp != NULL, 0);
+
+  len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */
+
+  if(mp_cmp_z(mp) < 0)
+    ++len; /* for sign */
+
+  return len;
+
+} /* end mp_radix_size() */
+
+/* }}} */
+
+/* {{{ mp_value_radix_size(num, qty, radix) */
+
+/* num = number of digits
+   qty = number of bits per digit
+   radix = target base
+   
+   Return the number of digits in the specified radix that would be
+   needed to express 'num' digits of 'qty' bits each.
+ */
+int    mp_value_radix_size(int num, int qty, int radix)
+{
+  ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0);
+
+  return s_mp_outlen(num * qty, radix);
+
+} /* end mp_value_radix_size() */
+
+/* }}} */
+
+/* {{{ mp_toradix(mp, str, radix) */
+
+mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix)
+{
+  int  ix, pos = 0;
+
+  ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+  ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
+
+  if(mp_cmp_z(mp) == MP_EQ) {
+    str[0] = '0';
+    str[1] = '\0';
+  } else {
+    mp_err   res;
+    mp_int   tmp;
+    mp_sign  sgn;
+    mp_digit rem, rdx = (mp_digit)radix;
+    char     ch;
+
+    if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
+      return res;
+
+    /* Save sign for later, and take absolute value */
+    sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS;
+
+    /* Generate output digits in reverse order      */
+    while(mp_cmp_z(&tmp) != 0) {
+      if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) {
+	mp_clear(&tmp);
+	return res;
+      }
+
+      /* Generate digits, use capital letters */
+      ch = s_mp_todigit(rem, radix, 0);
+
+      str[pos++] = ch;
+    }
+
+    /* Add - sign if original value was negative */
+    if(sgn == MP_NEG)
+      str[pos++] = '-';
+
+    /* Add trailing NUL to end the string        */
+    str[pos--] = '\0';
+
+    /* Reverse the digits and sign indicator     */
+    ix = 0;
+    while(ix < pos) {
+      char tmp = str[ix];
+
+      str[ix] = str[pos];
+      str[pos] = tmp;
+      ++ix;
+      --pos;
+    }
+    
+    mp_clear(&tmp);
+  }
+
+  return MP_OKAY;
+
+} /* end mp_toradix() */
+
+/* }}} */
+
+/* {{{ mp_char2value(ch, r) */
+
+int    mp_char2value(char ch, int r)
+{
+  return s_mp_tovalue(ch, r);
+
+} /* end mp_tovalue() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mp_strerror(ec) */
+
+/*
+  mp_strerror(ec)
+
+  Return a string describing the meaning of error code 'ec'.  The
+  string returned is allocated in static memory, so the caller should
+  not attempt to modify or free the memory associated with this
+  string.
+ */
+const char  *mp_strerror(mp_err ec)
+{
+  int   aec = (ec < 0) ? -ec : ec;
+
+  /* Code values are negative, so the senses of these comparisons
+     are accurate */
+  if(ec < MP_LAST_CODE || ec > MP_OKAY) {
+    return mp_err_string[0];  /* unknown error code */
+  } else {
+    return mp_err_string[aec + 1];
+  }
+
+} /* end mp_strerror() */
+
+/* }}} */
+
+/*========================================================================*/
+/*------------------------------------------------------------------------*/
+/* Static function definitions (internal use only)                        */
+
+/* {{{ Memory management */
+
+/* {{{ s_mp_grow(mp, min) */
+
+/* Make sure there are at least 'min' digits allocated to mp              */
+mp_err   s_mp_grow(mp_int *mp, mp_size min)
+{
+  if(min > ALLOC(mp)) {
+    mp_digit   *tmp;
+
+    /* Set min to next nearest default precision block size */
+    min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec;
+
+    if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
+      return MP_MEM;
+
+    s_mp_copy(DIGITS(mp), tmp, USED(mp));
+
+#if MP_CRYPTO
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+    s_mp_free(DIGITS(mp));
+    DIGITS(mp) = tmp;
+    ALLOC(mp) = min;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_grow() */
+
+/* }}} */
+
+/* {{{ s_mp_pad(mp, min) */
+
+/* Make sure the used size of mp is at least 'min', growing if needed     */
+mp_err   s_mp_pad(mp_int *mp, mp_size min)
+{
+  if(min > USED(mp)) {
+    mp_err  res;
+
+    /* Make sure there is room to increase precision  */
+    if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY)
+      return res;
+
+    /* Increase precision; should already be 0-filled */
+    USED(mp) = min;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_pad() */
+
+/* }}} */
+
+/* {{{ s_mp_setz(dp, count) */
+
+#if MP_MACRO == 0
+/* Set 'count' digits pointed to by dp to be zeroes                       */
+void s_mp_setz(mp_digit *dp, mp_size count)
+{
+#if MP_MEMSET == 0
+  int  ix;
+
+  for(ix = 0; ix < count; ix++)
+    dp[ix] = 0;
+#else
+  memset(dp, 0, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_setz() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_copy(sp, dp, count) */
+
+#if MP_MACRO == 0
+/* Copy 'count' digits from sp to dp                                      */
+void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count)
+{
+#if MP_MEMCPY == 0
+  int  ix;
+
+  for(ix = 0; ix < count; ix++)
+    dp[ix] = sp[ix];
+#else
+  memcpy(dp, sp, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_copy() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_alloc(nb, ni) */
+
+#if MP_MACRO == 0
+/* Allocate ni records of nb bytes each, and return a pointer to that     */
+void    *s_mp_alloc(size_t nb, size_t ni)
+{
+  return XCALLOC(nb, ni);
+
+} /* end s_mp_alloc() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_free(ptr) */
+
+#if MP_MACRO == 0
+/* Free the memory pointed to by ptr                                      */
+void     s_mp_free(void *ptr)
+{
+  if(ptr)
+    XFREE(ptr);
+
+} /* end s_mp_free() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_clamp(mp) */
+
+/* Remove leading zeroes from the given value                             */
+void     s_mp_clamp(mp_int *mp)
+{
+  mp_size   du = USED(mp);
+  mp_digit *zp = DIGITS(mp) + du - 1;
+
+  while(du > 1 && !*zp--)
+    --du;
+
+  USED(mp) = du;
+
+} /* end s_mp_clamp() */
+
+
+/* }}} */
+
+/* {{{ s_mp_exch(a, b) */
+
+/* Exchange the data for a and b; (b, a) = (a, b)                         */
+void     s_mp_exch(mp_int *a, mp_int *b)
+{
+  mp_int   tmp;
+
+  tmp = *a;
+  *a = *b;
+  *b = tmp;
+
+} /* end s_mp_exch() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Arithmetic helpers */
+
+/* {{{ s_mp_lshd(mp, p) */
+
+/* 
+   Shift mp leftward by p digits, growing if needed, and zero-filling
+   the in-shifted digits at the right end.  This is a convenient
+   alternative to multiplication by powers of the radix
+ */   
+
+mp_err   s_mp_lshd(mp_int *mp, mp_size p)
+{
+  mp_err   res;
+  mp_size  pos;
+  mp_digit *dp;
+  int     ix;
+
+  if(p == 0)
+    return MP_OKAY;
+
+  if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
+    return res;
+
+  pos = USED(mp) - 1;
+  dp = DIGITS(mp);
+
+  /* Shift all the significant figures over as needed */
+  for(ix = pos - p; ix >= 0; ix--) 
+    dp[ix + p] = dp[ix];
+
+  /* Fill the bottom digits with zeroes */
+  for(ix = 0; ix < (int)p; ix++)
+    dp[ix] = 0;
+
+  return MP_OKAY;
+
+} /* end s_mp_lshd() */
+
+/* }}} */
+
+/* {{{ s_mp_rshd(mp, p) */
+
+/* 
+   Shift mp rightward by p digits.  Maintains the invariant that
+   digits above the precision are all zero.  Digits shifted off the
+   end are lost.  Cannot fail.
+ */
+
+void     s_mp_rshd(mp_int *mp, mp_size p)
+{
+  mp_size  ix;
+  mp_digit *dp;
+
+  if(p == 0)
+    return;
+
+  /* Shortcut when all digits are to be shifted off */
+  if(p >= USED(mp)) {
+    s_mp_setz(DIGITS(mp), ALLOC(mp));
+    USED(mp) = 1;
+    SIGN(mp) = MP_ZPOS;
+    return;
+  }
+
+  /* Shift all the significant figures over as needed */
+  dp = DIGITS(mp);
+  for(ix = p; ix < USED(mp); ix++)
+    dp[ix - p] = dp[ix];
+
+  /* Fill the top digits with zeroes */
+  ix -= p;
+  while(ix < USED(mp))
+    dp[ix++] = 0;
+
+  /* Strip off any leading zeroes    */
+  s_mp_clamp(mp);
+
+} /* end s_mp_rshd() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2(mp) */
+
+/* Divide by two -- take advantage of radix properties to do it fast      */
+void     s_mp_div_2(mp_int *mp)
+{
+  s_mp_div_2d(mp, 1);
+
+} /* end s_mp_div_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2(mp) */
+
+mp_err s_mp_mul_2(mp_int *mp)
+{
+  int      ix;
+  mp_digit kin = 0, kout, *dp = DIGITS(mp);
+  mp_err   res;
+
+  /* Shift digits leftward by 1 bit */
+  for(ix = 0; ix < (int)USED(mp); ix++) {
+    kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1;
+    dp[ix] = (dp[ix] << 1) | kin;
+
+    kin = kout;
+  }
+
+  /* Deal with rollover from last digit */
+  if(kin) {
+    if(ix >= (int)ALLOC(mp)) {
+      if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
+	return res;
+      dp = DIGITS(mp);
+    }
+
+    dp[ix] = kin;
+    USED(mp) += 1;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_mul_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mod_2d(mp, d) */
+
+/*
+  Remainder the integer by 2^d, where d is a number of bits.  This
+  amounts to a bitwise AND of the value, and does not require the full
+  division code
+ */
+void     s_mp_mod_2d(mp_int *mp, mp_digit d)
+{
+  unsigned int  ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
+  unsigned int  ix;
+  mp_digit      dmask, *dp = DIGITS(mp);
+
+  if(ndig >= USED(mp))
+    return;
+
+  /* Flush all the bits above 2^d in its digit */
+  dmask = (1 << nbit) - 1;
+  dp[ndig] &= dmask;
+
+  /* Flush all digits above the one with 2^d in it */
+  for(ix = ndig + 1; ix < USED(mp); ix++)
+    dp[ix] = 0;
+
+  s_mp_clamp(mp);
+
+} /* end s_mp_mod_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2d(mp, d) */
+
+/*
+  Multiply by the integer 2^d, where d is a number of bits.  This
+  amounts to a bitwise shift of the value, and does not require the
+  full multiplication code.
+ */
+mp_err    s_mp_mul_2d(mp_int *mp, mp_digit d)
+{
+  mp_err   res;
+  mp_digit save, next, mask, *dp;
+  mp_size  used;
+  int      ix;
+
+  if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY)
+    return res;
+
+  dp = DIGITS(mp); used = USED(mp);
+  d %= DIGIT_BIT;
+
+  mask = (1 << d) - 1;
+
+  /* If the shift requires another digit, make sure we've got one to
+     work with */
+  if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) {
+    if((res = s_mp_grow(mp, used + 1)) != MP_OKAY)
+      return res;
+    dp = DIGITS(mp);
+  }
+
+  /* Do the shifting... */
+  save = 0;
+  for(ix = 0; ix < (int)used; ix++) {
+    next = (dp[ix] >> (DIGIT_BIT - d)) & mask;
+    dp[ix] = (dp[ix] << d) | save;
+    save = next;
+  }
+
+  /* If, at this point, we have a nonzero carryout into the next
+     digit, we'll increase the size by one digit, and store it...
+   */
+  if(save) {
+    dp[used] = save;
+    USED(mp) += 1;
+  }
+
+  s_mp_clamp(mp);
+  return MP_OKAY;
+
+} /* end s_mp_mul_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2d(mp, d) */
+
+/*
+  Divide the integer by 2^d, where d is a number of bits.  This
+  amounts to a bitwise shift of the value, and does not require the
+  full division code (used in Barrett reduction, see below)
+ */
+void     s_mp_div_2d(mp_int *mp, mp_digit d)
+{
+  int       ix;
+  mp_digit  save, next, mask, *dp = DIGITS(mp);
+
+  s_mp_rshd(mp, d / DIGIT_BIT);
+  d %= DIGIT_BIT;
+
+  mask = (1 << d) - 1;
+
+  save = 0;
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    next = dp[ix] & mask;
+    dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d));
+    save = next;
+  }
+
+  s_mp_clamp(mp);
+
+} /* end s_mp_div_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_norm(a, b) */
+
+/*
+  s_mp_norm(a, b)
+
+  Normalize a and b for division, where b is the divisor.  In order
+  that we might make good guesses for quotient digits, we want the
+  leading digit of b to be at least half the radix, which we
+  accomplish by multiplying a and b by a constant.  This constant is
+  returned (so that it can be divided back out of the remainder at the
+  end of the division process).
+
+  We multiply by the smallest power of 2 that gives us a leading digit
+  at least half the radix.  By choosing a power of 2, we simplify the 
+  multiplication and division steps to simple shifts.
+ */
+mp_digit s_mp_norm(mp_int *a, mp_int *b)
+{
+  mp_digit  t, d = 0;
+
+  t = DIGIT(b, USED(b) - 1);
+  while(t < (RADIX / 2)) {
+    t <<= 1;
+    ++d;
+  }
+    
+  if(d != 0) {
+    s_mp_mul_2d(a, d);
+    s_mp_mul_2d(b, d);
+  }
+
+  return d;
+
+} /* end s_mp_norm() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive digit arithmetic */
+
+/* {{{ s_mp_add_d(mp, d) */
+
+/* Add d to |mp| in place                                                 */
+mp_err   s_mp_add_d(mp_int *mp, mp_digit d)    /* unsigned digit addition */
+{
+  mp_word   w, k = 0;
+  mp_size   ix = 1, used = USED(mp);
+  mp_digit *dp = DIGITS(mp);
+
+  w = dp[0] + d;
+  dp[0] = ACCUM(w);
+  k = CARRYOUT(w);
+
+  while(ix < used && k) {
+    w = dp[ix] + k;
+    dp[ix] = ACCUM(w);
+    k = CARRYOUT(w);
+    ++ix;
+  }
+
+  if(k != 0) {
+    mp_err  res;
+
+    if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(mp, ix) = k;
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_add_d() */
+
+/* }}} */
+
+/* {{{ s_mp_sub_d(mp, d) */
+
+/* Subtract d from |mp| in place, assumes |mp| > d                        */
+mp_err   s_mp_sub_d(mp_int *mp, mp_digit d)    /* unsigned digit subtract */
+{
+  mp_word   w, b = 0;
+  mp_size   ix = 1, used = USED(mp);
+  mp_digit *dp = DIGITS(mp);
+
+  /* Compute initial subtraction    */
+  w = (RADIX + dp[0]) - d;
+  b = CARRYOUT(w) ? 0 : 1;
+  dp[0] = ACCUM(w);
+
+  /* Propagate borrows leftward     */
+  while(b && ix < used) {
+    w = (RADIX + dp[ix]) - b;
+    b = CARRYOUT(w) ? 0 : 1;
+    dp[ix] = ACCUM(w);
+    ++ix;
+  }
+
+  /* Remove leading zeroes          */
+  s_mp_clamp(mp);
+
+  /* If we have a borrow out, it's a violation of the input invariant */
+  if(b)
+    return MP_RANGE;
+  else
+    return MP_OKAY;
+
+} /* end s_mp_sub_d() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_d(a, d) */
+
+/* Compute a = a * d, single digit multiplication                         */
+mp_err   s_mp_mul_d(mp_int *a, mp_digit d)
+{
+  mp_word w, k = 0;
+  mp_size ix, max;
+  mp_err  res;
+  mp_digit *dp = DIGITS(a);
+
+  /*
+    Single-digit multiplication will increase the precision of the
+    output by at most one digit.  However, we can detect when this
+    will happen -- if the high-order digit of a, times d, gives a
+    two-digit result, then the precision of the result will increase;
+    otherwise it won't.  We use this fact to avoid calling s_mp_pad()
+    unless absolutely necessary.
+   */
+  max = USED(a);
+  w = dp[max - 1] * d;
+  if(CARRYOUT(w) != 0) {
+    if((res = s_mp_pad(a, max + 1)) != MP_OKAY)
+      return res;
+    dp = DIGITS(a);
+  }
+
+  for(ix = 0; ix < max; ix++) {
+    w = (dp[ix] * d) + k;
+    dp[ix] = ACCUM(w);
+    k = CARRYOUT(w);
+  }
+
+  /* If there is a precision increase, take care of it here; the above
+     test guarantees we have enough storage to do this safely.
+   */
+  if(k) {
+    dp[max] = k; 
+    USED(a) = max + 1;
+  }
+
+  s_mp_clamp(a);
+
+  return MP_OKAY;
+  
+} /* end s_mp_mul_d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_d(mp, d, r) */
+
+/*
+  s_mp_div_d(mp, d, r)
+
+  Compute the quotient mp = mp / d and remainder r = mp mod d, for a
+  single digit d.  If r is null, the remainder will be discarded.
+ */
+
+mp_err   s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
+{
+  mp_word   w = 0, t;
+  mp_int    quot;
+  mp_err    res;
+  mp_digit *dp = DIGITS(mp), *qp;
+  int       ix;
+
+  if(d == 0)
+    return MP_RANGE;
+
+  /* Make room for the quotient */
+  if((res = mp_init_size(&quot, USED(mp))) != MP_OKAY)
+    return res;
+
+  USED(&quot) = USED(mp); /* so clamping will work below */
+  qp = DIGITS(&quot);
+
+  /* Divide without subtraction */
+  for(ix = USED(mp) - 1; ix >= 0; ix--) {
+    w = (w << DIGIT_BIT) | dp[ix];
+
+    if(w >= d) {
+      t = w / d;
+      w = w % d;
+    } else {
+      t = 0;
+    }
+
+    qp[ix] = t;
+  }
+
+  /* Deliver the remainder, if desired */
+  if(r)
+    *r = w;
+
+  s_mp_clamp(&quot);
+  mp_exch(&quot, mp);
+  mp_clear(&quot);
+
+  return MP_OKAY;
+
+} /* end s_mp_div_d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive full arithmetic */
+
+/* {{{ s_mp_add(a, b) */
+
+/* Compute a = |a| + |b|                                                  */
+mp_err   s_mp_add(mp_int *a, mp_int *b)        /* magnitude addition      */
+{
+  mp_word   w = 0;
+  mp_digit *pa, *pb;
+  mp_size   ix, used = USED(b);
+  mp_err    res;
+
+  /* Make sure a has enough precision for the output value */
+  if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY)
+    return res;
+
+  /*
+    Add up all digits up to the precision of b.  If b had initially
+    the same precision as a, or greater, we took care of it by the
+    padding step above, so there is no problem.  If b had initially
+    less precision, we'll have to make sure the carry out is duly
+    propagated upward among the higher-order digits of the sum.
+   */
+  pa = DIGITS(a);
+  pb = DIGITS(b);
+  for(ix = 0; ix < used; ++ix) {
+    w += *pa + *pb++;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w);
+  }
+
+  /* If we run out of 'b' digits before we're actually done, make
+     sure the carries get propagated upward...  
+   */
+  used = USED(a);
+  while(w && ix < used) {
+    w += *pa;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w);
+    ++ix;
+  }
+
+  /* If there's an overall carry out, increase precision and include
+     it.  We could have done this initially, but why touch the memory
+     allocator unless we're sure we have to?
+   */
+  if(w) {
+    if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
+      return res;
+
+    DIGIT(a, ix) = w;  /* pa may not be valid after s_mp_pad() call */
+  }
+
+  return MP_OKAY;
+
+} /* end s_mp_add() */
+
+/* }}} */
+
+/* {{{ s_mp_sub(a, b) */
+
+/* Compute a = |a| - |b|, assumes |a| >= |b|                              */
+mp_err   s_mp_sub(mp_int *a, mp_int *b)        /* magnitude subtract      */
+{
+  mp_word   w = 0;
+  mp_digit *pa, *pb;
+  mp_size   ix, used = USED(b);
+
+  /*
+    Subtract and propagate borrow.  Up to the precision of b, this
+    accounts for the digits of b; after that, we just make sure the
+    carries get to the right place.  This saves having to pad b out to
+    the precision of a just to make the loops work right...
+   */
+  pa = DIGITS(a);
+  pb = DIGITS(b);
+
+  for(ix = 0; ix < used; ++ix) {
+    w = (RADIX + *pa) - w - *pb++;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w) ? 0 : 1;
+  }
+
+  used = USED(a);
+  while(ix < used) {
+    w = RADIX + *pa - w;
+    *pa++ = ACCUM(w);
+    w = CARRYOUT(w) ? 0 : 1;
+    ++ix;
+  }
+
+  /* Clobber any leading zeroes we created    */
+  s_mp_clamp(a);
+
+  /* 
+     If there was a borrow out, then |b| > |a| in violation
+     of our input invariant.  We've already done the work,
+     but we'll at least complain about it...
+   */
+  if(w)
+    return MP_RANGE;
+  else
+    return MP_OKAY;
+
+} /* end s_mp_sub() */
+
+/* }}} */
+
+/* {{{ s_mp_mul(a, b) */
+
+/* Compute a = |a| * |b|                                                  */
+mp_err   s_mp_mul(mp_int *a, mp_int *b)
+{
+  mp_word   w, k = 0;
+  mp_int    tmp;
+  mp_err    res;
+  mp_size   ix, jx, ua = USED(a), ub = USED(b);
+  mp_digit *pa, *pb, *pt, *pbt;
+
+  if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY)
+    return res;
+
+  /* This has the effect of left-padding with zeroes... */
+  USED(&tmp) = ua + ub;
+
+  /* We're going to need the base value each iteration */
+  pbt = DIGITS(&tmp);
+
+  /* Outer loop:  Digits of b */
+
+  pb = DIGITS(b);
+  for(ix = 0; ix < ub; ++ix, ++pb) {
+    if(*pb == 0) 
+      continue;
+
+    /* Inner product:  Digits of a */
+    pa = DIGITS(a);
+    for(jx = 0; jx < ua; ++jx, ++pa) {
+      pt = pbt + ix + jx;
+      w = *pb * *pa + k + *pt;
+      *pt = ACCUM(w);
+      k = CARRYOUT(w);
+    }
+
+    pbt[ix + jx] = k;
+    k = 0;
+  }
+
+  s_mp_clamp(&tmp);
+  s_mp_exch(&tmp, a);
+
+  mp_clear(&tmp);
+
+  return MP_OKAY;
+
+} /* end s_mp_mul() */
+
+/* }}} */
+
+/* {{{ s_mp_kmul(a, b, out, len) */
+
+#if 0
+void   s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len)
+{
+  mp_word   w, k = 0;
+  mp_size   ix, jx;
+  mp_digit *pa, *pt;
+
+  for(ix = 0; ix < len; ++ix, ++b) {
+    if(*b == 0)
+      continue;
+    
+    pa = a;
+    for(jx = 0; jx < len; ++jx, ++pa) {
+      pt = out + ix + jx;
+      w = *b * *pa + k + *pt;
+      *pt = ACCUM(w);
+      k = CARRYOUT(w);
+    }
+
+    out[ix + jx] = k;
+    k = 0;
+  }
+
+} /* end s_mp_kmul() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_sqr(a) */
+
+/*
+  Computes the square of a, in place.  This can be done more
+  efficiently than a general multiplication, because many of the
+  computation steps are redundant when squaring.  The inner product
+  step is a bit more complicated, but we save a fair number of
+  iterations of the multiplication loop.
+ */
+#if MP_SQUARE
+mp_err   s_mp_sqr(mp_int *a)
+{
+  mp_word  w, k = 0;
+  mp_int   tmp;
+  mp_err   res;
+  mp_size  ix, jx, kx, used = USED(a);
+  mp_digit *pa1, *pa2, *pt, *pbt;
+
+  if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY)
+    return res;
+
+  /* Left-pad with zeroes */
+  USED(&tmp) = 2 * used;
+
+  /* We need the base value each time through the loop */
+  pbt = DIGITS(&tmp);
+
+  pa1 = DIGITS(a);
+  for(ix = 0; ix < used; ++ix, ++pa1) {
+    if(*pa1 == 0)
+      continue;
+
+    w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1);
+
+    pbt[ix + ix] = ACCUM(w);
+    k = CARRYOUT(w);
+
+    /*
+      The inner product is computed as:
+
+         (C, S) = t[i,j] + 2 a[i] a[j] + C
+
+      This can overflow what can be represented in an mp_word, and
+      since C arithmetic does not provide any way to check for
+      overflow, we have to check explicitly for overflow conditions
+      before they happen.
+     */
+    for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) {
+      mp_word  u = 0, v;
+      
+      /* Store this in a temporary to avoid indirections later */
+      pt = pbt + ix + jx;
+
+      /* Compute the multiplicative step */
+      w = *pa1 * *pa2;
+
+      /* If w is more than half MP_WORD_MAX, the doubling will
+	 overflow, and we need to record a carry out into the next
+	 word */
+      u = (w >> (MP_WORD_BIT - 1)) & 1;
+
+      /* Double what we've got, overflow will be ignored as defined
+	 for C arithmetic (we've already noted if it is to occur)
+       */
+      w *= 2;
+
+      /* Compute the additive step */
+      v = *pt + k;
+
+      /* If we do not already have an overflow carry, check to see
+	 if the addition will cause one, and set the carry out if so 
+       */
+      u |= ((MP_WORD_MAX - v) < w);
+
+      /* Add in the rest, again ignoring overflow */
+      w += v;
+
+      /* Set the i,j digit of the output */
+      *pt = ACCUM(w);
+
+      /* Save carry information for the next iteration of the loop.
+	 This is why k must be an mp_word, instead of an mp_digit */
+      k = CARRYOUT(w) | (u << DIGIT_BIT);
+
+    } /* for(jx ...) */
+
+    /* Set the last digit in the cycle and reset the carry */
+    k = DIGIT(&tmp, ix + jx) + k;
+    pbt[ix + jx] = ACCUM(k);
+    k = CARRYOUT(k);
+
+    /* If we are carrying out, propagate the carry to the next digit
+       in the output.  This may cascade, so we have to be somewhat
+       circumspect -- but we will have enough precision in the output
+       that we won't overflow 
+     */
+    kx = 1;
+    while(k) {
+      k = pbt[ix + jx + kx] + 1;
+      pbt[ix + jx + kx] = ACCUM(k);
+      k = CARRYOUT(k);
+      ++kx;
+    }
+  } /* for(ix ...) */
+
+  s_mp_clamp(&tmp);
+  s_mp_exch(&tmp, a);
+
+  mp_clear(&tmp);
+
+  return MP_OKAY;
+
+} /* end s_mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_div(a, b) */
+
+/*
+  s_mp_div(a, b)
+
+  Compute a = a / b and b = a mod b.  Assumes b > a.
+ */
+
+mp_err   s_mp_div(mp_int *a, mp_int *b)
+{
+  mp_int   quot, rem, t;
+  mp_word  q;
+  mp_err   res;
+  mp_digit d;
+  int      ix;
+
+  if(mp_cmp_z(b) == 0)
+    return MP_RANGE;
+
+  /* Shortcut if b is power of two */
+  if((ix = s_mp_ispow2(b)) >= 0) {
+    mp_copy(a, b);  /* need this for remainder */
+    s_mp_div_2d(a, (mp_digit)ix);
+    s_mp_mod_2d(b, (mp_digit)ix);
+
+    return MP_OKAY;
+  }
+
+  /* Allocate space to store the quotient */
+  if((res = mp_init_size(&quot, USED(a))) != MP_OKAY)
+    return res;
+
+  /* A working temporary for division     */
+  if((res = mp_init_size(&t, USED(a))) != MP_OKAY)
+    goto T;
+
+  /* Allocate space for the remainder     */
+  if((res = mp_init_size(&rem, USED(a))) != MP_OKAY)
+    goto REM;
+
+  /* Normalize to optimize guessing       */
+  d = s_mp_norm(a, b);
+
+  /* Perform the division itself...woo!   */
+  ix = USED(a) - 1;
+
+  while(ix >= 0) {
+    /* Find a partial substring of a which is at least b */
+    while(s_mp_cmp(&rem, b) < 0 && ix >= 0) {
+      if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) 
+	goto CLEANUP;
+
+      if((res = s_mp_lshd(&quot, 1)) != MP_OKAY)
+	goto CLEANUP;
+
+      DIGIT(&rem, 0) = DIGIT(a, ix);
+      s_mp_clamp(&rem);
+      --ix;
+    }
+
+    /* If we didn't find one, we're finished dividing    */
+    if(s_mp_cmp(&rem, b) < 0) 
+      break;    
+
+    /* Compute a guess for the next quotient digit       */
+    q = DIGIT(&rem, USED(&rem) - 1);
+    if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1)
+      q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2);
+
+    q /= DIGIT(b, USED(b) - 1);
+
+    /* The guess can be as much as RADIX + 1 */
+    if(q >= RADIX)
+      q = RADIX - 1;
+
+    /* See what that multiplies out to                   */
+    mp_copy(b, &t);
+    if((res = s_mp_mul_d(&t, (mp_digit)q)) != MP_OKAY)
+      goto CLEANUP;
+
+    /* 
+       If it's too big, back it off.  We should not have to do this
+       more than once, or, in rare cases, twice.  Knuth describes a
+       method by which this could be reduced to a maximum of once, but
+       I didn't implement that here.
+     */
+    while(s_mp_cmp(&t, &rem) > 0) {
+      --q;
+      s_mp_sub(&t, b);
+    }
+
+    /* At this point, q should be the right next digit   */
+    if((res = s_mp_sub(&rem, &t)) != MP_OKAY)
+      goto CLEANUP;
+
+    /*
+      Include the digit in the quotient.  We allocated enough memory
+      for any quotient we could ever possibly get, so we should not
+      have to check for failures here
+     */
+    DIGIT(&quot, 0) = q;
+  }
+
+  /* Denormalize remainder                */
+  if(d != 0) 
+    s_mp_div_2d(&rem, d);
+
+  s_mp_clamp(&quot);
+  s_mp_clamp(&rem);
+
+  /* Copy quotient back to output         */
+  s_mp_exch(&quot, a);
+  
+  /* Copy remainder back to output        */
+  s_mp_exch(&rem, b);
+
+CLEANUP:
+  mp_clear(&rem);
+REM:
+  mp_clear(&t);
+T:
+  mp_clear(&quot);
+
+  return res;
+
+} /* end s_mp_div() */
+
+/* }}} */
+
+/* {{{ s_mp_2expt(a, k) */
+
+mp_err   s_mp_2expt(mp_int *a, mp_digit k)
+{
+  mp_err    res;
+  mp_size   dig, bit;
+
+  dig = k / DIGIT_BIT;
+  bit = k % DIGIT_BIT;
+
+  mp_zero(a);
+  if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
+    return res;
+  
+  DIGIT(a, dig) |= (1 << bit);
+
+  return MP_OKAY;
+
+} /* end s_mp_2expt() */
+
+/* }}} */
+
+/* {{{ s_mp_reduce(x, m, mu) */
+
+/*
+  Compute Barrett reduction, x (mod m), given a precomputed value for
+  mu = b^2k / m, where b = RADIX and k = #digits(m).  This should be
+  faster than straight division, when many reductions by the same
+  value of m are required (such as in modular exponentiation).  This
+  can nearly halve the time required to do modular exponentiation,
+  as compared to using the full integer divide to reduce.
+
+  This algorithm was derived from the _Handbook of Applied
+  Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
+  pp. 603-604.  
+ */
+
+mp_err   s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu)
+{
+  mp_int   q;
+  mp_err   res;
+  mp_size  um = USED(m);
+
+  if((res = mp_init_copy(&q, x)) != MP_OKAY)
+    return res;
+
+  s_mp_rshd(&q, um - 1);       /* q1 = x / b^(k-1)  */
+  s_mp_mul(&q, mu);            /* q2 = q1 * mu      */
+  s_mp_rshd(&q, um + 1);       /* q3 = q2 / b^(k+1) */
+
+  /* x = x mod b^(k+1), quick (no division) */
+  s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1)));
+
+  /* q = q * m mod b^(k+1), quick (no division) */
+  s_mp_mul(&q, m);
+  s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1)));
+
+  /* x = x - q */
+  if((res = mp_sub(x, &q, x)) != MP_OKAY)
+    goto CLEANUP;
+
+  /* If x < 0, add b^(k+1) to it */
+  if(mp_cmp_z(x) < 0) {
+    mp_set(&q, 1);
+    if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY)
+      goto CLEANUP;
+    if((res = mp_add(x, &q, x)) != MP_OKAY)
+      goto CLEANUP;
+  }
+
+  /* Back off if it's too big */
+  while(mp_cmp(x, m) >= 0) {
+    if((res = s_mp_sub(x, m)) != MP_OKAY)
+      break;
+  }
+
+ CLEANUP:
+  mp_clear(&q);
+
+  return res;
+
+} /* end s_mp_reduce() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive comparisons */
+
+/* {{{ s_mp_cmp(a, b) */
+
+/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b           */
+int      s_mp_cmp(mp_int *a, mp_int *b)
+{
+  mp_size   ua = USED(a), ub = USED(b);
+
+  if(ua > ub)
+    return MP_GT;
+  else if(ua < ub)
+    return MP_LT;
+  else {
+    int      ix = ua - 1;
+    mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix;
+
+    while(ix >= 0) {
+      if(*ap > *bp)
+	return MP_GT;
+      else if(*ap < *bp)
+	return MP_LT;
+
+      --ap; --bp; --ix;
+    }
+
+    return MP_EQ;
+  }
+
+} /* end s_mp_cmp() */
+
+/* }}} */
+
+/* {{{ s_mp_cmp_d(a, d) */
+
+/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d             */
+int      s_mp_cmp_d(mp_int *a, mp_digit d)
+{
+  mp_size  ua = USED(a);
+  mp_digit *ap = DIGITS(a);
+
+  if(ua > 1)
+    return MP_GT;
+
+  if(*ap < d) 
+    return MP_LT;
+  else if(*ap > d)
+    return MP_GT;
+  else
+    return MP_EQ;
+
+} /* end s_mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2(v) */
+
+/*
+  Returns -1 if the value is not a power of two; otherwise, it returns
+  k such that v = 2^k, i.e. lg(v).
+ */
+int      s_mp_ispow2(mp_int *v)
+{
+  mp_digit d, *dp;
+  mp_size  uv = USED(v);
+  int      extra = 0, ix;
+
+  d = DIGIT(v, uv - 1); /* most significant digit of v */
+
+  while(d && ((d & 1) == 0)) {
+    d >>= 1;
+    ++extra;
+  }
+
+  if(d == 1) {
+    ix = uv - 2;
+    dp = DIGITS(v) + ix;
+
+    while(ix >= 0) {
+      if(*dp)
+	return -1; /* not a power of two */
+
+      --dp; --ix;
+    }
+
+    return ((uv - 1) * DIGIT_BIT) + extra;
+  } 
+
+  return -1;
+
+} /* end s_mp_ispow2() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2d(d) */
+
+int      s_mp_ispow2d(mp_digit d)
+{
+  int   pow = 0;
+
+  while((d & 1) == 0) {
+    ++pow; d >>= 1;
+  }
+
+  if(d == 1)
+    return pow;
+
+  return -1;
+
+} /* end s_mp_ispow2d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive I/O helpers */
+
+/* {{{ s_mp_tovalue(ch, r) */
+
+/*
+  Convert the given character to its digit value, in the given radix.
+  If the given character is not understood in the given radix, -1 is
+  returned.  Otherwise the digit's numeric value is returned.
+
+  The results will be odd if you use a radix < 2 or > 62, you are
+  expected to know what you're up to.
+ */
+int      s_mp_tovalue(char ch, int r)
+{
+  int    val, xch;
+  
+  if(r > 36)
+    xch = ch;
+  else
+    xch = toupper(ch);
+
+  if(isdigit(xch))
+    val = xch - '0';
+  else if(isupper(xch))
+    val = xch - 'A' + 10;
+  else if(islower(xch))
+    val = xch - 'a' + 36;
+  else if(xch == '+')
+    val = 62;
+  else if(xch == '/')
+    val = 63;
+  else 
+    return -1;
+
+  if(val < 0 || val >= r)
+    return -1;
+
+  return val;
+
+} /* end s_mp_tovalue() */
+
+/* }}} */
+
+/* {{{ s_mp_todigit(val, r, low) */
+
+/*
+  Convert val to a radix-r digit, if possible.  If val is out of range
+  for r, returns zero.  Otherwise, returns an ASCII character denoting
+  the value in the given radix.
+
+  The results may be odd if you use a radix < 2 or > 64, you are
+  expected to know what you're doing.
+ */
+  
+char     s_mp_todigit(int val, int r, int low)
+{
+  char   ch;
+
+  if(val < 0 || val >= r)
+    return 0;
+
+  ch = s_dmap_1[val];
+
+  if(r <= 36 && low)
+    ch = tolower(ch);
+
+  return ch;
+
+} /* end s_mp_todigit() */
+
+/* }}} */
+
+/* {{{ s_mp_outlen(bits, radix) */
+
+/* 
+   Return an estimate for how long a string is needed to hold a radix
+   r representation of a number with 'bits' significant bits.
+
+   Does not include space for a sign or a NUL terminator.
+ */
+int      s_mp_outlen(int bits, int r)
+{
+  return (int)((double)bits * LOG_V_2(r));
+
+} /* end s_mp_outlen() */
+
+/* }}} */
+
+/* }}} */
+
+#endif /* MPI */
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS                                                  */
+
+ 

+ 225 - 0
mpi.h

@@ -0,0 +1,225 @@
+/*
+    mpi.h
+
+    by Michael J. Fromberger <[email protected]>
+    Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved
+
+    Arbitrary precision integer arithmetic library
+
+    $ID$
+ */
+
+#ifndef _H_MPI_
+#define _H_MPI_
+
+#include "mpi-config.h"
+
+#define  MP_LT       -1
+#define  MP_EQ        0
+#define  MP_GT        1
+
+#if MP_DEBUG
+#undef MP_IOFUNC
+#define MP_IOFUNC 1
+#endif
+
+#if MP_IOFUNC
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+#include <limits.h>
+
+#define  MP_NEG  1
+#define  MP_ZPOS 0
+
+/* Included for compatibility... */
+#define  NEG     MP_NEG
+#define  ZPOS    MP_ZPOS
+
+#define  MP_OKAY          0 /* no error, all is well */
+#define  MP_YES           0 /* yes (boolean result)  */
+#define  MP_NO           -1 /* no (boolean result)   */
+#define  MP_MEM          -2 /* out of memory         */
+#define  MP_RANGE        -3 /* argument out of range */
+#define  MP_BADARG       -4 /* invalid parameter     */
+#define  MP_UNDEF        -5 /* answer is undefined   */
+#define  MP_LAST_CODE    MP_UNDEF
+
+#include "mpi-types.h"
+
+/* Included for compatibility... */
+#define DIGIT_BIT         MP_DIGIT_BIT
+#define DIGIT_MAX         MP_DIGIT_MAX
+
+/* Macros for accessing the mp_int internals           */
+#define  SIGN(MP)     ((MP)->sign)
+#define  USED(MP)     ((MP)->used)
+#define  ALLOC(MP)    ((MP)->alloc)
+#define  DIGITS(MP)   ((MP)->dp)
+#define  DIGIT(MP,N)  (MP)->dp[(N)]
+
+#if MP_ARGCHK == 1
+#define  ARGCHK(X,Y)  {if(!(X)){return (Y);}}
+#elif MP_ARGCHK == 2
+#include <assert.h>
+#define  ARGCHK(X,Y)  assert(X)
+#else
+#define  ARGCHK(X,Y)  /*  */
+#endif
+
+/* This defines the maximum I/O base (minimum is 2)   */
+#define MAX_RADIX         64
+
+typedef struct {
+  mp_sign       sign;    /* sign of this quantity      */
+  mp_size       alloc;   /* how many digits allocated  */
+  mp_size       used;    /* how many digits used       */
+  mp_digit     *dp;      /* the digits themselves      */
+} mp_int;
+
+/*------------------------------------------------------------------------*/
+/* Default precision                                                      */
+
+unsigned int mp_get_prec(void);
+void         mp_set_prec(unsigned int prec);
+
+/*------------------------------------------------------------------------*/
+/* Memory management                                                      */
+
+mp_err mp_init(mp_int *mp);
+mp_err mp_init_array(mp_int mp[], int count);
+mp_err mp_init_size(mp_int *mp, mp_size prec);
+mp_err mp_init_copy(mp_int *mp, mp_int *from);
+mp_err mp_copy(mp_int *from, mp_int *to);
+void   mp_exch(mp_int *mp1, mp_int *mp2);
+void   mp_clear(mp_int *mp);
+void   mp_clear_array(mp_int mp[], int count);
+void   mp_zero(mp_int *mp);
+void   mp_set(mp_int *mp, mp_digit d);
+mp_err mp_set_int(mp_int *mp, long z);
+
+/*------------------------------------------------------------------------*/
+/* Single digit arithmetic                                                */
+
+mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_2(mp_int *a, mp_int *c);
+mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r);
+mp_err mp_div_2(mp_int *a, mp_int *c);
+mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c);
+
+/*------------------------------------------------------------------------*/
+/* Sign manipulations                                                     */
+
+mp_err mp_abs(mp_int *a, mp_int *b);
+mp_err mp_neg(mp_int *a, mp_int *b);
+
+/*------------------------------------------------------------------------*/
+/* Full arithmetic                                                        */
+
+mp_err mp_add(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqr(mp_int *a, mp_int *b);
+#else
+#define mp_sqr(a, b) mp_mul(a, a, b)
+#endif
+mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r);
+mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r);
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_2expt(mp_int *a, mp_digit k);
+mp_err mp_sqrt(mp_int *a, mp_int *b);
+
+/*------------------------------------------------------------------------*/
+/* Modular arithmetic                                                     */
+
+#if MP_MODARITH
+mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c);
+mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c);
+mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c);
+mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c);
+mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c);
+#else
+#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c)
+#endif
+mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c);
+mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c);
+#endif /* MP_MODARITH */
+
+/*------------------------------------------------------------------------*/
+/* Comparisons                                                            */
+
+int    mp_cmp_z(mp_int *a);
+int    mp_cmp_d(mp_int *a, mp_digit d);
+int    mp_cmp(mp_int *a, mp_int *b);
+int    mp_cmp_mag(mp_int *a, mp_int *b);
+int    mp_cmp_int(mp_int *a, long z);
+int    mp_isodd(mp_int *a);
+int    mp_iseven(mp_int *a);
+
+/*------------------------------------------------------------------------*/
+/* Number theoretic                                                       */
+
+#if MP_NUMTH
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y);
+mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c);
+#endif /* end MP_NUMTH */
+
+/*------------------------------------------------------------------------*/
+/* Input and output                                                       */
+
+#if MP_IOFUNC
+void   mp_print(mp_int *mp, FILE *ofp);
+#endif /* end MP_IOFUNC */
+
+/*------------------------------------------------------------------------*/
+/* Base conversion                                                        */
+
+#define BITS     1
+#define BYTES    CHAR_BIT
+
+mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len);
+int    mp_signed_bin_size(mp_int *mp);
+mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str);
+
+mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len);
+int    mp_unsigned_bin_size(mp_int *mp);
+mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str);
+
+int    mp_count_bits(mp_int *mp);
+
+#if MP_COMPAT_MACROS
+#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
+#define mp_raw_size(mp)           mp_signed_bin_size(mp)
+#define mp_toraw(mp, str)         mp_to_signed_bin((mp), (str))
+#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp)           mp_unsigned_bin_size(mp)
+#define mp_tomag(mp, str)         mp_to_unsigned_bin((mp), (str))
+#endif
+
+mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix);
+int    mp_radix_size(mp_int *mp, int radix);
+int    mp_value_radix_size(int num, int qty, int radix);
+mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix);
+
+int    mp_char2value(char ch, int r);
+
+#define mp_tobinary(M, S)  mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S)   mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S)     mp_toradix((M), (S), 16)
+
+/*------------------------------------------------------------------------*/
+/* Error strings                                                          */
+
+const  char  *mp_strerror(mp_err ec);
+
+#endif /* end _H_MPI_ */

+ 75 - 0
mycrypt.h

@@ -0,0 +1,75 @@
+#ifndef CRYPT_H_
+#define CRYPT_H_
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version */
+#define CRYPT   0x0075
+#define SCRYPT  "0.75"
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE           128
+
+/* error codes [will be expanded in future releases] */
+enum {
+   CRYPT_OK=0,
+   CRYPT_ERROR,
+
+   CRYPT_INVALID_KEYSIZE,
+   CRYPT_INVALID_ROUNDS,
+   CRYPT_FAIL_TESTVECTOR,
+
+   CRYPT_BUFFER_OVERFLOW,
+   CRYPT_INVALID_PACKET,
+
+   CRYPT_INVALID_PRNGSIZE,
+   CRYPT_ERROR_READPRNG,
+
+   CRYPT_INVALID_CIPHER,
+   CRYPT_INVALID_HASH,
+   CRYPT_INVALID_PRNG,
+
+   CRYPT_MEM,
+
+   CRYPT_PK_TYPE_MISMATCH,
+   CRYPT_PK_NOT_PRIVATE,
+
+   CRYPT_INVALID_ARG,
+
+   CRYPT_PK_INVALID_TYPE,
+   CRYPT_PK_INVALID_SYSTEM,
+   CRYPT_PK_DUP,
+   CRYPT_PK_NOT_FOUND,
+   CRYPT_PK_INVALID_SIZE,
+
+   CRYPT_INVALID_PRIME_SIZE
+};
+
+#include <mycrypt_cfg.h>
+#include <mycrypt_macros.h>
+#include <mycrypt_cipher.h>
+#include <mycrypt_hash.h>
+#include <mycrypt_prng.h>
+#include <mycrypt_pk.h>
+#include <mycrypt_gf.h>
+#include <mycrypt_misc.h>
+#include <mycrypt_kr.h>
+
+#include <mycrypt_argchk.h>
+
+
+#ifdef __cplusplus
+   }
+#endif
+
+#endif /* CRYPT_H_ */
+

+ 41 - 0
mycrypt_argchk.h

@@ -0,0 +1,41 @@
+/* Defines the _ARGCHK macro used within the library */
+
+/* ARGTYPE is defined in mycrypt_cfg.h */
+#if ARGTYPE == 0
+
+#include <signal.h>
+
+/* this is the default LibTomCrypt macro 
+ *
+ * On embedded platforms you can change the fprintf() to be a routine that would display a message
+ * somehow 
+ */
+#ifndef SONY_PS2
+
+#define _ARGCHK(x) \
+    if (!(x)) { \
+        fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \
+        raise(SIGABRT); \
+    }
+
+#else
+
+#define _ARGCHK(x) \
+    if (!(x)) { \
+        printf("_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \
+        raise(SIGABRT); \
+    }
+
+#endif  /* SONY_PS2 */
+
+#elif ARGTYPE == 1
+
+/* fatal type of error */
+#define _ARGCHK(x) assert((x))
+
+#elif ARGTYPE == 2
+
+#define _ARGCHK(x) 
+
+#endif
+

+ 122 - 0
mycrypt_cfg.h

@@ -0,0 +1,122 @@
+/* This is the build config file.
+ *
+ * With this you can setup what to inlcude/exclude automatically during any build.  Just comment
+ * out the line that #define's the word for the thing you want to remove.  phew!
+ */
+
+#ifndef MYCRYPT_CFG_H
+#define MYCRYPT_CFG_H
+
+/* you can change how memory allocation works ... */
+extern void *XMALLOC(size_t n);
+extern void *XCALLOC(size_t n, size_t s);
+extern void XFREE(void *p);
+
+/* change the clock function too */
+extern clock_t XCLOCK(void);
+
+/* type of argument checking, 0=default, 1=fatal and 2=none */
+#define ARGTYPE  0
+
+/* Controls endianess and size of registers.  Leave uncommented to get platform neutral [slower] code */
+/* detect x86-32 machines somewhat */
+#if (defined(_MSC_VER) && defined(WIN32))  || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__)))
+   #define ENDIAN_LITTLE
+   #define ENDIAN_32BITWORD
+#endif
+
+/* detects MIPS R5900 processors (PS2) */
+#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
+   #define ENDIAN_LITTLE
+   #define ENDIAN_64BITWORD
+#endif
+
+/* #define ENDIAN_LITTLE */
+/* #define ENDIAN_BIG */
+
+/* #define ENDIAN_32BITWORD */
+/* #define ENDIAN_64BITWORD */
+
+#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+    #error You must specify a word size as well as endianess in mycrypt_cfg.h
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+   #define ENDIAN_NEUTRAL
+#endif
+
+#ifdef SHA384
+   #ifndef SHA512
+      #error The SHA384 hash requires SHA512 to be defined!
+   #endif
+#endif
+
+#ifdef YARROW
+   #ifndef CTR
+      #error YARROW Requires CTR mode
+   #endif
+#endif
+
+/* packet code */
+#if defined(MRSA) || defined(MDH) || defined(MECC)
+    #define PACKET
+
+    /* size of a packet header in bytes */
+    #define PACKET_SIZE            8
+
+    /* Section tags */
+    #define PACKET_SECT_RSA        0
+    #define PACKET_SECT_DH         1
+    #define PACKET_SECT_ECC        2
+
+    /* Subsection Tags for the first three sections */
+    #define PACKET_SUB_KEY         0
+    #define PACKET_SUB_ENCRYPTED   1
+    #define PACKET_SUB_SIGNED      2
+    #define PACKET_SUB_ENC_KEY     3
+#endif
+
+/* Diffie-Hellman key settings you can omit ones you don't want to save space */
+#ifdef MDH
+
+#define DH512
+#define DH768
+#define DH1024
+#define DH1280
+#define DH1536
+#define DH1792
+#define DH2048
+#define DH2560
+#define DH3072
+#define DH4096
+
+#endif /* MDH */
+
+/* ECC Key settings */
+#ifdef MECC 
+
+#define ECC160
+#define ECC192
+#define ECC224
+#define ECC256
+#define ECC384
+#define ECC521
+
+#endif /* MECC */
+
+#ifdef MPI
+   #include "mpi.h"
+#else
+   #ifdef MRSA
+      #error RSA requires the big int library 
+   #endif
+   #ifdef MECC
+      #error ECC requires the big int library 
+   #endif
+   #ifdef MDH
+      #error DH requires the big int library 
+   #endif
+#endif /* MPI */
+
+#endif /* MYCRYPT_CFG_H */
+

+ 349 - 0
mycrypt_cipher.h

@@ -0,0 +1,349 @@
+/* ---- SYMMETRIC KEY STUFF -----
+ *
+ * We put each of the ciphers scheduled keys in their own structs then we put all of 
+ * the key formats in one union.  This makes the function prototypes easier to use.
+ */
+#ifdef BLOWFISH
+struct blowfish_key {
+   unsigned long S[4][256];
+   unsigned long K[18];
+};
+#endif
+
+#ifdef RC5
+struct rc5_key {
+   int rounds;
+   unsigned long K[50];
+};
+#endif
+
+#ifdef RC6
+struct rc6_key {
+   unsigned long K[44];
+};
+#endif
+
+#ifdef SAFERP
+struct saferp_key {
+   unsigned char K[33][16];
+   long rounds;
+};
+#endif
+
+#ifdef SERPENT
+struct serpent_key {
+   unsigned long K[132];
+};
+#endif
+
+#ifdef RIJNDAEL
+struct rijndael_key {
+   unsigned long eK[64], dK[64], k_len;
+};
+#endif
+
+#ifdef XTEA
+struct xtea_key {
+   unsigned long K[4];
+};
+#endif
+
+#ifdef TWOFISH
+#ifndef TWOFISH_SMALL
+   struct twofish_key {
+      unsigned long S[4][256], K[40];
+   };
+#else
+   struct twofish_key {
+      unsigned long K[40];
+      unsigned char S[32], start;
+   };
+#endif
+#endif
+
+#ifdef SAFER
+#define SAFER_K64_DEFAULT_NOF_ROUNDS     6
+#define SAFER_K128_DEFAULT_NOF_ROUNDS   10
+#define SAFER_SK64_DEFAULT_NOF_ROUNDS    8
+#define SAFER_SK128_DEFAULT_NOF_ROUNDS  10
+#define SAFER_MAX_NOF_ROUNDS            13
+#define SAFER_BLOCK_LEN                  8
+#define SAFER_KEY_LEN     (1 + SAFER_BLOCK_LEN * (1 + 2 * SAFER_MAX_NOF_ROUNDS))
+typedef unsigned char safer_block_t[SAFER_BLOCK_LEN];
+typedef unsigned char safer_key_t[SAFER_KEY_LEN];
+struct safer_key { safer_key_t key; };
+#endif
+
+#ifdef RC2
+struct rc2_key { unsigned xkey[64]; };
+#endif
+
+#ifdef DES
+struct des_key {
+    unsigned long ek[32], dk[32];
+};
+
+struct des3_key {
+    unsigned long ek[3][32], dk[3][32];
+};
+#endif
+
+#ifdef CAST5
+struct cast5_key {
+    unsigned long K[32], keylen;
+};
+#endif
+
+typedef union Symmetric_key {
+#ifdef DES
+   struct des_key des;
+   struct des3_key des3;
+#endif
+#ifdef RC2
+   struct rc2_key rc2;
+#endif
+#ifdef SAFER
+   struct safer_key safer;
+#endif
+#ifdef TWOFISH
+   struct twofish_key  twofish;
+#endif
+#ifdef BLOWFISH
+   struct blowfish_key blowfish;
+#endif
+#ifdef RC5
+   struct rc5_key      rc5;
+#endif
+#ifdef RC6
+   struct rc6_key      rc6;
+#endif
+#ifdef SAFERP
+   struct saferp_key   saferp;
+#endif
+#ifdef SERPENT
+   struct serpent_key  serpent;
+#endif
+#ifdef RIJNDAEL
+   struct rijndael_key rijndael;
+#endif
+#ifdef XTEA
+   struct xtea_key     xtea;
+#endif
+#ifdef CAST5
+   struct cast5_key    cast5;
+#endif
+} symmetric_key;
+
+/* A block cipher ECB structure */
+typedef struct {
+   int                 cipher, blocklen;
+   symmetric_key       key;
+} symmetric_ECB;
+
+/* A block cipher CFB structure */
+typedef struct {
+   int                 cipher, blocklen, padlen;
+   unsigned char       IV[MAXBLOCKSIZE], pad[MAXBLOCKSIZE];
+   symmetric_key       key;
+} symmetric_CFB;
+
+/* A block cipher OFB structure */
+typedef struct {
+   int                 cipher, blocklen, padlen;
+   unsigned char       IV[MAXBLOCKSIZE];
+   symmetric_key       key;
+} symmetric_OFB;
+
+/* A block cipher CBC structure */
+typedef struct Symmetric_CBC {
+   int                 cipher, blocklen;
+   unsigned char       IV[MAXBLOCKSIZE];
+   symmetric_key       key;
+} symmetric_CBC;
+
+/* A block cipher CTR structure */
+typedef struct Symmetric_CTR {
+   int                 cipher, blocklen, padlen;
+   unsigned char       ctr[MAXBLOCKSIZE], pad[MAXBLOCKSIZE];
+   symmetric_key       key;
+} symmetric_CTR;
+
+/* cipher descriptor table, last entry has "name == NULL" to mark the end of table */
+extern  struct _cipher_descriptor {
+   char *name;
+   unsigned char ID;
+   unsigned long  min_key_length, max_key_length, block_length, default_rounds;
+   int  (*setup)(const unsigned char *key, int keylength, int num_rounds, symmetric_key *skey);
+   void (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+   void (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+   int (*test)(void);
+   int  (*keysize)(int *desired_keysize);
+} cipher_descriptor[];
+
+#ifdef BLOWFISH
+extern int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int blowfish_test(void);
+extern int blowfish_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor blowfish_desc;
+#endif
+
+#ifdef RC5
+extern int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int rc5_test(void);
+extern int rc5_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor rc5_desc;
+#endif
+
+#ifdef RC6
+extern int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int rc6_test(void);
+extern int rc6_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor rc6_desc;
+#endif
+
+#ifdef RC2
+extern int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int rc2_test(void);
+extern int rc2_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor rc2_desc;
+#endif
+
+#ifdef SAFERP
+extern int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int saferp_test(void);
+extern int saferp_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor saferp_desc;
+#endif
+
+#ifdef SAFER
+extern int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+
+extern int safer_k64_test(void);
+extern int safer_sk64_test(void);
+extern int safer_sk128_test(void);
+
+extern int safer_64_keysize(int *desired_keysize);
+extern int safer_128_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc;
+#endif
+
+#ifdef SERPENT
+extern int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int serpent_test(void);
+extern int serpent_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor serpent_desc;
+#endif
+
+#ifdef RIJNDAEL
+extern int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int rijndael_test(void);
+extern int rijndael_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor rijndael_desc;
+#endif
+
+#ifdef XTEA
+extern int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int xtea_test(void);
+extern int xtea_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor xtea_desc;
+#endif
+
+#ifdef TWOFISH
+extern int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int twofish_test(void);
+extern int twofish_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor twofish_desc;
+#endif
+
+#ifdef DES
+extern int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int des_test(void);
+extern int des_keysize(int *desired_keysize);
+
+extern int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int des3_test(void);
+extern int des3_keysize(int *desired_keysize);
+
+extern const struct _cipher_descriptor des_desc, des3_desc;
+#endif
+
+#ifdef CAST5
+extern int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+extern void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+extern void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+extern int cast5_test(void);
+extern int cast5_keysize(int *desired_keysize);
+extern const struct _cipher_descriptor cast5_desc;
+#endif
+
+#ifdef ECB
+extern int ecb_start(int cipher, const unsigned char *key, 
+                     int keylen, int num_rounds, symmetric_ECB *ecb);
+extern int ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ECB *ecb);
+extern int ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ECB *ecb);
+#endif
+
+#ifdef CFB
+extern int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+                     int keylen, int num_rounds, symmetric_CFB *cfb);
+extern int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
+extern int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
+#endif
+
+#ifdef OFB
+extern int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+                     int keylen, int num_rounds, symmetric_OFB *ofb);
+extern int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb);
+extern int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb);
+#endif
+
+#ifdef CBC
+extern int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
+                     int keylen, int num_rounds, symmetric_CBC *cbc);
+extern int cbc_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_CBC *cbc);
+extern int cbc_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_CBC *cbc);
+#endif
+
+#ifdef CTR
+extern int ctr_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+                     int keylen, int num_rounds, symmetric_CTR *ctr);
+extern int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr);
+extern int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr);
+#endif
+	
+extern int find_cipher(const char *name);
+extern int find_cipher_any(const char *name, int blocklen, int keylen);
+extern int find_cipher_id(unsigned char ID);
+
+extern int register_cipher(const struct _cipher_descriptor *cipher);
+extern int unregister_cipher(const struct _cipher_descriptor *cipher);
+
+extern int cipher_is_valid(int idx);
+

+ 32 - 0
mycrypt_gf.h

@@ -0,0 +1,32 @@
+
+/* ---- GF(2^w) polynomial basis ---- */
+#ifdef GF
+#define   LSIZE    32   /* handle upto 1024-bit GF numbers */
+
+typedef unsigned long gf_int[LSIZE];
+typedef unsigned long *gf_intp;
+
+extern void gf_copy(gf_intp a, gf_intp b);
+extern void gf_zero(gf_intp a);
+extern int gf_iszero(gf_intp a);
+extern int gf_isone(gf_intp a);
+extern int gf_deg(gf_intp a);
+
+extern void gf_shl(gf_intp a, gf_intp b);
+extern void gf_shr(gf_intp a, gf_intp b);
+extern void gf_add(gf_intp a, gf_intp b, gf_intp c);
+extern void gf_mul(gf_intp a, gf_intp b, gf_intp c);
+extern void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r);
+
+extern void gf_mod(gf_intp a, gf_intp m, gf_intp b);
+extern void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c);
+extern void gf_invmod(gf_intp A, gf_intp M, gf_intp B);
+extern void gf_sqrt(gf_intp a, gf_intp M, gf_intp b);
+extern void gf_gcd(gf_intp A, gf_intp B, gf_intp c);
+extern int gf_is_prime(gf_intp a);
+
+extern int gf_size(gf_intp a);
+extern void gf_toraw(gf_intp a, unsigned char *dst);
+extern void gf_readraw(gf_intp a, unsigned char *str, int len);
+
+#endif

+ 184 - 0
mycrypt_hash.h

@@ -0,0 +1,184 @@
+/* ---- HASH FUNCTIONS ---- */
+#ifdef SHA512
+struct sha512_state {
+    ulong64  length, state[8];
+    unsigned long curlen;
+    unsigned char buf[128];
+};
+#endif
+
+#ifdef SHA256
+struct sha256_state {
+    ulong64 length;
+    unsigned long state[8], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef SHA1
+struct sha1_state {
+    ulong64 length;
+    unsigned long state[5], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef MD5
+struct md5_state {
+    ulong64 length;
+    unsigned long state[4], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef MD4
+struct md4_state {
+    ulong64 length;
+    unsigned long state[4], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef TIGER
+struct tiger_state {
+    ulong64 state[3], length;
+    unsigned long curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef MD2
+struct md2_state {
+    unsigned char chksum[16], X[48], buf[16];
+    unsigned long curlen;
+};
+#endif
+
+typedef union Hash_state {
+#ifdef SHA512
+    struct sha512_state sha512;
+#endif
+#ifdef SHA256
+    struct sha256_state sha256;
+#endif
+#ifdef SHA1
+    struct sha1_state   sha1;
+#endif
+#ifdef MD5
+    struct md5_state    md5;
+#endif
+#ifdef MD4
+    struct md4_state    md4;
+#endif
+#ifdef MD2
+    struct md2_state    md2;
+#endif
+#ifdef TIGER
+    struct tiger_state  tiger;
+#endif
+} hash_state;
+
+extern struct _hash_descriptor {
+    char *name;
+    unsigned char ID;
+    unsigned long hashsize;       /* digest output size in bytes  */
+    unsigned long blocksize;      /* the block size the hash uses */
+    void (*init)(hash_state *);
+    void (*process)(hash_state *, const unsigned char *, unsigned long);
+    void (*done)(hash_state *, unsigned char *);
+    int  (*test)(void);
+} hash_descriptor[];
+
+#ifdef SHA512
+extern void sha512_init(hash_state * md);
+extern void sha512_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void sha512_done(hash_state * md, unsigned char *hash);
+extern int  sha512_test(void);
+extern const struct _hash_descriptor sha512_desc;
+#endif
+
+#ifdef SHA384
+extern void sha384_init(hash_state * md);
+extern void sha384_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void sha384_done(hash_state * md, unsigned char *hash);
+extern int  sha384_test(void);
+extern const struct _hash_descriptor sha384_desc;
+#endif
+
+#ifdef SHA256
+extern void sha256_init(hash_state * md);
+extern void sha256_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void sha256_done(hash_state * md, unsigned char *hash);
+extern int  sha256_test(void);
+extern const struct _hash_descriptor sha256_desc;
+#endif
+
+#ifdef SHA1
+extern void sha1_init(hash_state * md);
+extern void sha1_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void sha1_done(hash_state * md, unsigned char *hash);
+extern int  sha1_test(void);
+extern const struct _hash_descriptor sha1_desc;
+#endif
+
+#ifdef MD5
+extern void md5_init(hash_state * md);
+extern void md5_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void md5_done(hash_state * md, unsigned char *hash);
+extern int  md5_test(void);
+extern const struct _hash_descriptor md5_desc;
+#endif
+
+#ifdef MD4
+extern void md4_init(hash_state * md);
+extern void md4_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void md4_done(hash_state * md, unsigned char *hash);
+extern int  md4_test(void);
+extern const struct _hash_descriptor md4_desc;
+#endif
+
+#ifdef MD2
+extern void md2_init(hash_state * md);
+extern void md2_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void md2_done(hash_state * md, unsigned char *hash);
+extern int  md2_test(void);
+extern const struct _hash_descriptor md2_desc;
+#endif
+
+#ifdef TIGER
+extern void tiger_init(hash_state * md);
+extern void tiger_process(hash_state * md, const unsigned char *buf, unsigned long len);
+extern void tiger_done(hash_state * md, unsigned char *hash);
+extern int  tiger_test(void);
+extern const struct _hash_descriptor tiger_desc;
+#endif
+
+extern int find_hash(const char *name);
+extern int find_hash_id(unsigned char ID);
+extern int register_hash(const struct _hash_descriptor *hash);
+extern int unregister_hash(const struct _hash_descriptor *hash);
+extern int hash_is_valid(int idx);
+
+extern int hash_memory(int hash, const unsigned char *data, unsigned long len, unsigned char *dst, unsigned long *outlen);
+extern int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen);
+extern int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen);
+
+#ifdef HMAC
+typedef struct Hmac_state {
+     hash_state md;
+     int hash;
+     unsigned long hashsize; /* here for your reference */
+     hash_state hashstate;
+     unsigned char key[MAXBLOCKSIZE];
+} hmac_state;
+
+extern int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);
+extern int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len);
+extern int hmac_done(hmac_state *hmac, unsigned char *hash);
+extern int hmac_test(void);
+extern int hmac_memory(int hash, const unsigned char *key, unsigned long keylen,
+                       const unsigned char *data, unsigned long len, unsigned char *dst);
+extern int hmac_file(int hash, const char *fname, const unsigned char *key,
+                     unsigned long keylen, unsigned char *dst);
+#endif
+

+ 77 - 0
mycrypt_kr.h

@@ -0,0 +1,77 @@
+#ifdef KR
+
+#define MAXLEN    256
+
+enum {
+   NON_KEY=0,
+   RSA_KEY,
+   DH_KEY,
+   ECC_KEY
+};
+
+typedef union {
+    rsa_key rsa;
+    dh_key  dh;
+    ecc_key ecc;
+} _pk_key;
+
+typedef struct Pk_key {
+    int     key_type,             /* PUBLIC, PRIVATE, PRIVATE_OPTIMIZED */
+            system;               /* RSA, ECC or DH ?   */
+
+    unsigned char 
+            name[MAXLEN],         /* various info's about this key */
+            email[MAXLEN],
+            description[MAXLEN];
+
+    unsigned long ID;             /* CRC32 of the name/email/description together */
+
+    _pk_key key;
+
+    struct Pk_key  *next;         /* linked list chain */
+} pk_key;
+
+extern int kr_init(pk_key **pk);
+
+extern unsigned long kr_crc(const unsigned char *name, const unsigned char *email, const unsigned char *description);
+
+extern pk_key *kr_find(pk_key *pk, unsigned long ID);
+extern pk_key *kr_find_name(pk_key *pk, const char *name);
+
+extern int kr_add(pk_key *pk, int key_type, int system, const unsigned char *name, 
+                  const unsigned char *email, const unsigned char *description, const _pk_key *key);
+                  
+extern int kr_del(pk_key **_pk, unsigned long ID);
+extern int kr_clear(pk_key **pk);
+extern int kr_make_key(pk_key *pk, prng_state *prng, int wprng, 
+                       int system, int keysize, const unsigned char *name,
+                       const unsigned char *email, const unsigned char *description);
+
+extern int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen);
+extern int kr_import(pk_key *pk, const unsigned char *in);
+
+extern int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr);
+extern int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr);
+
+extern int kr_encrypt_key(pk_key *pk, unsigned long ID, 
+                          const unsigned char *in, unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int wprng, int hash);
+
+extern int kr_decrypt_key(pk_key *pk, const unsigned char *in,
+                          unsigned char *out, unsigned long *outlen);
+
+extern int kr_sign_hash(pk_key *pk, unsigned long ID, 
+                        const unsigned char *in, unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng);
+
+extern int kr_verify_hash(pk_key *pk, const unsigned char *in, 
+                          const unsigned char *hash, unsigned long hashlen,
+                          int *stat);
+
+extern int kr_fingerprint(pk_key *pk, unsigned long ID, int hash,
+                          unsigned char *out, unsigned long *outlen);
+
+#endif
+

+ 200 - 0
mycrypt_macros.h

@@ -0,0 +1,200 @@
+/* fix for MSVC ...evil! */
+#ifdef _MSC_VER
+   #define CONST64(n) n ## ui64
+   typedef unsigned __int64 ulong64;
+#else
+   #define CONST64(n) n ## ULL
+   typedef unsigned long long ulong64;
+#endif
+
+extern char *crypt_error;
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y)                                                                     \
+     { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y)                            \
+     { x = ((unsigned long)((y)[3] & 255)<<24) | \
+           ((unsigned long)((y)[2] & 255)<<16) | \
+           ((unsigned long)((y)[1] & 255)<<8)  | \
+           ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y)                                                                     \
+     { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                       \
+     { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y)                            \
+     { x = ((unsigned long)((y)[0] & 255)<<24) | \
+           ((unsigned long)((y)[1] & 255)<<16) | \
+           ((unsigned long)((y)[2] & 255)<<8)  | \
+           ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y)                                                                     \
+   { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                      \
+   { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#define STORE32H(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y)                            \
+     { x = ((unsigned long)((y)[0] & 255)<<24) | \
+           ((unsigned long)((y)[1] & 255)<<16) | \
+           ((unsigned long)((y)[2] & 255)<<8)  | \
+           ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y)                                                                     \
+   { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                      \
+   { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#ifdef ENDIAN_32BITWORD 
+
+#define STORE32L(x, y)        \
+     { unsigned long t = (x); memcpy(y, &t, 4); }
+
+#define LOAD32L(x, y)         \
+     memcpy(&(x), y, 4);
+
+#define STORE64L(x, y)                                                                     \
+     { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                       \
+     { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then  */
+
+#define STORE32L(x, y)        \
+     { unsigned long t = (x); memcpy(y, &t, 4); }
+
+#define LOAD32L(x, y)         \
+     { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y)        \
+     { ulong64 t = (x); memcpy(y, &t, 8); }
+
+#define LOAD64L(x, y)         \
+    { memcpy(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y)                                                                     \
+     { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y)                            \
+     { x = ((unsigned long)((y)[0] & 255)<<24) | \
+           ((unsigned long)((y)[1] & 255)<<16) | \
+           ((unsigned long)((y)[2] & 255)<<8)  | \
+           ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64L(x, y)                                                                     \
+   { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y)                                                      \
+   { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#ifdef ENDIAN_32BITWORD 
+
+#define STORE32H(x, y)        \
+     { unsigned long t = (x); memcpy(y, &t, 4); }
+
+#define LOAD32H(x, y)         \
+     memcpy(&(x), y, 4);
+
+#define STORE64H(x, y)                                                                     \
+     { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y)                                                       \
+     { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then  */
+
+#define STORE32H(x, y)        \
+     { unsigned long t = (x); memcpy(y, &t, 4); }
+
+#define LOAD32H(x, y)         \
+     { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y)        \
+     { ulong64 t = (x); memcpy(y, &t, 8); }
+
+#define LOAD64H(x, y)         \
+    { memcpy(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x)  ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL)  | \
+                    ((x>>8)&0x0000FF00UL)  | ((x<<8)&0x00FF0000UL) )
+
+#define ROL(x, y) ( (((x)<<((y)&31)) | (((x)&0xFFFFFFFFUL)>>(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((x)&0xFFFFFFFFUL)>>((y)&31)) | ((x)<<(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#define ROL64(x, y) \
+    ( (((x)<<((ulong64)(y)&63)) | \
+      (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+      ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#undef MAX
+#undef MIN
+#define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )

+ 16 - 0
mycrypt_misc.h

@@ -0,0 +1,16 @@
+/* ---- BASE64 Routines ---- */
+#ifdef BASE64
+extern int base64_encode(const unsigned char *in,  unsigned long len, 
+                               unsigned char *out, unsigned long *outlen);
+
+extern int base64_decode(const unsigned char *in,  unsigned long len, 
+                               unsigned char *out, unsigned long *outlen);
+#endif
+
+/* ---- MEM routines ---- */
+extern void zeromem(void *dst, unsigned long len);
+extern void burn_stack(unsigned long len);
+
+extern const char *error_to_string(int errno);
+
+extern const char *crypt_build_settings;

+ 219 - 0
mycrypt_pk.h

@@ -0,0 +1,219 @@
+/* ---- NUMBER THEORY ---- */
+#ifdef MPI
+
+extern int is_prime(mp_int *, int *);
+extern int rand_prime(mp_int *N, long len, prng_state *prng, int wprng);
+extern mp_err mp_init_multi(mp_int* mp, ...);
+extern void mp_clear_multi(mp_int* mp, ...);
+
+#endif
+
+/* ---- PUBLIC KEY CRYPTO ---- */
+
+#define PK_PRIVATE            0        /* PK private keys */
+#define PK_PUBLIC             1        /* PK public keys */
+#define PK_PRIVATE_OPTIMIZED  2        /* PK private key [rsa optimized] */
+
+/* ---- PACKET ---- */
+#ifdef PACKET
+
+extern void packet_store_header(unsigned char *dst, int section, int subsection, unsigned long length);
+extern int packet_valid_header(unsigned char *src, int section, int subsection);
+
+#endif
+
+
+/* ---- RSA ---- */
+#ifdef MRSA
+typedef struct Rsa_key {
+    int type;
+    mp_int e, d, N, qP, pQ, dP, dQ, p, q;
+} rsa_key;
+
+extern int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+extern int rsa_exptmod(const unsigned char *in,  unsigned long inlen, 
+                             unsigned char *out, unsigned long *outlen, int which, 
+                             rsa_key *key);
+
+extern int rsa_pad(const unsigned char *in,  unsigned long inlen, 
+                         unsigned char *out, unsigned long *outlen, 
+                         int wprng, prng_state *prng);
+
+extern int rsa_signpad(const unsigned char *in,  unsigned long inlen, 
+                             unsigned char *out, unsigned long *outlen);
+
+extern int rsa_depad(const unsigned char *in,  unsigned long inlen, 
+                           unsigned char *out, unsigned long *outlen);
+
+extern int rsa_signdepad(const unsigned char *in,  unsigned long inlen,
+                               unsigned char *out, unsigned long *outlen);
+
+
+extern void rsa_free(rsa_key *key);
+
+#ifdef PK_PACKET
+
+extern int rsa_encrypt(const unsigned char *in,  unsigned long len, 
+                             unsigned char *out, unsigned long *outlen,
+                             prng_state *prng, int wprng, int cipher, 
+                             rsa_key *key);
+
+extern int rsa_decrypt(const unsigned char *in,  unsigned long len, 
+                             unsigned char *out, unsigned long *outlen, 
+                             rsa_key *key);
+
+extern int rsa_sign(const unsigned char *in, unsigned long inlen, 
+                          unsigned char *out, unsigned long *outlen, 
+                          int hash, rsa_key *key);
+
+extern int rsa_verify(const unsigned char *sig, const unsigned char *msg, 
+                            unsigned long inlen, int *stat, 
+                            rsa_key *key);
+                            
+#endif                            
+
+extern int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen,
+                                 unsigned char *outkey, unsigned long *outlen,
+                                 prng_state *prng, int wprng, rsa_key *key);
+
+extern int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                                 unsigned long *keylen, rsa_key *key);
+
+extern int rsa_sign_hash(const unsigned char *in,  unsigned long inlen, 
+                               unsigned char *out, unsigned long *outlen, 
+                               rsa_key *key);
+
+extern int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash,
+                                 int *stat, rsa_key *key);
+
+extern int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
+extern int rsa_import(const unsigned char *in, rsa_key *key);
+#endif
+
+/* ---- DH Routines ---- */
+#ifdef MDH 
+
+typedef struct Dh_key {
+    int idx, type;
+    mp_int x, y;
+} dh_key;
+
+extern int dh_test(void);
+extern void dh_sizes(int *low, int *high);
+extern int dh_get_size(dh_key *key);
+
+extern int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key);
+extern void dh_free(dh_key *key);
+
+extern int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key);
+extern int dh_import(const unsigned char *in, dh_key *key);
+
+extern int dh_shared_secret(dh_key *private_key, dh_key *public_key,
+                            unsigned char *out, unsigned long *outlen);
+
+#ifdef PK_PACKET
+
+extern int dh_encrypt(const unsigned char *in,  unsigned long len, 
+                            unsigned char *out, unsigned long *outlen,
+                            prng_state *prng, int wprng, int cipher, int hash, 
+                            dh_key *key);
+
+extern int dh_decrypt(const unsigned char *in,  unsigned long len, 
+                            unsigned char *out, unsigned long *outlen, 
+                            dh_key *key);
+
+extern int dh_sign(const unsigned char *in,  unsigned long inlen, 
+                         unsigned char *out, unsigned long *outlen, int hash, 
+                         prng_state *prng, int wprng, 
+                         dh_key *key);
+
+extern int dh_verify(const unsigned char *sig, const unsigned char *msg, 
+                           unsigned long inlen, int *stat, 
+                           dh_key *key);
+                           
+#endif                           
+
+extern int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                                unsigned char *out,  unsigned long *len, 
+                                prng_state *prng, int wprng, int hash, 
+                                dh_key *key);
+
+extern int dh_decrypt_key(const unsigned char *in,  unsigned char *outkey, 
+                                unsigned long *keylen, dh_key *key);
+
+extern int dh_sign_hash(const unsigned char *in,  unsigned long inlen,
+                              unsigned char *out, unsigned long *outlen,
+                              prng_state *prng, int wprng, dh_key *key);
+
+extern int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                                unsigned long inlen, int *stat, 
+                                dh_key *key);
+
+
+#endif
+
+/* ---- ECC Routines ---- */
+#ifdef MECC
+typedef struct {
+    mp_int x, y;
+} ecc_point;
+
+typedef struct {
+    int type, idx;
+    ecc_point pubkey;
+    mp_int k;
+} ecc_key;
+
+extern int ecc_test(void);
+extern void ecc_sizes(int *low, int *high);
+extern int ecc_get_size(ecc_key *key);
+
+extern int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
+extern void ecc_free(ecc_key *key);
+
+extern int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key);
+extern int ecc_import(const unsigned char *in, ecc_key *key);
+
+extern int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, 
+                             unsigned char *out, unsigned long *outlen);
+
+#ifdef PK_PACKET
+
+extern int ecc_encrypt(const unsigned char *in,  unsigned long len, 
+                             unsigned char *out, unsigned long *outlen,
+                             prng_state *prng, int wprng, int cipher, int hash, 
+                             ecc_key *key);
+
+extern int ecc_decrypt(const unsigned char *in,  unsigned long len,
+                             unsigned char *out, unsigned long *outlen, 
+                             ecc_key *key);
+
+extern int ecc_sign(const unsigned char *in, unsigned long inlen, 
+                          unsigned char *out, unsigned long *outlen, int hash, 
+                          prng_state *prng, int wprng, 
+                          ecc_key *key);
+
+extern int ecc_verify(const unsigned char *sig, const unsigned char *msg, 
+                            unsigned long inlen, int *stat, 
+                            ecc_key *key);
+                            
+#endif                            
+
+extern int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen,
+                                 unsigned char *out,  unsigned long *len, 
+                                 prng_state *prng, int wprng, int hash, 
+                                 ecc_key *key);
+
+extern int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                                 unsigned long *keylen, ecc_key *key);
+
+extern int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                               unsigned char *out, unsigned long *outlen,
+                               prng_state *prng, int wprng, ecc_key *key);
+
+extern int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, 
+                                 unsigned long inlen, int *stat, 
+                                 ecc_key *key);
+#endif
+

+ 62 - 0
mycrypt_prng.h

@@ -0,0 +1,62 @@
+/* ---- PRNG Stuff ---- */
+struct yarrow_prng {
+    int                   cipher, hash;
+    unsigned char         pool[MAXBLOCKSIZE];
+    symmetric_CTR         ctr;
+};
+
+struct rc4_prng {
+    int x, y;
+    unsigned char buf[256];
+};
+
+typedef union Prng_state {
+    struct yarrow_prng    yarrow;
+    struct rc4_prng       rc4;
+} prng_state;
+
+extern struct _prng_descriptor {
+    char *name;
+    int (*start)(prng_state *);
+    int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
+    int (*ready)(prng_state *);
+    unsigned long (*read)(unsigned char *, unsigned long len, prng_state *);
+} prng_descriptor[];
+
+#ifdef YARROW
+extern int yarrow_start(prng_state *prng);
+extern int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
+extern int yarrow_ready(prng_state *prng);
+extern unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng);
+extern const struct _prng_descriptor yarrow_desc;
+#endif
+
+#ifdef RC4
+extern int rc4_start(prng_state *prng);
+extern int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
+extern int rc4_ready(prng_state *prng);
+extern unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng);
+extern const struct _prng_descriptor rc4_desc;
+#endif
+
+#ifdef SPRNG
+extern int sprng_start(prng_state *prng);
+extern int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
+extern int sprng_ready(prng_state *prng);
+extern unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng);
+extern const struct _prng_descriptor sprng_desc;
+#endif
+
+extern int find_prng(const char *name);
+extern int register_prng(const struct _prng_descriptor *prng);
+extern int unregister_prng(const struct _prng_descriptor *prng);
+extern int prng_is_valid(int idx);
+
+
+/* Slow RNG you **might** be able to use to seed a PRNG with.  Be careful as this
+ * might not work on all platforms as planned
+ */
+extern unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, void (*callback)(void));
+
+extern int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));
+

+ 73 - 0
notes/tech0001.txt

@@ -0,0 +1,73 @@
+Tech Note 0001
+How to Gather Entropy on Embedded Systems
+Tom St Denis
+
+Introduction
+------------
+
+This tech note explains a relatively simple way to gather entropy for a PRNG (Yarrow in this case) in embedded systems
+where there are few sources of entropy or physical sources.
+
+When trying to setup a secure random number generator a fresh source of random data (entropy) is required to ensure the
+deterministic state of the PRNG is not known or predetermined with respect to an attacker.
+
+At the very least the system requires one timer and one source of un-timed interrupts.  by "un-timed" I mean interrupts
+that do not occur at regular intervals [e.g. joypad/keypad input, network packets, etc...].
+
+First we shall begin by taking an overview of how the Yarrow PRNG works within libtomcrypt.  At the heart of all
+PRNGs is the "prng_state" data type.  This is a union of structures that hold the PRNG state for the various prngs.  The 
+first thing we require is a state... 
+
+   prng_state myPrng;
+
+Next we must initialize the state once to get the ball rolling
+
+   if (yarrow_start(&myPrng) != CRYPT_OK) {
+      // error should never happen!
+   }
+
+At this point the PRNG is ready to accept fresh entropy which is added with
+
+   int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
+
+This function is **NOT** thread safe which will come under consideration later.  To add entropy to our PRNG we must 
+call this function with fresh data as its sampled.  Lets say we have a timer counter called "uTimer" which is a 32-bit 
+long and say a 32-bit joyPad state called "uPad".  An example interrupt handler would look like
+
+   void joypad_interrupt(...) {
+       unsigned char buf[8];
+
+       STORE32L(uTimer, buf);
+       STORE32L(uPad, buf+4)
+       if (yarrow_add_entropy(buf, 8, &myPrng) != CRYPT_OK) {
+          // this should never occur either unless you didn't call yarrow_start
+       }
+ 
+       // handle interrupt
+   }
+
+In this snippet the timer count and state of the joypad are added together into the entropy pool.  The timer is important
+because with respect to the joypad it is a good source of entropy (on its own its not).  For example, the probability of
+the user pushing the up arrow is fairly high, but at a specific time is not.
+
+This method doesn't gather alot of entropy and has to be used to for quite a while.  One way to speed it up is to tap
+multiple sources.  If you have a network adapter and other sources of events (keyboard, mouse, etc...) trapping their
+data is ideal as well.  Its important to gather the timer along with the event data.
+
+As mentioned the "yarrow_add_entropy()" function is not thread safe.  If your system allows interrupt handlers to be 
+interrupted themselves then you could have trouble.  One simple way is to detect when an interrupt is in progress and
+simply not add entropy during the call (jump over the yarrow_add_entropy() call)
+
+Once you feel that there has been enough entropy added to the pool then within a single thread you can call
+
+    int yarrow_ready(prng_state *prng)
+
+Now the PRNG is ready to read via the 
+
+    unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng)
+
+It is a very good idea that once you call the yarrow_ready() function that you stop harvesting entropy in your interrupt
+functions.  This will free up alot of CPU time.  Also one more final note.  The yarrow_read() function is not thread
+safe either.  This means if you have multiple threads or processes that read from it you will have to add your own semaphores
+around calls to it.
+

+ 60 - 0
ofb.c

@@ -0,0 +1,60 @@
+#include "mycrypt.h"
+
+#ifdef OFB
+
+int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key, 
+              int keylen, int num_rounds, symmetric_OFB *ofb)
+{
+   int x, errno;
+
+   _ARGCHK(IV != NULL);
+   _ARGCHK(key != NULL);
+   _ARGCHK(ofb != NULL);
+
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* copy details */
+   ofb->cipher = cipher;
+   ofb->blocklen = cipher_descriptor[cipher].block_length;
+   for (x = 0; x < ofb->blocklen; x++) {
+       ofb->IV[x] = IV[x];
+   }
+
+   /* init the cipher */
+   ofb->padlen = ofb->blocklen;
+   return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ofb->key);
+}
+
+int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb)
+{
+   int errno;
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ofb != NULL);
+   if ((errno = cipher_is_valid(ofb->cipher)) != CRYPT_OK) {
+       return errno;
+   }
+   while (len--) {
+       if (ofb->padlen == ofb->blocklen) {
+          cipher_descriptor[ofb->cipher].ecb_encrypt(ofb->IV, ofb->IV, &ofb->key);
+          ofb->padlen = 0;
+       }
+       *ct++ = *pt++ ^ ofb->IV[ofb->padlen++];
+   }
+   return CRYPT_OK;
+}
+
+int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb)
+{
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(ofb != NULL);
+   return ofb_encrypt(ct, pt, len, ofb);
+}
+
+
+#endif
+
+ 

+ 43 - 0
packet.c

@@ -0,0 +1,43 @@
+#include "mycrypt.h"
+
+#ifdef PACKET
+
+void packet_store_header(unsigned char *dst, int section, int subsection, unsigned long length)
+{
+   _ARGCHK(dst != NULL);
+
+   /* store version number */
+   dst[0] = CRYPT&255;
+   dst[1] = (CRYPT>>8)&255;
+
+   /* store section and subsection */
+   dst[2] = section & 255;
+   dst[3] = subsection & 255;
+
+   /* store length */
+   STORE32L(length, &dst[4]);
+}
+
+int packet_valid_header(unsigned char *src, int section, int subsection)
+{
+   unsigned long ver;
+
+   _ARGCHK(src != NULL);
+
+   /* check version */
+   ver = ((unsigned long)src[0]) | ((unsigned long)src[1] << 8);
+   if (CRYPT < ver) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check section and subsection */
+   if (section != src[2] || subsection != src[3]) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+ 

+ 1008 - 0
prime.c

@@ -0,0 +1,1008 @@
+#include "mycrypt.h"
+
+#ifdef MPI
+
+#ifdef SMALL_PRIME_TAB
+static const mp_digit prime_tab[] = {
+    0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+    0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+    0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+    0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
+    0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+    0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+    0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+    0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137 };
+#else
+static const mp_digit prime_tab[] = {
+    0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+    0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, 
+    0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, 
+    0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, 
+    0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, 
+    0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, 
+    0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, 
+    0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, 
+
+    0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, 
+    0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, 
+    0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, 
+    0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, 
+    0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, 
+    0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, 
+    0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, 
+    0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, 
+
+    0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, 
+    0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, 
+    0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, 
+    0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, 
+    0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+    0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, 
+    0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, 
+    0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, 
+    0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, 
+    0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, 
+    0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, 
+    0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, 
+    0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, 
+    0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, 
+    0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, 
+    0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653, 
+    0x0655, 0x065B, 0x0665, 0x0679, 0x067F, 0x0683, 0x0685, 0x069D, 
+    0x06A1, 0x06A3, 0x06AD, 0x06B9, 0x06BB, 0x06C5, 0x06CD, 0x06D3, 
+    0x06D9, 0x06DF, 0x06F1, 0x06F7, 0x06FB, 0x06FD, 0x0709, 0x0713, 
+    0x071F, 0x0727, 0x0737, 0x0745, 0x074B, 0x074F, 0x0751, 0x0755, 
+    0x0757, 0x0761, 0x076D, 0x0773, 0x0779, 0x078B, 0x078D, 0x079D, 
+    0x079F, 0x07B5, 0x07BB, 0x07C3, 0x07C9, 0x07CD, 0x07CF, 0x07D3,
+    0x07DB, 0x07E1, 0x07EB, 0x07ED, 0x07F7, 0x0805, 0x080F, 0x0815, 
+    0x0821, 0x0823, 0x0827, 0x0829, 0x0833, 0x083F, 0x0841, 0x0851, 
+    0x0853, 0x0859, 0x085D, 0x085F, 0x0869, 0x0871, 0x0883, 0x089B, 
+    0x089F, 0x08A5, 0x08AD, 0x08BD, 0x08BF, 0x08C3, 0x08CB, 0x08DB, 
+    0x08DD, 0x08E1, 0x08E9, 0x08EF, 0x08F5, 0x08F9, 0x0905, 0x0907, 
+    0x091D, 0x0923, 0x0925, 0x092B, 0x092F, 0x0935, 0x0943, 0x0949, 
+    0x094D, 0x094F, 0x0955, 0x0959, 0x095F, 0x096B, 0x0971, 0x0977, 
+    0x0985, 0x0989, 0x098F, 0x099B, 0x09A3, 0x09A9, 0x09AD, 0x09C7, 
+    0x09D9, 0x09E3, 0x09EB, 0x09EF, 0x09F5, 0x09F7, 0x09FD, 0x0A13, 
+    0x0A1F, 0x0A21, 0x0A31, 0x0A39, 0x0A3D, 0x0A49, 0x0A57, 0x0A61, 
+    0x0A63, 0x0A67, 0x0A6F, 0x0A75, 0x0A7B, 0x0A7F, 0x0A81, 0x0A85, 
+    0x0A8B, 0x0A93, 0x0A97, 0x0A99, 0x0A9F, 0x0AA9, 0x0AAB, 0x0AB5, 
+    0x0ABD, 0x0AC1, 0x0ACF, 0x0AD9, 0x0AE5, 0x0AE7, 0x0AED, 0x0AF1, 
+    0x0AF3, 0x0B03, 0x0B11, 0x0B15, 0x0B1B, 0x0B23, 0x0B29, 0x0B2D, 
+    0x0B3F, 0x0B47, 0x0B51, 0x0B57, 0x0B5D, 0x0B65, 0x0B6F, 0x0B7B,
+    0x0B89, 0x0B8D, 0x0B93, 0x0B99, 0x0B9B, 0x0BB7, 0x0BB9, 0x0BC3, 
+    0x0BCB, 0x0BCF, 0x0BDD, 0x0BE1, 0x0BE9, 0x0BF5, 0x0BFB, 0x0C07, 
+    0x0C0B, 0x0C11, 0x0C25, 0x0C2F, 0x0C31, 0x0C41, 0x0C5B, 0x0C5F, 
+    0x0C61, 0x0C6D, 0x0C73, 0x0C77, 0x0C83, 0x0C89, 0x0C91, 0x0C95, 
+    0x0C9D, 0x0CB3, 0x0CB5, 0x0CB9, 0x0CBB, 0x0CC7, 0x0CE3, 0x0CE5, 
+    0x0CEB, 0x0CF1, 0x0CF7, 0x0CFB, 0x0D01, 0x0D03, 0x0D0F, 0x0D13, 
+    0x0D1F, 0x0D21, 0x0D2B, 0x0D2D, 0x0D3D, 0x0D3F, 0x0D4F, 0x0D55, 
+    0x0D69, 0x0D79, 0x0D81, 0x0D85, 0x0D87, 0x0D8B, 0x0D8D, 0x0DA3, 
+    0x0DAB, 0x0DB7, 0x0DBD, 0x0DC7, 0x0DC9, 0x0DCD, 0x0DD3, 0x0DD5, 
+    0x0DDB, 0x0DE5, 0x0DE7, 0x0DF3, 0x0DFD, 0x0DFF, 0x0E09, 0x0E17, 
+    0x0E1D, 0x0E21, 0x0E27, 0x0E2F, 0x0E35, 0x0E3B, 0x0E4B, 0x0E57, 
+    0x0E59, 0x0E5D, 0x0E6B, 0x0E71, 0x0E75, 0x0E7D, 0x0E87, 0x0E8F, 
+    0x0E95, 0x0E9B, 0x0EB1, 0x0EB7, 0x0EB9, 0x0EC3, 0x0ED1, 0x0ED5, 
+    0x0EDB, 0x0EED, 0x0EEF, 0x0EF9, 0x0F07, 0x0F0B, 0x0F0D, 0x0F17, 
+    0x0F25, 0x0F29, 0x0F31, 0x0F43, 0x0F47, 0x0F4D, 0x0F4F, 0x0F53, 
+    0x0F59, 0x0F5B, 0x0F67, 0x0F6B, 0x0F7F, 0x0F95, 0x0FA1, 0x0FA3, 
+    0x0FA7, 0x0FAD, 0x0FB3, 0x0FB5, 0x0FBB, 0x0FD1, 0x0FD3, 0x0FD9, 
+    0x0FE9, 0x0FEF, 0x0FFB, 0x0FFD, 0x1003, 0x100F, 0x101F, 0x1021, 
+    0x1025, 0x102B, 0x1039, 0x103D, 0x103F, 0x1051, 0x1069, 0x1073, 
+    0x1079, 0x107B, 0x1085, 0x1087, 0x1091, 0x1093, 0x109D, 0x10A3, 
+    0x10A5, 0x10AF, 0x10B1, 0x10BB, 0x10C1, 0x10C9, 0x10E7, 0x10F1, 
+    0x10F3, 0x10FD, 0x1105, 0x110B, 0x1115, 0x1127, 0x112D, 0x1139, 
+    0x1145, 0x1147, 0x1159, 0x115F, 0x1163, 0x1169, 0x116F, 0x1181,
+    0x1183, 0x118D, 0x119B, 0x11A1, 0x11A5, 0x11A7, 0x11AB, 0x11C3, 
+    0x11C5, 0x11D1, 0x11D7, 0x11E7, 0x11EF, 0x11F5, 0x11FB, 0x120D, 
+    0x121D, 0x121F, 0x1223, 0x1229, 0x122B, 0x1231, 0x1237, 0x1241, 
+    0x1247, 0x1253, 0x125F, 0x1271, 0x1273, 0x1279, 0x127D, 0x128F, 
+    0x1297, 0x12AF, 0x12B3, 0x12B5, 0x12B9, 0x12BF, 0x12C1, 0x12CD, 
+    0x12D1, 0x12DF, 0x12FD, 0x1307, 0x130D, 0x1319, 0x1327, 0x132D, 
+    0x1337, 0x1343, 0x1345, 0x1349, 0x134F, 0x1357, 0x135D, 0x1367, 
+    0x1369, 0x136D, 0x137B, 0x1381, 0x1387, 0x138B, 0x1391, 0x1393, 
+    0x139D, 0x139F, 0x13AF, 0x13BB, 0x13C3, 0x13D5, 0x13D9, 0x13DF, 
+    0x13EB, 0x13ED, 0x13F3, 0x13F9, 0x13FF, 0x141B, 0x1421, 0x142F, 
+    0x1433, 0x143B, 0x1445, 0x144D, 0x1459, 0x146B, 0x146F, 0x1471, 
+    0x1475, 0x148D, 0x1499, 0x149F, 0x14A1, 0x14B1, 0x14B7, 0x14BD, 
+    0x14CB, 0x14D5, 0x14E3, 0x14E7, 0x1505, 0x150B, 0x1511, 0x1517, 
+    0x151F, 0x1525, 0x1529, 0x152B, 0x1537, 0x153D, 0x1541, 0x1543, 
+    0x1549, 0x155F, 0x1565, 0x1567, 0x156B, 0x157D, 0x157F, 0x1583, 
+    0x158F, 0x1591, 0x1597, 0x159B, 0x15B5, 0x15BB, 0x15C1, 0x15C5, 
+    0x15CD, 0x15D7, 0x15F7, 0x1607, 0x1609, 0x160F, 0x1613, 0x1615,
+    0x1619, 0x161B, 0x1625, 0x1633, 0x1639, 0x163D, 0x1645, 0x164F, 
+    0x1655, 0x1669, 0x166D, 0x166F, 0x1675, 0x1693, 0x1697, 0x169F, 
+    0x16A9, 0x16AF, 0x16B5, 0x16BD, 0x16C3, 0x16CF, 0x16D3, 0x16D9, 
+    0x16DB, 0x16E1, 0x16E5, 0x16EB, 0x16ED, 0x16F7, 0x16F9, 0x1709, 
+    0x170F, 0x1723, 0x1727, 0x1733, 0x1741, 0x175D, 0x1763, 0x1777, 
+    0x177B, 0x178D, 0x1795, 0x179B, 0x179F, 0x17A5, 0x17B3, 0x17B9, 
+    0x17BF, 0x17C9, 0x17CB, 0x17D5, 0x17E1, 0x17E9, 0x17F3, 0x17F5, 
+    0x17FF, 0x1807, 0x1813, 0x181D, 0x1835, 0x1837, 0x183B, 0x1843, 
+    0x1849, 0x184D, 0x1855, 0x1867, 0x1871, 0x1877, 0x187D, 0x187F, 
+    0x1885, 0x188F, 0x189B, 0x189D, 0x18A7, 0x18AD, 0x18B3, 0x18B9, 
+    0x18C1, 0x18C7, 0x18D1, 0x18D7, 0x18D9, 0x18DF, 0x18E5, 0x18EB, 
+    0x18F5, 0x18FD, 0x1915, 0x191B, 0x1931, 0x1933, 0x1945, 0x1949, 
+    0x1951, 0x195B, 0x1979, 0x1981, 0x1993, 0x1997, 0x1999, 0x19A3, 
+    0x19A9, 0x19AB, 0x19B1, 0x19B5, 0x19C7, 0x19CF, 0x19DB, 0x19ED, 
+    0x19FD, 0x1A03, 0x1A05, 0x1A11, 0x1A17, 0x1A21, 0x1A23, 0x1A2D,
+    0x1A2F, 0x1A35, 0x1A3F, 0x1A4D, 0x1A51, 0x1A69, 0x1A6B, 0x1A7B, 
+    0x1A7D, 0x1A87, 0x1A89, 0x1A93, 0x1AA7, 0x1AAB, 0x1AAD, 0x1AB1, 
+    0x1AB9, 0x1AC9, 0x1ACF, 0x1AD5, 0x1AD7, 0x1AE3, 0x1AF3, 0x1AFB, 
+    0x1AFF, 0x1B05, 0x1B23, 0x1B25, 0x1B2F, 0x1B31, 0x1B37, 0x1B3B, 
+    0x1B41, 0x1B47, 0x1B4F, 0x1B55, 0x1B59, 0x1B65, 0x1B6B, 0x1B73, 
+    0x1B7F, 0x1B83, 0x1B91, 0x1B9D, 0x1BA7, 0x1BBF, 0x1BC5, 0x1BD1, 
+    0x1BD7, 0x1BD9, 0x1BEF, 0x1BF7, 0x1C09, 0x1C13, 0x1C19, 0x1C27, 
+    0x1C2B, 0x1C2D, 0x1C33, 0x1C3D, 0x1C45, 0x1C4B, 0x1C4F, 0x1C55, 
+    0x1C73, 0x1C81, 0x1C8B, 0x1C8D, 0x1C99, 0x1CA3, 0x1CA5, 0x1CB5, 
+    0x1CB7, 0x1CC9, 0x1CE1, 0x1CF3, 0x1CF9, 0x1D09, 0x1D1B, 0x1D21, 
+    0x1D23, 0x1D35, 0x1D39, 0x1D3F, 0x1D41, 0x1D4B, 0x1D53, 0x1D5D, 
+    0x1D63, 0x1D69, 0x1D71, 0x1D75, 0x1D7B, 0x1D7D, 0x1D87, 0x1D89, 
+    0x1D95, 0x1D99, 0x1D9F, 0x1DA5, 0x1DA7, 0x1DB3, 0x1DB7, 0x1DC5, 
+    0x1DD7, 0x1DDB, 0x1DE1, 0x1DF5, 0x1DF9, 0x1E01, 0x1E07, 0x1E0B, 
+    0x1E13, 0x1E17, 0x1E25, 0x1E2B, 0x1E2F, 0x1E3D, 0x1E49, 0x1E4D, 
+    0x1E4F, 0x1E6D, 0x1E71, 0x1E89, 0x1E8F, 0x1E95, 0x1EA1, 0x1EAD, 
+    0x1EBB, 0x1EC1, 0x1EC5, 0x1EC7, 0x1ECB, 0x1EDD, 0x1EE3, 0x1EEF, 
+    0x1EF7, 0x1EFD, 0x1F01, 0x1F0D, 0x1F0F, 0x1F1B, 0x1F39, 0x1F49, 
+    0x1F4B, 0x1F51, 0x1F67, 0x1F75, 0x1F7B, 0x1F85, 0x1F91, 0x1F97, 
+    0x1F99, 0x1F9D, 0x1FA5, 0x1FAF, 0x1FB5, 0x1FBB, 0x1FD3, 0x1FE1, 
+    0x1FE7, 0x1FEB, 0x1FF3, 0x1FFF, 0x2011, 0x201B, 0x201D, 0x2027, 
+    0x2029, 0x202D, 0x2033, 0x2047, 0x204D, 0x2051, 0x205F, 0x2063, 
+    0x2065, 0x2069, 0x2077, 0x207D, 0x2089, 0x20A1, 0x20AB, 0x20B1,
+    0x20B9, 0x20C3, 0x20C5, 0x20E3, 0x20E7, 0x20ED, 0x20EF, 0x20FB, 
+    0x20FF, 0x210D, 0x2113, 0x2135, 0x2141, 0x2149, 0x214F, 0x2159, 
+    0x215B, 0x215F, 0x2173, 0x217D, 0x2185, 0x2195, 0x2197, 0x21A1, 
+    0x21AF, 0x21B3, 0x21B5, 0x21C1, 0x21C7, 0x21D7, 0x21DD, 0x21E5, 
+    0x21E9, 0x21F1, 0x21F5, 0x21FB, 0x2203, 0x2209, 0x220F, 0x221B, 
+    0x2221, 0x2225, 0x222B, 0x2231, 0x2239, 0x224B, 0x224F, 0x2263, 
+    0x2267, 0x2273, 0x2275, 0x227F, 0x2285, 0x2287, 0x2291, 0x229D, 
+    0x229F, 0x22A3, 0x22B7, 0x22BD, 0x22DB, 0x22E1, 0x22E5, 0x22ED, 
+    0x22F7, 0x2303, 0x2309, 0x230B, 0x2327, 0x2329, 0x232F, 0x2333, 
+    0x2335, 0x2345, 0x2351, 0x2353, 0x2359, 0x2363, 0x236B, 0x2383, 
+    0x238F, 0x2395, 0x23A7, 0x23AD, 0x23B1, 0x23BF, 0x23C5, 0x23C9, 
+    0x23D5, 0x23DD, 0x23E3, 0x23EF, 0x23F3, 0x23F9, 0x2405, 0x240B, 
+    0x2417, 0x2419, 0x2429, 0x243D, 0x2441, 0x2443, 0x244D, 0x245F, 
+    0x2467, 0x246B, 0x2479, 0x247D, 0x247F, 0x2485, 0x249B, 0x24A1, 
+    0x24AF, 0x24B5, 0x24BB, 0x24C5, 0x24CB, 0x24CD, 0x24D7, 0x24D9, 
+    0x24DD, 0x24DF, 0x24F5, 0x24F7, 0x24FB, 0x2501, 0x2507, 0x2513, 
+    0x2519, 0x2527, 0x2531, 0x253D, 0x2543, 0x254B, 0x254F, 0x2573,
+    0x2581, 0x258D, 0x2593, 0x2597, 0x259D, 0x259F, 0x25AB, 0x25B1, 
+    0x25BD, 0x25CD, 0x25CF, 0x25D9, 0x25E1, 0x25F7, 0x25F9, 0x2605, 
+    0x260B, 0x260F, 0x2615, 0x2627, 0x2629, 0x2635, 0x263B, 0x263F, 
+    0x264B, 0x2653, 0x2659, 0x2665, 0x2669, 0x266F, 0x267B, 0x2681, 
+    0x2683, 0x268F, 0x269B, 0x269F, 0x26AD, 0x26B3, 0x26C3, 0x26C9, 
+    0x26CB, 0x26D5, 0x26DD, 0x26EF, 0x26F5, 0x2717, 0x2719, 0x2735, 
+    0x2737, 0x274D, 0x2753, 0x2755, 0x275F, 0x276B, 0x276D, 0x2773, 
+    0x2777, 0x277F, 0x2795, 0x279B, 0x279D, 0x27A7, 0x27AF, 0x27B3, 
+    0x27B9, 0x27C1, 0x27C5, 0x27D1, 0x27E3, 0x27EF, 0x2803, 0x2807, 
+    0x280D, 0x2813, 0x281B, 0x281F, 0x2821, 0x2831, 0x283D, 0x283F, 
+    0x2849, 0x2851, 0x285B, 0x285D, 0x2861, 0x2867, 0x2875, 0x2881, 
+    0x2897, 0x289F, 0x28BB, 0x28BD, 0x28C1, 0x28D5, 0x28D9, 0x28DB, 
+    0x28DF, 0x28ED, 0x28F7, 0x2903, 0x2905, 0x2911, 0x2921, 0x2923, 
+    0x293F, 0x2947, 0x295D, 0x2965, 0x2969, 0x296F, 0x2975, 0x2983, 
+    0x2987, 0x298F, 0x299B, 0x29A1, 0x29A7, 0x29AB, 0x29BF, 0x29C3,
+    0x29D5, 0x29D7, 0x29E3, 0x29E9, 0x29ED, 0x29F3, 0x2A01, 0x2A13, 
+    0x2A1D, 0x2A25, 0x2A2F, 0x2A4F, 0x2A55, 0x2A5F, 0x2A65, 0x2A6B, 
+    0x2A6D, 0x2A73, 0x2A83, 0x2A89, 0x2A8B, 0x2A97, 0x2A9D, 0x2AB9, 
+    0x2ABB, 0x2AC5, 0x2ACD, 0x2ADD, 0x2AE3, 0x2AEB, 0x2AF1, 0x2AFB, 
+    0x2B13, 0x2B27, 0x2B31, 0x2B33, 0x2B3D, 0x2B3F, 0x2B4B, 0x2B4F, 
+    0x2B55, 0x2B69, 0x2B6D, 0x2B6F, 0x2B7B, 0x2B8D, 0x2B97, 0x2B99, 
+    0x2BA3, 0x2BA5, 0x2BA9, 0x2BBD, 0x2BCD, 0x2BE7, 0x2BEB, 0x2BF3, 
+    0x2BF9, 0x2BFD, 0x2C09, 0x2C0F, 0x2C17, 0x2C23, 0x2C2F, 0x2C35, 
+    0x2C39, 0x2C41, 0x2C57, 0x2C59, 0x2C69, 0x2C77, 0x2C81, 0x2C87, 
+    0x2C93, 0x2C9F, 0x2CAD, 0x2CB3, 0x2CB7, 0x2CCB, 0x2CCF, 0x2CDB, 
+    0x2CE1, 0x2CE3, 0x2CE9, 0x2CEF, 0x2CFF, 0x2D07, 0x2D1D, 0x2D1F, 
+    0x2D3B, 0x2D43, 0x2D49, 0x2D4D, 0x2D61, 0x2D65, 0x2D71, 0x2D89, 
+    0x2D9D, 0x2DA1, 0x2DA9, 0x2DB3, 0x2DB5, 0x2DC5, 0x2DC7, 0x2DD3, 
+    0x2DDF, 0x2E01, 0x2E03, 0x2E07, 0x2E0D, 0x2E19, 0x2E1F, 0x2E25, 
+    0x2E2D, 0x2E33, 0x2E37, 0x2E39, 0x2E3F, 0x2E57, 0x2E5B, 0x2E6F, 
+    0x2E79, 0x2E7F, 0x2E85, 0x2E93, 0x2E97, 0x2E9D, 0x2EA3, 0x2EA5, 
+    0x2EB1, 0x2EB7, 0x2EC1, 0x2EC3, 0x2ECD, 0x2ED3, 0x2EE7, 0x2EEB, 
+    0x2F05, 0x2F09, 0x2F0B, 0x2F11, 0x2F27, 0x2F29, 0x2F41, 0x2F45, 
+    0x2F4B, 0x2F4D, 0x2F51, 0x2F57, 0x2F6F, 0x2F75, 0x2F7D, 0x2F81, 
+    0x2F83, 0x2FA5, 0x2FAB, 0x2FB3, 0x2FC3, 0x2FCF, 0x2FD1, 0x2FDB, 
+    0x2FDD, 0x2FE7, 0x2FED, 0x2FF5, 0x2FF9, 0x3001, 0x300D, 0x3023, 
+    0x3029, 0x3037, 0x303B, 0x3055, 0x3059, 0x305B, 0x3067, 0x3071, 
+    0x3079, 0x307D, 0x3085, 0x3091, 0x3095, 0x30A3, 0x30A9, 0x30B9, 
+    0x30BF, 0x30C7, 0x30CB, 0x30D1, 0x30D7, 0x30DF, 0x30E5, 0x30EF, 
+    0x30FB, 0x30FD, 0x3103, 0x3109, 0x3119, 0x3121, 0x3127, 0x312D, 
+    0x3139, 0x3143, 0x3145, 0x314B, 0x315D, 0x3161, 0x3167, 0x316D, 
+    0x3173, 0x317F, 0x3191, 0x3199, 0x319F, 0x31A9, 0x31B1, 0x31C3, 
+    0x31C7, 0x31D5, 0x31DB, 0x31ED, 0x31F7, 0x31FF, 0x3209, 0x3215, 
+    0x3217, 0x321D, 0x3229, 0x3235, 0x3259, 0x325D, 0x3263, 0x326B, 
+    0x326F, 0x3275, 0x3277, 0x327B, 0x328D, 0x3299, 0x329F, 0x32A7, 
+    0x32AD, 0x32B3, 0x32B7, 0x32C9, 0x32CB, 0x32CF, 0x32D1, 0x32E9, 
+    0x32ED, 0x32F3, 0x32F9, 0x3307, 0x3325, 0x332B, 0x332F, 0x3335, 
+    0x3341, 0x3347, 0x335B, 0x335F, 0x3367, 0x336B, 0x3373, 0x3379, 
+    0x337F, 0x3383, 0x33A1, 0x33A3, 0x33AD, 0x33B9, 0x33C1, 0x33CB, 
+    0x33D3, 0x33EB, 0x33F1, 0x33FD, 0x3401, 0x340F, 0x3413, 0x3419, 
+    0x341B, 0x3437, 0x3445, 0x3455, 0x3457, 0x3463, 0x3469, 0x346D, 
+    0x3481, 0x348B, 0x3491, 0x3497, 0x349D, 0x34A5, 0x34AF, 0x34BB, 
+    0x34C9, 0x34D3, 0x34E1, 0x34F1, 0x34FF, 0x3509, 0x3517, 0x351D, 
+    0x352D, 0x3533, 0x353B, 0x3541, 0x3551, 0x3565, 0x356F, 0x3571, 
+    0x3577, 0x357B, 0x357D, 0x3581, 0x358D, 0x358F, 0x3599, 0x359B,
+    0x35A1, 0x35B7, 0x35BD, 0x35BF, 0x35C3, 0x35D5, 0x35DD, 0x35E7, 
+    0x35EF, 0x3605, 0x3607, 0x3611, 0x3623, 0x3631, 0x3635, 0x3637, 
+    0x363B, 0x364D, 0x364F, 0x3653, 0x3659, 0x3661, 0x366B, 0x366D, 
+    0x368B, 0x368F, 0x36AD, 0x36AF, 0x36B9, 0x36BB, 0x36CD, 0x36D1, 
+    0x36E3, 0x36E9, 0x36F7, 0x3701, 0x3703, 0x3707, 0x371B, 0x373F, 
+    0x3745, 0x3749, 0x374F, 0x375D, 0x3761, 0x3775, 0x377F, 0x378D, 
+    0x37A3, 0x37A9, 0x37AB, 0x37C9, 0x37D5, 0x37DF, 0x37F1, 0x37F3, 
+    0x37F7, 0x3805, 0x380B, 0x3821, 0x3833, 0x3835, 0x3841, 0x3847, 
+    0x384B, 0x3853, 0x3857, 0x385F, 0x3865, 0x386F, 0x3871, 0x387D, 
+    0x388F, 0x3899, 0x38A7, 0x38B7, 0x38C5, 0x38C9, 0x38CF, 0x38D5, 
+    0x38D7, 0x38DD, 0x38E1, 0x38E3, 0x38FF, 0x3901, 0x391D, 0x3923, 
+    0x3925, 0x3929, 0x392F, 0x393D, 0x3941, 0x394D, 0x395B, 0x396B, 
+    0x3979, 0x397D, 0x3983, 0x398B, 0x3991, 0x3995, 0x399B, 0x39A1, 
+    0x39A7, 0x39AF, 0x39B3, 0x39BB, 0x39BF, 0x39CD, 0x39DD, 0x39E5, 
+    0x39EB, 0x39EF, 0x39FB, 0x3A03, 0x3A13, 0x3A15, 0x3A1F, 0x3A27,
+    0x3A2B, 0x3A31, 0x3A4B, 0x3A51, 0x3A5B, 0x3A63, 0x3A67, 0x3A6D, 
+    0x3A79, 0x3A87, 0x3AA5, 0x3AA9, 0x3AB7, 0x3ACD, 0x3AD5, 0x3AE1, 
+    0x3AE5, 0x3AEB, 0x3AF3, 0x3AFD, 0x3B03, 0x3B11, 0x3B1B, 0x3B21, 
+    0x3B23, 0x3B2D, 0x3B39, 0x3B45, 0x3B53, 0x3B59, 0x3B5F, 0x3B71, 
+    0x3B7B, 0x3B81, 0x3B89, 0x3B9B, 0x3B9F, 0x3BA5, 0x3BA7, 0x3BAD, 
+    0x3BB7, 0x3BB9, 0x3BC3, 0x3BCB, 0x3BD1, 0x3BD7, 0x3BE1, 0x3BE3, 
+    0x3BF5, 0x3BFF, 0x3C01, 0x3C0D, 0x3C11, 0x3C17, 0x3C1F, 0x3C29, 
+    0x3C35, 0x3C43, 0x3C4F, 0x3C53, 0x3C5B, 0x3C65, 0x3C6B, 0x3C71, 
+    0x3C85, 0x3C89, 0x3C97, 0x3CA7, 0x3CB5, 0x3CBF, 0x3CC7, 0x3CD1, 
+    0x3CDD, 0x3CDF, 0x3CF1, 0x3CF7, 0x3D03, 0x3D0D, 0x3D19, 0x3D1B, 
+    0x3D1F, 0x3D21, 0x3D2D, 0x3D33, 0x3D37, 0x3D3F, 0x3D43, 0x3D6F, 
+    0x3D73, 0x3D75, 0x3D79, 0x3D7B, 0x3D85, 0x3D91, 0x3D97, 0x3D9D, 
+    0x3DAB, 0x3DAF, 0x3DB5, 0x3DBB, 0x3DC1, 0x3DC9, 0x3DCF, 0x3DF3, 
+    0x3E05, 0x3E09, 0x3E0F, 0x3E11, 0x3E1D, 0x3E23, 0x3E29, 0x3E2F, 
+    0x3E33, 0x3E41, 0x3E57, 0x3E63, 0x3E65, 0x3E77, 0x3E81, 0x3E87, 
+    0x3EA1, 0x3EB9, 0x3EBD, 0x3EBF, 0x3EC3, 0x3EC5, 0x3EC9, 0x3ED7, 
+    0x3EDB, 0x3EE1, 0x3EE7, 0x3EEF, 0x3EFF, 0x3F0B, 0x3F0D, 0x3F37, 
+    0x3F3B, 0x3F3D, 0x3F41, 0x3F59, 0x3F5F, 0x3F65, 0x3F67, 0x3F79, 
+    0x3F7D, 0x3F8B, 0x3F91, 0x3FAD, 0x3FBF, 0x3FCD, 0x3FD3, 0x3FDD, 
+    0x3FE9, 0x3FEB, 0x3FF1, 0x3FFD, 0x401B, 0x4021, 0x4025, 0x402B, 
+    0x4031, 0x403F, 0x4043, 0x4045, 0x405D, 0x4061, 0x4067, 0x406D, 
+    0x4087, 0x4091, 0x40A3, 0x40A9, 0x40B1, 0x40B7, 0x40BD, 0x40DB, 
+    0x40DF, 0x40EB, 0x40F7, 0x40F9, 0x4109, 0x410B, 0x4111, 0x4115, 
+    0x4121, 0x4133, 0x4135, 0x413B, 0x413F, 0x4159, 0x4165, 0x416B, 
+    0x4177, 0x417B, 0x4193, 0x41AB, 0x41B7, 0x41BD, 0x41BF, 0x41CB, 
+    0x41E7, 0x41EF, 0x41F3, 0x41F9, 0x4205, 0x4207, 0x4219, 0x421F, 
+    0x4223, 0x4229, 0x422F, 0x4243, 0x4253, 0x4255, 0x425B, 0x4261, 
+    0x4273, 0x427D, 0x4283, 0x4285, 0x4289, 0x4291, 0x4297, 0x429D, 
+    0x42B5, 0x42C5, 0x42CB, 0x42D3, 0x42DD, 0x42E3, 0x42F1, 0x4307, 
+    0x430F, 0x431F, 0x4325, 0x4327, 0x4333, 0x4337, 0x4339, 0x434F, 
+    0x4357, 0x4369, 0x438B, 0x438D, 0x4393, 0x43A5, 0x43A9, 0x43AF, 
+    0x43B5, 0x43BD, 0x43C7, 0x43CF, 0x43E1, 0x43E7, 0x43EB, 0x43ED, 
+    0x43F1, 0x43F9, 0x4409, 0x440B, 0x4417, 0x4423, 0x4429, 0x443B, 
+    0x443F, 0x4445, 0x444B, 0x4451, 0x4453, 0x4459, 0x4465, 0x446F, 
+    0x4483, 0x448F, 0x44A1, 0x44A5, 0x44AB, 0x44AD, 0x44BD, 0x44BF, 
+    0x44C9, 0x44D7, 0x44DB, 0x44F9, 0x44FB, 0x4505, 0x4511, 0x4513, 
+    0x452B, 0x4531, 0x4541, 0x4549, 0x4553, 0x4555, 0x4561, 0x4577, 
+    0x457D, 0x457F, 0x458F, 0x45A3, 0x45AD, 0x45AF, 0x45BB, 0x45C7, 
+    0x45D9, 0x45E3, 0x45EF, 0x45F5, 0x45F7, 0x4601, 0x4603, 0x4609, 
+    0x4613, 0x4625, 0x4627, 0x4633, 0x4639, 0x463D, 0x4643, 0x4645, 
+    0x465D, 0x4679, 0x467B, 0x467F, 0x4681, 0x468B, 0x468D, 0x469D, 
+    0x46A9, 0x46B1, 0x46C7, 0x46C9, 0x46CF, 0x46D3, 0x46D5, 0x46DF, 
+    0x46E5, 0x46F9, 0x4705, 0x470F, 0x4717, 0x4723, 0x4729, 0x472F, 
+    0x4735, 0x4739, 0x474B, 0x474D, 0x4751, 0x475D, 0x476F, 0x4771, 
+    0x477D, 0x4783, 0x4787, 0x4789, 0x4799, 0x47A5, 0x47B1, 0x47BF, 
+    0x47C3, 0x47CB, 0x47DD, 0x47E1, 0x47ED, 0x47FB, 0x4801, 0x4807, 
+    0x480B, 0x4813, 0x4819, 0x481D, 0x4831, 0x483D, 0x4847, 0x4855, 
+    0x4859, 0x485B, 0x486B, 0x486D, 0x4879, 0x4897, 0x489B, 0x48A1, 
+    0x48B9, 0x48CD, 0x48E5, 0x48EF, 0x48F7, 0x4903, 0x490D, 0x4919, 
+    0x491F, 0x492B, 0x4937, 0x493D, 0x4945, 0x4955, 0x4963, 0x4969, 
+    0x496D, 0x4973, 0x4997, 0x49AB, 0x49B5, 0x49D3, 0x49DF, 0x49E1, 
+    0x49E5, 0x49E7, 0x4A03, 0x4A0F, 0x4A1D, 0x4A23, 0x4A39, 0x4A41, 
+    0x4A45, 0x4A57, 0x4A5D, 0x4A6B, 0x4A7D, 0x4A81, 0x4A87, 0x4A89, 
+    0x4A8F, 0x4AB1, 0x4AC3, 0x4AC5, 0x4AD5, 0x4ADB, 0x4AED, 0x4AEF, 
+    0x4B07, 0x4B0B, 0x4B0D, 0x4B13, 0x4B1F, 0x4B25, 0x4B31, 0x4B3B,
+    0x4B43, 0x4B49, 0x4B59, 0x4B65, 0x4B6D, 0x4B77, 0x4B85, 0x4BAD, 
+    0x4BB3, 0x4BB5, 0x4BBB, 0x4BBF, 0x4BCB, 0x4BD9, 0x4BDD, 0x4BDF, 
+    0x4BE3, 0x4BE5, 0x4BE9, 0x4BF1, 0x4BF7, 0x4C01, 0x4C07, 0x4C0D, 
+    0x4C0F, 0x4C15, 0x4C1B, 0x4C21, 0x4C2D, 0x4C33, 0x4C4B, 0x4C55, 
+    0x4C57, 0x4C61, 0x4C67, 0x4C73, 0x4C79, 0x4C7F, 0x4C8D, 0x4C93, 
+    0x4C99, 0x4CCD, 0x4CE1, 0x4CE7, 0x4CF1, 0x4CF3, 0x4CFD, 0x4D05, 
+    0x4D0F, 0x4D1B, 0x4D27, 0x4D29, 0x4D2F, 0x4D33, 0x4D41, 0x4D51, 
+    0x4D59, 0x4D65, 0x4D6B, 0x4D81, 0x4D83, 0x4D8D, 0x4D95, 0x4D9B, 
+    0x4DB1, 0x4DB3, 0x4DC9, 0x4DCF, 0x4DD7, 0x4DE1, 0x4DED, 0x4DF9, 
+    0x4DFB, 0x4E05, 0x4E0B, 0x4E17, 0x4E19, 0x4E1D, 0x4E2B, 0x4E35, 
+    0x4E37, 0x4E3D, 0x4E4F, 0x4E53, 0x4E5F, 0x4E67, 0x4E79, 0x4E85, 
+    0x4E8B, 0x4E91, 0x4E95, 0x4E9B, 0x4EA1, 0x4EAF, 0x4EB3, 0x4EB5, 
+    0x4EC1, 0x4ECD, 0x4ED1, 0x4ED7, 0x4EE9, 0x4EFB, 0x4F07, 0x4F09, 
+    0x4F19, 0x4F25, 0x4F2D, 0x4F3F, 0x4F49, 0x4F63, 0x4F67, 0x4F6D, 
+    0x4F75, 0x4F7B, 0x4F81, 0x4F85, 0x4F87, 0x4F91, 0x4FA5, 0x4FA9, 
+    0x4FAF, 0x4FB7, 0x4FBB, 0x4FCF, 0x4FD9, 0x4FDB, 0x4FFD, 0x4FFF, 
+    0x5003, 0x501B, 0x501D, 0x5029, 0x5035, 0x503F, 0x5045, 0x5047, 
+    0x5053, 0x5071, 0x5077, 0x5083, 0x5093, 0x509F, 0x50A1, 0x50B7, 
+    0x50C9, 0x50D5, 0x50E3, 0x50ED, 0x50EF, 0x50FB, 0x5107, 0x510B, 
+    0x510D, 0x5111, 0x5117, 0x5123, 0x5125, 0x5135, 0x5147, 0x5149, 
+    0x5171, 0x5179, 0x5189, 0x518F, 0x5197, 0x51A1, 0x51A3, 0x51A7, 
+    0x51B9, 0x51C1, 0x51CB, 0x51D3, 0x51DF, 0x51E3, 0x51F5, 0x51F7, 
+    0x5209, 0x5213, 0x5215, 0x5219, 0x521B, 0x521F, 0x5227, 0x5243, 
+    0x5245, 0x524B, 0x5261, 0x526D, 0x5273, 0x5281, 0x5293, 0x5297, 
+    0x529D, 0x52A5, 0x52AB, 0x52B1, 0x52BB, 0x52C3, 0x52C7, 0x52C9, 
+    0x52DB, 0x52E5, 0x52EB, 0x52FF, 0x5315, 0x531D, 0x5323, 0x5341, 
+    0x5345, 0x5347, 0x534B, 0x535D, 0x5363, 0x5381, 0x5383, 0x5387, 
+    0x538F, 0x5395, 0x5399, 0x539F, 0x53AB, 0x53B9, 0x53DB, 0x53E9, 
+    0x53EF, 0x53F3, 0x53F5, 0x53FB, 0x53FF, 0x540D, 0x5411, 0x5413, 
+    0x5419, 0x5435, 0x5437, 0x543B, 0x5441, 0x5449, 0x5453, 0x5455, 
+    0x545F, 0x5461, 0x546B, 0x546D, 0x5471, 0x548F, 0x5491, 0x549D, 
+    0x54A9, 0x54B3, 0x54C5, 0x54D1, 0x54DF, 0x54E9, 0x54EB, 0x54F7, 
+    0x54FD, 0x5507, 0x550D, 0x551B, 0x5527, 0x552B, 0x5539, 0x553D, 
+    0x554F, 0x5551, 0x555B, 0x5563, 0x5567, 0x556F, 0x5579, 0x5585, 
+    0x5597, 0x55A9, 0x55B1, 0x55B7, 0x55C9, 0x55D9, 0x55E7, 0x55ED, 
+    0x55F3, 0x55FD, 0x560B, 0x560F, 0x5615, 0x5617, 0x5623, 0x562F, 
+    0x5633, 0x5639, 0x563F, 0x564B, 0x564D, 0x565D, 0x565F, 0x566B, 
+    0x5671, 0x5675, 0x5683, 0x5689, 0x568D, 0x568F, 0x569B, 0x56AD, 
+    0x56B1, 0x56D5, 0x56E7, 0x56F3, 0x56FF, 0x5701, 0x5705, 0x5707, 
+    0x570B, 0x5713, 0x571F, 0x5723, 0x5747, 0x574D, 0x575F, 0x5761, 
+    0x576D, 0x5777, 0x577D, 0x5789, 0x57A1, 0x57A9, 0x57AF, 0x57B5, 
+    0x57C5, 0x57D1, 0x57D3, 0x57E5, 0x57EF, 0x5803, 0x580D, 0x580F, 
+    0x5815, 0x5827, 0x582B, 0x582D, 0x5855, 0x585B, 0x585D, 0x586D, 
+    0x586F, 0x5873, 0x587B, 0x588D, 0x5897, 0x58A3, 0x58A9, 0x58AB, 
+    0x58B5, 0x58BD, 0x58C1, 0x58C7, 0x58D3, 0x58D5, 0x58DF, 0x58F1, 
+    0x58F9, 0x58FF, 0x5903, 0x5917, 0x591B, 0x5921, 0x5945, 0x594B, 
+    0x594D, 0x5957, 0x595D, 0x5975, 0x597B, 0x5989, 0x5999, 0x599F, 
+    0x59B1, 0x59B3, 0x59BD, 0x59D1, 0x59DB, 0x59E3, 0x59E9, 0x59ED, 
+    0x59F3, 0x59F5, 0x59FF, 0x5A01, 0x5A0D, 0x5A11, 0x5A13, 0x5A17, 
+    0x5A1F, 0x5A29, 0x5A2F, 0x5A3B, 0x5A4D, 0x5A5B, 0x5A67, 0x5A77, 
+    0x5A7F, 0x5A85, 0x5A95, 0x5A9D, 0x5AA1, 0x5AA3, 0x5AA9, 0x5ABB, 
+    0x5AD3, 0x5AE5, 0x5AEF, 0x5AFB, 0x5AFD, 0x5B01, 0x5B0F, 0x5B19, 
+    0x5B1F, 0x5B25, 0x5B2B, 0x5B3D, 0x5B49, 0x5B4B, 0x5B67, 0x5B79, 
+    0x5B87, 0x5B97, 0x5BA3, 0x5BB1, 0x5BC9, 0x5BD5, 0x5BEB, 0x5BF1, 
+    0x5BF3, 0x5BFD, 0x5C05, 0x5C09, 0x5C0B, 0x5C0F, 0x5C1D, 0x5C29,
+    0x5C2F, 0x5C33, 0x5C39, 0x5C47, 0x5C4B, 0x5C4D, 0x5C51, 0x5C6F, 
+    0x5C75, 0x5C77, 0x5C7D, 0x5C87, 0x5C89, 0x5CA7, 0x5CBD, 0x5CBF, 
+    0x5CC3, 0x5CC9, 0x5CD1, 0x5CD7, 0x5CDD, 0x5CED, 0x5CF9, 0x5D05, 
+    0x5D0B, 0x5D13, 0x5D17, 0x5D19, 0x5D31, 0x5D3D, 0x5D41, 0x5D47, 
+    0x5D4F, 0x5D55, 0x5D5B, 0x5D65, 0x5D67, 0x5D6D, 0x5D79, 0x5D95, 
+    0x5DA3, 0x5DA9, 0x5DAD, 0x5DB9, 0x5DC1, 0x5DC7, 0x5DD3, 0x5DD7, 
+    0x5DDD, 0x5DEB, 0x5DF1, 0x5DFD, 0x5E07, 0x5E0D, 0x5E13, 0x5E1B, 
+    0x5E21, 0x5E27, 0x5E2B, 0x5E2D, 0x5E31, 0x5E39, 0x5E45, 0x5E49, 
+    0x5E57, 0x5E69, 0x5E73, 0x5E75, 0x5E85, 0x5E8B, 0x5E9F, 0x5EA5, 
+    0x5EAF, 0x5EB7, 0x5EBB, 0x5ED9, 0x5EFD, 0x5F09, 0x5F11, 0x5F27, 
+    0x5F33, 0x5F35, 0x5F3B, 0x5F47, 0x5F57, 0x5F5D, 0x5F63, 0x5F65, 
+    0x5F77, 0x5F7B, 0x5F95, 0x5F99, 0x5FA1, 0x5FB3, 0x5FBD, 0x5FC5, 
+    0x5FCF, 0x5FD5, 0x5FE3, 0x5FE7, 0x5FFB, 0x6011, 0x6023, 0x602F, 
+    0x6037, 0x6053, 0x605F, 0x6065, 0x606B, 0x6073, 0x6079, 0x6085, 
+    0x609D, 0x60AD, 0x60BB, 0x60BF, 0x60CD, 0x60D9, 0x60DF, 0x60E9, 
+    0x60F5, 0x6109, 0x610F, 0x6113, 0x611B, 0x612D, 0x6139, 0x614B, 
+    0x6155, 0x6157, 0x615B, 0x616F, 0x6179, 0x6187, 0x618B, 0x6191, 
+    0x6193, 0x619D, 0x61B5, 0x61C7, 0x61C9, 0x61CD, 0x61E1, 0x61F1, 
+    0x61FF, 0x6209, 0x6217, 0x621D, 0x6221, 0x6227, 0x623B, 0x6241, 
+    0x624B, 0x6251, 0x6253, 0x625F, 0x6265, 0x6283, 0x628D, 0x6295, 
+    0x629B, 0x629F, 0x62A5, 0x62AD, 0x62D5, 0x62D7, 0x62DB, 0x62DD, 
+    0x62E9, 0x62FB, 0x62FF, 0x6305, 0x630D, 0x6317, 0x631D, 0x632F, 
+    0x6341, 0x6343, 0x634F, 0x635F, 0x6367, 0x636D, 0x6371, 0x6377, 
+    0x637D, 0x637F, 0x63B3, 0x63C1, 0x63C5, 0x63D9, 0x63E9, 0x63EB, 
+    0x63EF, 0x63F5, 0x6401, 0x6403, 0x6409, 0x6415, 0x6421, 0x6427, 
+    0x642B, 0x6439, 0x6443, 0x6449, 0x644F, 0x645D, 0x6467, 0x6475, 
+    0x6485, 0x648D, 0x6493, 0x649F, 0x64A3, 0x64AB, 0x64C1, 0x64C7, 
+    0x64C9, 0x64DB, 0x64F1, 0x64F7, 0x64F9, 0x650B, 0x6511, 0x6521, 
+    0x652F, 0x6539, 0x653F, 0x654B, 0x654D, 0x6553, 0x6557, 0x655F, 
+    0x6571, 0x657D, 0x658D, 0x658F, 0x6593, 0x65A1, 0x65A5, 0x65AD, 
+    0x65B9, 0x65C5, 0x65E3, 0x65F3, 0x65FB, 0x65FF, 0x6601, 0x6607, 
+    0x661D, 0x6629, 0x6631, 0x663B, 0x6641, 0x6647, 0x664D, 0x665B, 
+    0x6661, 0x6673, 0x667D, 0x6689, 0x668B, 0x6695, 0x6697, 0x669B, 
+    0x66B5, 0x66B9, 0x66C5, 0x66CD, 0x66D1, 0x66E3, 0x66EB, 0x66F5, 
+    0x6703, 0x6713, 0x6719, 0x671F, 0x6727, 0x6731, 0x6737, 0x673F, 
+    0x6745, 0x6751, 0x675B, 0x676F, 0x6779, 0x6781, 0x6785, 0x6791, 
+    0x67AB, 0x67BD, 0x67C1, 0x67CD, 0x67DF, 0x67E5, 0x6803, 0x6809, 
+    0x6811, 0x6817, 0x682D, 0x6839, 0x683B, 0x683F, 0x6845, 0x684B, 
+    0x684D, 0x6857, 0x6859, 0x685D, 0x6863, 0x6869, 0x686B, 0x6871, 
+    0x6887, 0x6899, 0x689F, 0x68B1, 0x68BD, 0x68C5, 0x68D1, 0x68D7, 
+    0x68E1, 0x68ED, 0x68EF, 0x68FF, 0x6901, 0x690B, 0x690D, 0x6917, 
+    0x6929, 0x692F, 0x6943, 0x6947, 0x6949, 0x694F, 0x6965, 0x696B, 
+    0x6971, 0x6983, 0x6989, 0x6997, 0x69A3, 0x69B3, 0x69B5, 0x69BB, 
+    0x69C1, 0x69C5, 0x69D3, 0x69DF, 0x69E3, 0x69E5, 0x69F7, 0x6A07, 
+    0x6A2B, 0x6A37, 0x6A3D, 0x6A4B, 0x6A67, 0x6A69, 0x6A75, 0x6A7B, 
+    0x6A87, 0x6A8D, 0x6A91, 0x6A93, 0x6AA3, 0x6AC1, 0x6AC9, 0x6AE1, 
+    0x6AE7, 0x6B05, 0x6B0F, 0x6B11, 0x6B23, 0x6B27, 0x6B2D, 0x6B39, 
+    0x6B41, 0x6B57, 0x6B59, 0x6B5F, 0x6B75, 0x6B87, 0x6B89, 0x6B93, 
+    0x6B95, 0x6B9F, 0x6BBD, 0x6BBF, 0x6BDB, 0x6BE1, 0x6BEF, 0x6BFF, 
+    0x6C05, 0x6C19, 0x6C29, 0x6C2B, 0x6C31, 0x6C35, 0x6C55, 0x6C59, 
+    0x6C5B, 0x6C5F, 0x6C65, 0x6C67, 0x6C73, 0x6C77, 0x6C7D, 0x6C83, 
+    0x6C8F, 0x6C91, 0x6C97, 0x6C9B, 0x6CA1, 0x6CA9, 0x6CAF, 0x6CB3, 
+    0x6CC7, 0x6CCB, 0x6CEB, 0x6CF5, 0x6CFD, 0x6D0D, 0x6D0F, 0x6D25, 
+    0x6D27, 0x6D2B, 0x6D31, 0x6D39, 0x6D3F, 0x6D4F, 0x6D5D, 0x6D61, 
+    0x6D73, 0x6D7B, 0x6D7F, 0x6D93, 0x6D99, 0x6DA5, 0x6DB1, 0x6DB7, 
+    0x6DC1, 0x6DC3, 0x6DCD, 0x6DCF, 0x6DDB, 0x6DF7, 0x6E03, 0x6E15, 
+    0x6E17, 0x6E29, 0x6E33, 0x6E3B, 0x6E45, 0x6E75, 0x6E77, 0x6E7B, 
+    0x6E81, 0x6E89, 0x6E93, 0x6E95, 0x6E9F, 0x6EBD, 0x6EBF, 0x6EE3, 
+    0x6EE9, 0x6EF3, 0x6EF9, 0x6EFB, 0x6F0D, 0x6F11, 0x6F17, 0x6F1F, 
+    0x6F2F, 0x6F3D, 0x6F4D, 0x6F53, 0x6F61, 0x6F65, 0x6F79, 0x6F7D, 
+    0x6F83, 0x6F85, 0x6F8F, 0x6F9B, 0x6F9D, 0x6FA3, 0x6FAF, 0x6FB5, 
+    0x6FBB, 0x6FBF, 0x6FCB, 0x6FCD, 0x6FD3, 0x6FD7, 0x6FE3, 0x6FE9, 
+    0x6FF1, 0x6FF5, 0x6FF7, 0x6FFD, 0x700F, 0x7019, 0x701F, 0x7027, 
+    0x7033, 0x7039, 0x704F, 0x7051, 0x7057, 0x7063, 0x7075, 0x7079, 
+    0x7087, 0x708D, 0x7091, 0x70A5, 0x70AB, 0x70BB, 0x70C3, 0x70C7, 
+    0x70CF, 0x70E5, 0x70ED, 0x70F9, 0x70FF, 0x7105, 0x7115, 0x7121, 
+    0x7133, 0x7151, 0x7159, 0x715D, 0x715F, 0x7163, 0x7169, 0x7183, 
+    0x7187, 0x7195, 0x71AD, 0x71C3, 0x71C9, 0x71CB, 0x71D1, 0x71DB, 
+    0x71E1, 0x71EF, 0x71F5, 0x71FB, 0x7207, 0x7211, 0x7217, 0x7219, 
+    0x7225, 0x722F, 0x723B, 0x7243, 0x7255, 0x7267, 0x7271, 0x7277, 
+    0x727F, 0x728F, 0x7295, 0x729B, 0x72A3, 0x72B3, 0x72C7, 0x72CB, 
+    0x72CD, 0x72D7, 0x72D9, 0x72E3, 0x72EF, 0x72F5, 0x72FD, 0x7303, 
+    0x730D, 0x7321, 0x732B, 0x733D, 0x7357, 0x735B, 0x7361, 0x737F, 
+    0x7381, 0x7385, 0x738D, 0x7393, 0x739F, 0x73AB, 0x73BD, 0x73C1, 
+    0x73C9, 0x73DF, 0x73E5, 0x73E7, 0x73F3, 0x7415, 0x741B, 0x742D, 
+    0x7439, 0x743F, 0x7441, 0x745D, 0x746B, 0x747B, 0x7489, 0x748D, 
+    0x749B, 0x74A7, 0x74AB, 0x74B1, 0x74B7, 0x74B9, 0x74DD, 0x74E1, 
+    0x74E7, 0x74FB, 0x7507, 0x751F, 0x7525, 0x753B, 0x753D, 0x754D, 
+    0x755F, 0x756B, 0x7577, 0x7589, 0x758B, 0x7591, 0x7597, 0x759D, 
+    0x75A1, 0x75A7, 0x75B5, 0x75B9, 0x75BB, 0x75D1, 0x75D9, 0x75E5, 
+    0x75EB, 0x75F5, 0x75FB, 0x7603, 0x760F, 0x7621, 0x762D, 0x7633, 
+    0x763D, 0x763F, 0x7655, 0x7663, 0x7669, 0x766F, 0x7673, 0x7685, 
+    0x768B, 0x769F, 0x76B5, 0x76B7, 0x76C3, 0x76DB, 0x76DF, 0x76F1, 
+    0x7703, 0x7705, 0x771B, 0x771D, 0x7721, 0x772D, 0x7735, 0x7741, 
+    0x774B, 0x7759, 0x775D, 0x775F, 0x7771, 0x7781, 0x77A7, 0x77AD, 
+    0x77B3, 0x77B9, 0x77C5, 0x77CF, 0x77D5, 0x77E1, 0x77E9, 0x77EF, 
+    0x77F3, 0x77F9, 0x7807, 0x7825, 0x782B, 0x7835, 0x783D, 0x7853, 
+    0x7859, 0x7861, 0x786D, 0x7877, 0x7879, 0x7883, 0x7885, 0x788B, 
+    0x7895, 0x7897, 0x78A1, 0x78AD, 0x78BF, 0x78D3, 0x78D9, 0x78DD, 
+    0x78E5, 0x78FB, 0x7901, 0x7907, 0x7925, 0x792B, 0x7939, 0x793F, 
+    0x794B, 0x7957, 0x795D, 0x7967, 0x7969, 0x7973, 0x7991, 0x7993, 
+    0x79A3, 0x79AB, 0x79AF, 0x79B1, 0x79B7, 0x79C9, 0x79CD, 0x79CF, 
+    0x79D5, 0x79D9, 0x79F3, 0x79F7, 0x79FF, 0x7A05, 0x7A0F, 0x7A11, 
+    0x7A15, 0x7A1B, 0x7A23, 0x7A27, 0x7A2D, 0x7A4B, 0x7A57, 0x7A59, 
+    0x7A5F, 0x7A65, 0x7A69, 0x7A7D, 0x7A93, 0x7A9B, 0x7A9F, 0x7AA1, 
+    0x7AA5, 0x7AED, 0x7AF5, 0x7AF9, 0x7B01, 0x7B17, 0x7B19, 0x7B1D, 
+    0x7B2B, 0x7B35, 0x7B37, 0x7B3B, 0x7B4F, 0x7B55, 0x7B5F, 0x7B71, 
+    0x7B77, 0x7B8B, 0x7B9B, 0x7BA1, 0x7BA9, 0x7BAF, 0x7BB3, 0x7BC7, 
+    0x7BD3, 0x7BE9, 0x7BEB, 0x7BEF, 0x7BF1, 0x7BFD, 0x7C07, 0x7C19, 
+    0x7C1B, 0x7C31, 0x7C37, 0x7C49, 0x7C67, 0x7C69, 0x7C73, 0x7C81, 
+    0x7C8B, 0x7C93, 0x7CA3, 0x7CD5, 0x7CDB, 0x7CE5, 0x7CED, 0x7CF7, 
+    0x7D03, 0x7D09, 0x7D1B, 0x7D1D, 0x7D33, 0x7D39, 0x7D3B, 0x7D3F, 
+    0x7D45, 0x7D4D, 0x7D53, 0x7D59, 0x7D63, 0x7D75, 0x7D77, 0x7D8D, 
+    0x7D8F, 0x7D9F, 0x7DAD, 0x7DB7, 0x7DBD, 0x7DBF, 0x7DCB, 0x7DD5, 
+    0x7DE9, 0x7DED, 0x7DFB, 0x7E01, 0x7E05, 0x7E29, 0x7E2B, 0x7E2F, 
+    0x7E35, 0x7E41, 0x7E43, 0x7E47, 0x7E55, 0x7E61, 0x7E67, 0x7E6B, 
+    0x7E71, 0x7E73, 0x7E79, 0x7E7D, 0x7E91, 0x7E9B, 0x7E9D, 0x7EA7, 
+    0x7EAD, 0x7EB9, 0x7EBB, 0x7ED3, 0x7EDF, 0x7EEB, 0x7EF1, 0x7EF7, 
+    0x7EFB, 0x7F13, 0x7F15, 0x7F19, 0x7F31, 0x7F33, 0x7F39, 0x7F3D, 
+    0x7F43, 0x7F4B, 0x7F5B, 0x7F61, 0x7F63, 0x7F6D, 0x7F79, 0x7F87, 
+    0x7F8D, 0x7FAF, 0x7FB5, 0x7FC3, 0x7FC9, 0x7FCD, 0x7FCF, 0x7FED, 
+    0x8003, 0x800B, 0x800F, 0x8015, 0x801D, 0x8021, 0x8023, 0x803F, 
+    0x8041, 0x8047, 0x804B, 0x8065, 0x8077, 0x808D, 0x808F, 0x8095, 
+    0x80A5, 0x80AB, 0x80AD, 0x80BD, 0x80C9, 0x80CB, 0x80D7, 0x80DB, 
+    0x80E1, 0x80E7, 0x80F5, 0x80FF, 0x8105, 0x810D, 0x8119, 0x811D, 
+    0x812F, 0x8131, 0x813B, 0x8143, 0x8153, 0x8159, 0x815F, 0x817D, 
+    0x817F, 0x8189, 0x819B, 0x819D, 0x81A7, 0x81AF, 0x81B3, 0x81BB, 
+    0x81C7, 0x81DF, 0x8207, 0x8209, 0x8215, 0x821F, 0x8225, 0x8231, 
+    0x8233, 0x823F, 0x8243, 0x8245, 0x8249, 0x824F, 0x8261, 0x826F, 
+    0x827B, 0x8281, 0x8285, 0x8293, 0x82B1, 0x82B5, 0x82BD, 0x82C7, 
+    0x82CF, 0x82D5, 0x82DF, 0x82F1, 0x82F9, 0x82FD, 0x830B, 0x831B, 
+    0x8321, 0x8329, 0x832D, 0x8333, 0x8335, 0x833F, 0x8341, 0x834D, 
+    0x8351, 0x8353, 0x8357, 0x835D, 0x8365, 0x8369, 0x836F, 0x838F, 
+    0x83A7, 0x83B1, 0x83B9, 0x83CB, 0x83D5, 0x83D7, 0x83DD, 0x83E7, 
+    0x83E9, 0x83ED, 0x83FF, 0x8405, 0x8411, 0x8413, 0x8423, 0x8425, 
+    0x843B, 0x8441, 0x8447, 0x844F, 0x8461, 0x8465, 0x8477, 0x8483, 
+    0x848B, 0x8491, 0x8495, 0x84A9, 0x84AF, 0x84CD, 0x84E3, 0x84EF, 
+    0x84F1, 0x84F7, 0x8509, 0x850D, 0x854B, 0x854F, 0x8551, 0x855D, 
+    0x8563, 0x856D, 0x856F, 0x857B, 0x8587, 0x85A3, 0x85A5, 0x85A9, 
+    0x85B7, 0x85CD, 0x85D3, 0x85D5, 0x85DB, 0x85E1, 0x85EB, 0x85F9, 
+    0x85FD, 0x85FF, 0x8609, 0x860F, 0x8617, 0x8621, 0x862F, 0x8639, 
+    0x863F, 0x8641, 0x864D, 0x8663, 0x8675, 0x867D, 0x8687, 0x8699, 
+    0x86A5, 0x86A7, 0x86B3, 0x86B7, 0x86C3, 0x86C5, 0x86CF, 0x86D1, 
+    0x86D7, 0x86E9, 0x86EF, 0x86F5, 0x8717, 0x871D, 0x871F, 0x872B, 
+    0x872F, 0x8735, 0x8747, 0x8759, 0x875B, 0x876B, 0x8771, 0x8777, 
+    0x877F, 0x8785, 0x878F, 0x87A1, 0x87A9, 0x87B3, 0x87BB, 0x87C5, 
+    0x87C7, 0x87CB, 0x87DD, 0x87F7, 0x8803, 0x8819, 0x881B, 0x881F, 
+    0x8821, 0x8837, 0x883D, 0x8843, 0x8851, 0x8861, 0x8867, 0x887B, 
+    0x8885, 0x8891, 0x8893, 0x88A5, 0x88CF, 0x88D3, 0x88EB, 0x88ED, 
+    0x88F3, 0x88FD, 0x8909, 0x890B, 0x8911, 0x891B, 0x8923, 0x8927, 
+    0x892D, 0x8939, 0x8945, 0x894D, 0x8951, 0x8957, 0x8963, 0x8981, 
+    0x8995, 0x899B, 0x89B3, 0x89B9, 0x89C3, 0x89CF, 0x89D1, 0x89DB, 
+    0x89EF, 0x89F5, 0x89FB, 0x89FF, 0x8A0B, 0x8A19, 0x8A23, 0x8A35, 
+    0x8A41, 0x8A49, 0x8A4F, 0x8A5B, 0x8A5F, 0x8A6D, 0x8A77, 0x8A79, 
+    0x8A85, 0x8AA3, 0x8AB3, 0x8AB5, 0x8AC1, 0x8AC7, 0x8ACB, 0x8ACD, 
+    0x8AD1, 0x8AD7, 0x8AF1, 0x8AF5, 0x8B07, 0x8B09, 0x8B0D, 0x8B13, 
+    0x8B21, 0x8B57, 0x8B5D, 0x8B91, 0x8B93, 0x8BA3, 0x8BA9, 0x8BAF, 
+    0x8BBB, 0x8BD5, 0x8BD9, 0x8BDB, 0x8BE1, 0x8BF7, 0x8BFD, 0x8BFF, 
+    0x8C0B, 0x8C17, 0x8C1D, 0x8C27, 0x8C39, 0x8C3B, 0x8C47, 0x8C53, 
+    0x8C5D, 0x8C6F, 0x8C7B, 0x8C81, 0x8C89, 0x8C8F, 0x8C99, 0x8C9F, 
+    0x8CA7, 0x8CAB, 0x8CAD, 0x8CB1, 0x8CC5, 0x8CDD, 0x8CE3, 0x8CE9, 
+    0x8CF3, 0x8D01, 0x8D0B, 0x8D0D, 0x8D23, 0x8D29, 0x8D37, 0x8D41, 
+    0x8D5B, 0x8D5F, 0x8D71, 0x8D79, 0x8D85, 0x8D91, 0x8D9B, 0x8DA7, 
+    0x8DAD, 0x8DB5, 0x8DC5, 0x8DCB, 0x8DD3, 0x8DD9, 0x8DDF, 0x8DF5, 
+    0x8DF7, 0x8E01, 0x8E15, 0x8E1F, 0x8E25, 0x8E51, 0x8E63, 0x8E69, 
+    0x8E73, 0x8E75, 0x8E79, 0x8E7F, 0x8E8D, 0x8E91, 0x8EAB, 0x8EAF, 
+    0x8EB1, 0x8EBD, 0x8EC7, 0x8ECF, 0x8ED3, 0x8EDB, 0x8EE7, 0x8EEB, 
+    0x8EF7, 0x8EFF, 0x8F15, 0x8F1D, 0x8F23, 0x8F2D, 0x8F3F, 0x8F45, 
+    0x8F4B, 0x8F53, 0x8F59, 0x8F65, 0x8F69, 0x8F71, 0x8F83, 0x8F8D, 
+    0x8F99, 0x8F9F, 0x8FAB, 0x8FAD, 0x8FB3, 0x8FB7, 0x8FB9, 0x8FC9, 
+    0x8FD5, 0x8FE1, 0x8FEF, 0x8FF9, 0x9007, 0x900D, 0x9017, 0x9023, 
+    0x9025, 0x9031, 0x9037, 0x903B, 0x9041, 0x9043, 0x904F, 0x9053, 
+    0x906D, 0x9073, 0x9085, 0x908B, 0x9095, 0x909B, 0x909D, 0x90AF, 
+    0x90B9, 0x90C1, 0x90C5, 0x90DF, 0x90E9, 0x90FD, 0x9103, 0x9113, 
+    0x9127, 0x9133, 0x913D, 0x9145, 0x914F, 0x9151, 0x9161, 0x9167, 
+    0x917B, 0x9185, 0x9199, 0x919D, 0x91BB, 0x91BD, 0x91C1, 0x91C9, 
+    0x91D9, 0x91DB, 0x91ED, 0x91F1, 0x91F3, 0x91F9, 0x9203, 0x9215, 
+    0x9221, 0x922F, 0x9241, 0x9247, 0x9257, 0x926B, 0x9271, 0x9275, 
+    0x927D, 0x9283, 0x9287, 0x928D, 0x9299, 0x92A1, 0x92AB, 0x92AD, 
+    0x92B9, 0x92BF, 0x92C3, 0x92C5, 0x92CB, 0x92D5, 0x92D7, 0x92E7, 
+    0x92F3, 0x9301, 0x930B, 0x9311, 0x9319, 0x931F, 0x933B, 0x933D, 
+    0x9343, 0x9355, 0x9373, 0x9395, 0x9397, 0x93A7, 0x93B3, 0x93B5, 
+    0x93C7, 0x93D7, 0x93DD, 0x93E5, 0x93EF, 0x93F7, 0x9401, 0x9409, 
+    0x9413, 0x943F, 0x9445, 0x944B, 0x944F, 0x9463, 0x9467, 0x9469, 
+    0x946D, 0x947B, 0x9497, 0x949F, 0x94A5, 0x94B5, 0x94C3, 0x94E1, 
+    0x94E7, 0x9505, 0x9509, 0x9517, 0x9521, 0x9527, 0x952D, 0x9535, 
+    0x9539, 0x954B, 0x9557, 0x955D, 0x955F, 0x9575, 0x9581, 0x9589, 
+    0x958F, 0x959B, 0x959F, 0x95AD, 0x95B1, 0x95B7, 0x95B9, 0x95BD, 
+    0x95CF, 0x95E3, 0x95E9, 0x95F9, 0x961F, 0x962F, 0x9631, 0x9635, 
+    0x963B, 0x963D, 0x9665, 0x968F, 0x969D, 0x96A1, 0x96A7, 0x96A9, 
+    0x96C1, 0x96CB, 0x96D1, 0x96D3, 0x96E5, 0x96EF, 0x96FB, 0x96FD, 
+    0x970D, 0x970F, 0x9715, 0x9725, 0x972B, 0x9733, 0x9737, 0x9739, 
+    0x9743, 0x9749, 0x9751, 0x975B, 0x975D, 0x976F, 0x977F, 0x9787, 
+    0x9793, 0x97A5, 0x97B1, 0x97B7, 0x97C3, 0x97CD, 0x97D3, 0x97D9, 
+    0x97EB, 0x97F7, 0x9805, 0x9809, 0x980B, 0x9815, 0x9829, 0x982F, 
+    0x983B, 0x9841, 0x9851, 0x986B, 0x986F, 0x9881, 0x9883, 0x9887, 
+    0x98A7, 0x98B1, 0x98B9, 0x98BF, 0x98C3, 0x98C9, 0x98CF, 0x98DD, 
+    0x98E3, 0x98F5, 0x98F9, 0x98FB, 0x990D, 0x9917, 0x991F, 0x9929, 
+    0x9931, 0x993B, 0x993D, 0x9941, 0x9947, 0x9949, 0x9953, 0x997D, 
+    0x9985, 0x9991, 0x9995, 0x999B, 0x99AD, 0x99AF, 0x99BF, 0x99C7, 
+    0x99CB, 0x99CD, 0x99D7, 0x99E5, 0x99F1, 0x99FB, 0x9A0F, 0x9A13, 
+    0x9A1B, 0x9A25, 0x9A4B, 0x9A4F, 0x9A55, 0x9A57, 0x9A61, 0x9A75, 
+    0x9A7F, 0x9A8B, 0x9A91, 0x9A9D, 0x9AB7, 0x9AC3, 0x9AC7, 0x9ACF, 
+    0x9AEB, 0x9AF3, 0x9AF7, 0x9AFF, 0x9B17, 0x9B1D, 0x9B27, 0x9B2F, 
+    0x9B35, 0x9B45, 0x9B51, 0x9B59, 0x9B63, 0x9B6F, 0x9B77, 0x9B8D, 
+    0x9B93, 0x9B95, 0x9B9F, 0x9BA1, 0x9BA7, 0x9BB1, 0x9BB7, 0x9BBD, 
+    0x9BC5, 0x9BCB, 0x9BCF, 0x9BDD, 0x9BF9, 0x9C01, 0x9C11, 0x9C23, 
+    0x9C2B, 0x9C2F, 0x9C35, 0x9C49, 0x9C4D, 0x9C5F, 0x9C65, 0x9C67, 
+    0x9C7F, 0x9C97, 0x9C9D, 0x9CA3, 0x9CAF, 0x9CBB, 0x9CBF, 0x9CC1, 
+    0x9CD7, 0x9CD9, 0x9CE3, 0x9CE9, 0x9CF1, 0x9CFD, 0x9D01, 0x9D15, 
+    0x9D27, 0x9D2D, 0x9D31, 0x9D3D, 0x9D55, 0x9D5B, 0x9D61, 0x9D97, 
+    0x9D9F, 0x9DA5, 0x9DA9, 0x9DC3, 0x9DE7, 0x9DEB, 0x9DED, 0x9DF1, 
+    0x9E0B, 0x9E17, 0x9E23, 0x9E27, 0x9E2D, 0x9E33, 0x9E3B, 0x9E47, 
+    0x9E51, 0x9E53, 0x9E5F, 0x9E6F, 0x9E81, 0x9E87, 0x9E8F, 0x9E95, 
+    0x9EA1, 0x9EB3, 0x9EBD, 0x9EBF, 0x9EF5, 0x9EF9, 0x9EFB, 0x9F05, 
+    0x9F23, 0x9F2F, 0x9F37, 0x9F3B, 0x9F43, 0x9F53, 0x9F61, 0x9F6D, 
+    0x9F73, 0x9F77, 0x9F7D, 0x9F89, 0x9F8F, 0x9F91, 0x9F95, 0x9FA3, 
+    0x9FAF, 0x9FB3, 0x9FC1, 0x9FC7, 0x9FDF, 0x9FE5, 0x9FEB, 0x9FF5, 
+    0xA001, 0xA00D, 0xA021, 0xA033, 0xA039, 0xA03F, 0xA04F, 0xA057, 
+    0xA05B, 0xA061, 0xA075, 0xA079, 0xA099, 0xA09D, 0xA0AB, 0xA0B5, 
+    0xA0B7, 0xA0BD, 0xA0C9, 0xA0D9, 0xA0DB, 0xA0DF, 0xA0E5, 0xA0F1, 
+    0xA0F3, 0xA0FD, 0xA105, 0xA10B, 0xA10F, 0xA111, 0xA11B, 0xA129, 
+    0xA12F, 0xA135, 0xA141, 0xA153, 0xA175, 0xA17D, 0xA187, 0xA18D, 
+    0xA1A5, 0xA1AB, 0xA1AD, 0xA1B7, 0xA1C3, 0xA1C5, 0xA1E3, 0xA1ED, 
+    0xA1FB, 0xA207, 0xA213, 0xA223, 0xA229, 0xA22F, 0xA231, 0xA243, 
+    0xA247, 0xA24D, 0xA26B, 0xA279, 0xA27D, 0xA283, 0xA289, 0xA28B, 
+    0xA291, 0xA295, 0xA29B, 0xA2A9, 0xA2AF, 0xA2B3, 0xA2BB, 0xA2C5, 
+    0xA2D1, 0xA2D7, 0xA2F7, 0xA301, 0xA309, 0xA31F, 0xA321, 0xA32B, 
+    0xA331, 0xA349, 0xA351, 0xA355, 0xA373, 0xA379, 0xA37B, 0xA387, 
+    0xA397, 0xA39F, 0xA3A5, 0xA3A9, 0xA3AF, 0xA3B7, 0xA3C7, 0xA3D5, 
+    0xA3DB, 0xA3E1, 0xA3E5, 0xA3E7, 0xA3F1, 0xA3FD, 0xA3FF, 0xA40F, 
+    0xA41D, 0xA421, 0xA423, 0xA427, 0xA43B, 0xA44D, 0xA457, 0xA459, 
+    0xA463, 0xA469, 0xA475, 0xA493, 0xA49B, 0xA4AD, 0xA4B9, 0xA4C3, 
+    0xA4C5, 0xA4CB, 0xA4D1, 0xA4D5, 0xA4E1, 0xA4ED, 0xA4EF, 0xA4F3, 
+    0xA4FF, 0xA511, 0xA529, 0xA52B, 0xA535, 0xA53B, 0xA543, 0xA553, 
+    0xA55B, 0xA561, 0xA56D, 0xA577, 0xA585, 0xA58B, 0xA597, 0xA59D, 
+    0xA5A3, 0xA5A7, 0xA5A9, 0xA5C1, 0xA5C5, 0xA5CB, 0xA5D3, 0xA5D9, 
+    0xA5DD, 0xA5DF, 0xA5E3, 0xA5E9, 0xA5F7, 0xA5FB, 0xA603, 0xA60D, 
+    0xA625, 0xA63D, 0xA649, 0xA64B, 0xA651, 0xA65D, 0xA673, 0xA691, 
+    0xA693, 0xA699, 0xA6AB, 0xA6B5, 0xA6BB, 0xA6C1, 0xA6C9, 0xA6CD, 
+    0xA6CF, 0xA6D5, 0xA6DF, 0xA6E7, 0xA6F1, 0xA6F7, 0xA6FF, 0xA70F, 
+    0xA715, 0xA723, 0xA729, 0xA72D, 0xA745, 0xA74D, 0xA757, 0xA759, 
+    0xA765, 0xA76B, 0xA76F, 0xA793, 0xA795, 0xA7AB, 0xA7B1, 0xA7B9, 
+    0xA7BF, 0xA7C9, 0xA7D1, 0xA7D7, 0xA7E3, 0xA7ED, 0xA7FB, 0xA805, 
+    0xA80B, 0xA81D, 0xA829, 0xA82B, 0xA837, 0xA83B, 0xA855, 0xA85F, 
+    0xA86D, 0xA87D, 0xA88F, 0xA897, 0xA8A9, 0xA8B5, 0xA8C1, 0xA8C7, 
+    0xA8D7, 0xA8E5, 0xA8FD, 0xA907, 0xA913, 0xA91B, 0xA931, 0xA937, 
+    0xA939, 0xA943, 0xA97F, 0xA985, 0xA987, 0xA98B, 0xA993, 0xA9A3, 
+    0xA9B1, 0xA9BB, 0xA9C1, 0xA9D9, 0xA9DF, 0xA9EB, 0xA9FD, 0xAA15, 
+    0xAA17, 0xAA35, 0xAA39, 0xAA3B, 0xAA47, 0xAA4D, 0xAA57, 0xAA59, 
+    0xAA5D, 0xAA6B, 0xAA71, 0xAA81, 0xAA83, 0xAA8D, 0xAA95, 0xAAAB, 
+    0xAABF, 0xAAC5, 0xAAC9, 0xAAE9, 0xAAEF, 0xAB01, 0xAB05, 0xAB07, 
+    0xAB0B, 0xAB0D, 0xAB11, 0xAB19, 0xAB4D, 0xAB5B, 0xAB71, 0xAB73, 
+    0xAB89, 0xAB9D, 0xABA7, 0xABAF, 0xABB9, 0xABBB, 0xABC1, 0xABC5, 
+    0xABD3, 0xABD7, 0xABDD, 0xABF1, 0xABF5, 0xABFB, 0xABFD, 0xAC09, 
+    0xAC15, 0xAC1B, 0xAC27, 0xAC37, 0xAC39, 0xAC45, 0xAC4F, 0xAC57, 
+    0xAC5B, 0xAC61, 0xAC63, 0xAC7F, 0xAC8B, 0xAC93, 0xAC9D, 0xACA9, 
+    0xACAB, 0xACAF, 0xACBD, 0xACD9, 0xACE1, 0xACE7, 0xACEB, 0xACED, 
+    0xACF1, 0xACF7, 0xACF9, 0xAD05, 0xAD3F, 0xAD45, 0xAD53, 0xAD5D, 
+    0xAD5F, 0xAD65, 0xAD81, 0xADA1, 0xADA5, 0xADC3, 0xADCB, 0xADD1, 
+    0xADD5, 0xADDB, 0xADE7, 0xADF3, 0xADF5, 0xADF9, 0xADFF, 0xAE05, 
+    0xAE13, 0xAE23, 0xAE2B, 0xAE49, 0xAE4D, 0xAE4F, 0xAE59, 0xAE61, 
+    0xAE67, 0xAE6B, 0xAE71, 0xAE8B, 0xAE8F, 0xAE9B, 0xAE9D, 0xAEA7, 
+    0xAEB9, 0xAEC5, 0xAED1, 0xAEE3, 0xAEE5, 0xAEE9, 0xAEF5, 0xAEFD, 
+    0xAF09, 0xAF13, 0xAF27, 0xAF2B, 0xAF33, 0xAF43, 0xAF4F, 0xAF57, 
+    0xAF5D, 0xAF6D, 0xAF75, 0xAF7F, 0xAF8B, 0xAF99, 0xAF9F, 0xAFA3, 
+    0xAFAB, 0xAFB7, 0xAFBB, 0xAFCF, 0xAFD5, 0xAFFD, 0xB005, 0xB015, 
+    0xB01B, 0xB03F, 0xB041, 0xB047, 0xB04B, 0xB051, 0xB053, 0xB069, 
+    0xB07B, 0xB07D, 0xB087, 0xB08D, 0xB0B1, 0xB0BF, 0xB0CB, 0xB0CF, 
+    0xB0E1, 0xB0E9, 0xB0ED, 0xB0FB, 0xB105, 0xB107, 0xB111, 0xB119, 
+    0xB11D, 0xB11F, 0xB131, 0xB141, 0xB14D, 0xB15B, 0xB165, 0xB173, 
+    0xB179, 0xB17F, 0xB1A9, 0xB1B3, 0xB1B9, 0xB1BF, 0xB1D3, 0xB1DD, 
+    0xB1E5, 0xB1F1, 0xB1F5, 0xB201, 0xB213, 0xB215, 0xB21F, 0xB22D, 
+    0xB23F, 0xB249, 0xB25B, 0xB263, 0xB269, 0xB26D, 0xB27B, 0xB281, 
+    0xB28B, 0xB2A9, 0xB2B7, 0xB2BD, 0xB2C3, 0xB2C7, 0xB2D3, 0xB2F9, 
+    0xB2FD, 0xB2FF, 0xB303, 0xB309, 0xB311, 0xB31D, 0xB327, 0xB32D, 
+    0xB33F, 0xB345, 0xB377, 0xB37D, 0xB381, 0xB387, 0xB393, 0xB39B, 
+    0xB3A5, 0xB3C5, 0xB3CB, 0xB3E1, 0xB3E3, 0xB3ED, 0xB3F9, 0xB40B, 
+    0xB40D, 0xB413, 0xB417, 0xB435, 0xB43D, 0xB443, 0xB449, 0xB45B, 
+    0xB465, 0xB467, 0xB46B, 0xB477, 0xB48B, 0xB495, 0xB49D, 0xB4B5, 
+    0xB4BF, 0xB4C1, 0xB4C7, 0xB4DD, 0xB4E3, 0xB4E5, 0xB4F7, 0xB501, 
+    0xB50D, 0xB50F, 0xB52D, 0xB53F, 0xB54B, 0xB567, 0xB569, 0xB56F, 
+    0xB573, 0xB579, 0xB587, 0xB58D, 0xB599, 0xB5A3, 0xB5AB, 0xB5AF, 
+    0xB5BB, 0xB5D5, 0xB5DF, 0xB5E7, 0xB5ED, 0xB5FD, 0xB5FF, 0xB609, 
+    0xB61B, 0xB629, 0xB62F, 0xB633, 0xB639, 0xB647, 0xB657, 0xB659, 
+    0xB65F, 0xB663, 0xB66F, 0xB683, 0xB687, 0xB69B, 0xB69F, 0xB6A5, 
+    0xB6B1, 0xB6B3, 0xB6D7, 0xB6DB, 0xB6E1, 0xB6E3, 0xB6ED, 0xB6EF, 
+    0xB705, 0xB70D, 0xB713, 0xB71D, 0xB729, 0xB735, 0xB747, 0xB755, 
+    0xB76D, 0xB791, 0xB795, 0xB7A9, 0xB7C1, 0xB7CB, 0xB7D1, 0xB7D3, 
+    0xB7EF, 0xB7F5, 0xB807, 0xB80F, 0xB813, 0xB819, 0xB821, 0xB827, 
+    0xB82B, 0xB82D, 0xB839, 0xB855, 0xB867, 0xB875, 0xB885, 0xB893, 
+    0xB8A5, 0xB8AF, 0xB8B7, 0xB8BD, 0xB8C1, 0xB8C7, 0xB8CD, 0xB8D5, 
+    0xB8EB, 0xB8F7, 0xB8F9, 0xB903, 0xB915, 0xB91B, 0xB91D, 0xB92F, 
+    0xB939, 0xB93B, 0xB947, 0xB951, 0xB963, 0xB983, 0xB989, 0xB98D, 
+    0xB993, 0xB999, 0xB9A1, 0xB9A7, 0xB9AD, 0xB9B7, 0xB9CB, 0xB9D1, 
+    0xB9DD, 0xB9E7, 0xB9EF, 0xB9F9, 0xBA07, 0xBA0D, 0xBA17, 0xBA25, 
+    0xBA29, 0xBA2B, 0xBA41, 0xBA53, 0xBA55, 0xBA5F, 0xBA61, 0xBA65, 
+    0xBA79, 0xBA7D, 0xBA7F, 0xBAA1, 0xBAA3, 0xBAAF, 0xBAB5, 0xBABF, 
+    0xBAC1, 0xBACB, 0xBADD, 0xBAE3, 0xBAF1, 0xBAFD, 0xBB09, 0xBB1F, 
+    0xBB27, 0xBB2D, 0xBB3D, 0xBB43, 0xBB4B, 0xBB4F, 0xBB5B, 0xBB61, 
+    0xBB69, 0xBB6D, 0xBB91, 0xBB97, 0xBB9D, 0xBBB1, 0xBBC9, 0xBBCF, 
+    0xBBDB, 0xBBED, 0xBBF7, 0xBBF9, 0xBC03, 0xBC1D, 0xBC23, 0xBC33, 
+    0xBC3B, 0xBC41, 0xBC45, 0xBC5D, 0xBC6F, 0xBC77, 0xBC83, 0xBC8F, 
+    0xBC99, 0xBCAB, 0xBCB7, 0xBCB9, 0xBCD1, 0xBCD5, 0xBCE1, 0xBCF3, 
+    0xBCFF, 0xBD0D, 0xBD17, 0xBD19, 0xBD1D, 0xBD35, 0xBD41, 0xBD4F, 
+    0xBD59, 0xBD5F, 0xBD61, 0xBD67, 0xBD6B, 0xBD71, 0xBD8B, 0xBD8F, 
+    0xBD95, 0xBD9B, 0xBD9D, 0xBDB3, 0xBDBB, 0xBDCD, 0xBDD1, 0xBDE3, 
+    0xBDEB, 0xBDEF, 0xBE07, 0xBE09, 0xBE15, 0xBE21, 0xBE25, 0xBE27, 
+    0xBE5B, 0xBE5D, 0xBE6F, 0xBE75, 0xBE79, 0xBE7F, 0xBE8B, 0xBE8D, 
+    0xBE93, 0xBE9F, 0xBEA9, 0xBEB1, 0xBEB5, 0xBEB7, 0xBECF, 0xBED9, 
+    0xBEDB, 0xBEE5, 0xBEE7, 0xBEF3, 0xBEF9, 0xBF0B, 0xBF33, 0xBF39, 
+    0xBF4D, 0xBF5D, 0xBF5F, 0xBF6B, 0xBF71, 0xBF7B, 0xBF87, 0xBF89, 
+    0xBF8D, 0xBF93, 0xBFA1, 0xBFAD, 0xBFB9, 0xBFCF, 0xBFD5, 0xBFDD, 
+    0xBFE1, 0xBFE3, 0xBFF3, 0xC005, 0xC011, 0xC013, 0xC019, 0xC029, 
+    0xC02F, 0xC031, 0xC037, 0xC03B, 0xC047, 0xC065, 0xC06D, 0xC07D, 
+    0xC07F, 0xC091, 0xC09B, 0xC0B3, 0xC0B5, 0xC0BB, 0xC0D3, 0xC0D7, 
+    0xC0D9, 0xC0EF, 0xC0F1, 0xC101, 0xC103, 0xC109, 0xC115, 0xC119, 
+    0xC12B, 0xC133, 0xC137, 0xC145, 0xC149, 0xC15B, 0xC173, 0xC179, 
+    0xC17B, 0xC181, 0xC18B, 0xC18D, 0xC197, 0xC1BD, 0xC1C3, 0xC1CD, 
+    0xC1DB, 0xC1E1, 0xC1E7, 0xC1FF, 0xC203, 0xC205, 0xC211, 0xC221, 
+    0xC22F, 0xC23F, 0xC24B, 0xC24D, 0xC253, 0xC25D, 0xC277, 0xC27B, 
+    0xC27D, 0xC289, 0xC28F, 0xC293, 0xC29F, 0xC2A7, 0xC2B3, 0xC2BD, 
+    0xC2CF, 0xC2D5, 0xC2E3, 0xC2FF, 0xC301, 0xC307, 0xC311, 0xC313, 
+    0xC317, 0xC325, 0xC347, 0xC349, 0xC34F, 0xC365, 0xC367, 0xC371, 
+    0xC37F, 0xC383, 0xC385, 0xC395, 0xC39D, 0xC3A7, 0xC3AD, 0xC3B5, 
+    0xC3BF, 0xC3C7, 0xC3CB, 0xC3D1, 0xC3D3, 0xC3E3, 0xC3E9, 0xC3EF, 
+    0xC401, 0xC41F, 0xC42D, 0xC433, 0xC437, 0xC455, 0xC457, 0xC461, 
+    0xC46F, 0xC473, 0xC487, 0xC491, 0xC499, 0xC49D, 0xC4A5, 0xC4B7, 
+    0xC4BB, 0xC4C9, 0xC4CF, 0xC4D3, 0xC4EB, 0xC4F1, 0xC4F7, 0xC509, 
+    0xC51B, 0xC51D, 0xC541, 0xC547, 0xC551, 0xC55F, 0xC56B, 0xC56F, 
+    0xC575, 0xC577, 0xC595, 0xC59B, 0xC59F, 0xC5A1, 0xC5A7, 0xC5C3, 
+    0xC5D7, 0xC5DB, 0xC5EF, 0xC5FB, 0xC613, 0xC623, 0xC635, 0xC641, 
+    0xC64F, 0xC655, 0xC659, 0xC665, 0xC685, 0xC691, 0xC697, 0xC6A1, 
+    0xC6A9, 0xC6B3, 0xC6B9, 0xC6CB, 0xC6CD, 0xC6DD, 0xC6EB, 0xC6F1, 
+    0xC707, 0xC70D, 0xC719, 0xC71B, 0xC72D, 0xC731, 0xC739, 0xC757, 
+    0xC763, 0xC767, 0xC773, 0xC775, 0xC77F, 0xC7A5, 0xC7BB, 0xC7BD, 
+    0xC7C1, 0xC7CF, 0xC7D5, 0xC7E1, 0xC7F9, 0xC7FD, 0xC7FF, 0xC803, 
+    0xC811, 0xC81D, 0xC827, 0xC829, 0xC839, 0xC83F, 0xC853, 0xC857, 
+    0xC86B, 0xC881, 0xC88D, 0xC88F, 0xC893, 0xC895, 0xC8A1, 0xC8B7, 
+    0xC8CF, 0xC8D5, 0xC8DB, 0xC8DD, 0xC8E3, 0xC8E7, 0xC8ED, 0xC8EF, 
+    0xC8F9, 0xC905, 0xC911, 0xC917, 0xC919, 0xC91F, 0xC92F, 0xC937, 
+    0xC93D, 0xC941, 0xC953, 0xC95F, 0xC96B, 0xC979, 0xC97D, 0xC989, 
+    0xC98F, 0xC997, 0xC99D, 0xC9AF, 0xC9B5, 0xC9BF, 0xC9CB, 0xC9D9, 
+    0xC9DF, 0xC9E3, 0xC9EB, 0xCA01, 0xCA07, 0xCA09, 0xCA25, 0xCA37, 
+    0xCA39, 0xCA4B, 0xCA55, 0xCA5B, 0xCA69, 0xCA73, 0xCA75, 0xCA7F, 
+    0xCA8D, 0xCA93, 0xCA9D, 0xCA9F, 0xCAB5, 0xCABB, 0xCAC3, 0xCAC9, 
+    0xCAD9, 0xCAE5, 0xCAED, 0xCB03, 0xCB05, 0xCB09, 0xCB17, 0xCB29, 
+    0xCB35, 0xCB3B, 0xCB53, 0xCB59, 0xCB63, 0xCB65, 0xCB71, 0xCB87, 
+    0xCB99, 0xCB9F, 0xCBB3, 0xCBB9, 0xCBC3, 0xCBD1, 0xCBD5, 0xCBD7, 
+    0xCBDD, 0xCBE9, 0xCBFF, 0xCC0D, 0xCC19, 0xCC1D, 0xCC23, 0xCC2B, 
+    0xCC41, 0xCC43, 0xCC4D, 0xCC59, 0xCC61, 0xCC89, 0xCC8B, 0xCC91, 
+    0xCC9B, 0xCCA3, 0xCCA7, 0xCCD1, 0xCCE5, 0xCCE9, 0xCD09, 0xCD15, 
+    0xCD1F, 0xCD25, 0xCD31, 0xCD3D, 0xCD3F, 0xCD49, 0xCD51, 0xCD57, 
+    0xCD5B, 0xCD63, 0xCD67, 0xCD81, 0xCD93, 0xCD97, 0xCD9F, 0xCDBB, 
+    0xCDC1, 0xCDD3, 0xCDD9, 0xCDE5, 0xCDE7, 0xCDF1, 0xCDF7, 0xCDFD, 
+    0xCE0B, 0xCE15, 0xCE21, 0xCE2F, 0xCE47, 0xCE4D, 0xCE51, 0xCE65, 
+    0xCE7B, 0xCE7D, 0xCE8F, 0xCE93, 0xCE99, 0xCEA5, 0xCEA7, 0xCEB7, 
+    0xCEC9, 0xCED7, 0xCEDD, 0xCEE3, 0xCEE7, 0xCEED, 0xCEF5, 0xCF07, 
+    0xCF0B, 0xCF19, 0xCF37, 0xCF3B, 0xCF4D, 0xCF55, 0xCF5F, 0xCF61, 
+    0xCF65, 0xCF6D, 0xCF79, 0xCF7D, 0xCF89, 0xCF9B, 0xCF9D, 0xCFA9, 
+    0xCFB3, 0xCFB5, 0xCFC5, 0xCFCD, 0xCFD1, 0xCFEF, 0xCFF1, 0xCFF7, 
+    0xD013, 0xD015, 0xD01F, 0xD021, 0xD033, 0xD03D, 0xD04B, 0xD04F, 
+    0xD069, 0xD06F, 0xD081, 0xD085, 0xD099, 0xD09F, 0xD0A3, 0xD0AB, 
+    0xD0BD, 0xD0C1, 0xD0CD, 0xD0E7, 0xD0FF, 0xD103, 0xD117, 0xD12D, 
+    0xD12F, 0xD141, 0xD157, 0xD159, 0xD15D, 0xD169, 0xD16B, 0xD171, 
+    0xD177, 0xD17D, 0xD181, 0xD187, 0xD195, 0xD199, 0xD1B1, 0xD1BD, 
+    0xD1C3, 0xD1D5, 0xD1D7, 0xD1E3, 0xD1FF, 0xD20D, 0xD211, 0xD217, 
+    0xD21F, 0xD235, 0xD23B, 0xD247, 0xD259, 0xD261, 0xD265, 0xD279, 
+    0xD27F, 0xD283, 0xD289, 0xD28B, 0xD29D, 0xD2A3, 0xD2A7, 0xD2B3, 
+    0xD2BF, 0xD2C7, 0xD2E3, 0xD2E9, 0xD2F1, 0xD2FB, 0xD2FD, 0xD315, 
+    0xD321, 0xD32B, 0xD343, 0xD34B, 0xD355, 0xD369, 0xD375, 0xD37B, 
+    0xD387, 0xD393, 0xD397, 0xD3A5, 0xD3B1, 0xD3C9, 0xD3EB, 0xD3FD, 
+    0xD405, 0xD40F, 0xD415, 0xD427, 0xD42F, 0xD433, 0xD43B, 0xD44B, 
+    0xD459, 0xD45F, 0xD463, 0xD469, 0xD481, 0xD483, 0xD489, 0xD48D, 
+    0xD493, 0xD495, 0xD4A5, 0xD4AB, 0xD4B1, 0xD4C5, 0xD4DD, 0xD4E1, 
+    0xD4E3, 0xD4E7, 0xD4F5, 0xD4F9, 0xD50B, 0xD50D, 0xD513, 0xD51F, 
+    0xD523, 0xD531, 0xD535, 0xD537, 0xD549, 0xD559, 0xD55F, 0xD565, 
+    0xD567, 0xD577, 0xD58B, 0xD591, 0xD597, 0xD5B5, 0xD5B9, 0xD5C1, 
+    0xD5C7, 0xD5DF, 0xD5EF, 0xD5F5, 0xD5FB, 0xD603, 0xD60F, 0xD62D, 
+    0xD631, 0xD643, 0xD655, 0xD65D, 0xD661, 0xD67B, 0xD685, 0xD687, 
+    0xD69D, 0xD6A5, 0xD6AF, 0xD6BD, 0xD6C3, 0xD6C7, 0xD6D9, 0xD6E1, 
+    0xD6ED, 0xD709, 0xD70B, 0xD711, 0xD715, 0xD721, 0xD727, 0xD73F, 
+    0xD745, 0xD74D, 0xD757, 0xD76B, 0xD77B, 0xD783, 0xD7A1, 0xD7A7, 
+    0xD7AD, 0xD7B1, 0xD7B3, 0xD7BD, 0xD7CB, 0xD7D1, 0xD7DB, 0xD7FB, 
+    0xD811, 0xD823, 0xD825, 0xD829, 0xD82B, 0xD82F, 0xD837, 0xD84D, 
+    0xD855, 0xD867, 0xD873, 0xD88F, 0xD891, 0xD8A1, 0xD8AD, 0xD8BF, 
+    0xD8CD, 0xD8D7, 0xD8E9, 0xD8F5, 0xD8FB, 0xD91B, 0xD925, 0xD933, 
+    0xD939, 0xD943, 0xD945, 0xD94F, 0xD951, 0xD957, 0xD96D, 0xD96F, 
+    0xD973, 0xD979, 0xD981, 0xD98B, 0xD991, 0xD99F, 0xD9A5, 0xD9A9, 
+    0xD9B5, 0xD9D3, 0xD9EB, 0xD9F1, 0xD9F7, 0xD9FF, 0xDA05, 0xDA09, 
+    0xDA0B, 0xDA0F, 0xDA15, 0xDA1D, 0xDA23, 0xDA29, 0xDA3F, 0xDA51, 
+    0xDA59, 0xDA5D, 0xDA5F, 0xDA71, 0xDA77, 0xDA7B, 0xDA7D, 0xDA8D, 
+    0xDA9F, 0xDAB3, 0xDABD, 0xDAC3, 0xDAC9, 0xDAE7, 0xDAE9, 0xDAF5, 
+    0xDB11, 0xDB17, 0xDB1D, 0xDB23, 0xDB25, 0xDB31, 0xDB3B, 0xDB43, 
+    0xDB55, 0xDB67, 0xDB6B, 0xDB73, 0xDB85, 0xDB8F, 0xDB91, 0xDBAD, 
+    0xDBAF, 0xDBB9, 0xDBC7, 0xDBCB, 0xDBCD, 0xDBEB, 0xDBF7, 0xDC0D, 
+    0xDC27, 0xDC31, 0xDC39, 0xDC3F, 0xDC49, 0xDC51, 0xDC61, 0xDC6F, 
+    0xDC75, 0xDC7B, 0xDC85, 0xDC93, 0xDC99, 0xDC9D, 0xDC9F, 0xDCA9, 
+    0xDCB5, 0xDCB7, 0xDCBD, 0xDCC7, 0xDCCF, 0xDCD3, 0xDCD5, 0xDCDF, 
+    0xDCF9, 0xDD0F, 0xDD15, 0xDD17, 0xDD23, 0xDD35, 0xDD39, 0xDD53, 
+    0xDD57, 0xDD5F, 0xDD69, 0xDD6F, 0xDD7D, 0xDD87, 0xDD89, 0xDD9B, 
+    0xDDA1, 0xDDAB, 0xDDBF, 0xDDC5, 0xDDCB, 0xDDCF, 0xDDE7, 0xDDE9, 
+    0xDDED, 0xDDF5, 0xDDFB, 0xDE0B, 0xDE19, 0xDE29, 0xDE3B, 0xDE3D, 
+    0xDE41, 0xDE4D, 0xDE4F, 0xDE59, 0xDE5B, 0xDE61, 0xDE6D, 0xDE77, 
+    0xDE7D, 0xDE83, 0xDE97, 0xDE9D, 0xDEA1, 0xDEA7, 0xDECD, 0xDED1, 
+    0xDED7, 0xDEE3, 0xDEF1, 0xDEF5, 0xDF01, 0xDF09, 0xDF13, 0xDF1F, 
+    0xDF2B, 0xDF33, 0xDF37, 0xDF3D, 0xDF4B, 0xDF55, 0xDF5B, 0xDF67, 
+    0xDF69, 0xDF73, 0xDF85, 0xDF87, 0xDF99, 0xDFA3, 0xDFAB, 0xDFB5, 
+    0xDFB7, 0xDFC3, 0xDFC7, 0xDFD5, 0xDFF1, 0xDFF3, 0xE003, 0xE005, 
+    0xE017, 0xE01D, 0xE027, 0xE02D, 0xE035, 0xE045, 0xE053, 0xE071, 
+    0xE07B, 0xE08F, 0xE095, 0xE09F, 0xE0B7, 0xE0B9, 0xE0D5, 0xE0D7, 
+    0xE0E3, 0xE0F3, 0xE0F9, 0xE101, 0xE125, 0xE129, 0xE131, 0xE135, 
+    0xE143, 0xE14F, 0xE159, 0xE161, 0xE16D, 0xE171, 0xE177, 0xE17F, 
+    0xE183, 0xE189, 0xE197, 0xE1AD, 0xE1B5, 0xE1BB, 0xE1BF, 0xE1C1, 
+    0xE1CB, 0xE1D1, 0xE1E5, 0xE1EF, 0xE1F7, 0xE1FD, 0xE203, 0xE219, 
+    0xE22B, 0xE22D, 0xE23D, 0xE243, 0xE257, 0xE25B, 0xE275, 0xE279, 
+    0xE287, 0xE29D, 0xE2AB, 0xE2AF, 0xE2BB, 0xE2C1, 0xE2C9, 0xE2CD, 
+    0xE2D3, 0xE2D9, 0xE2F3, 0xE2FD, 0xE2FF, 0xE311, 0xE323, 0xE327, 
+    0xE329, 0xE339, 0xE33B, 0xE34D, 0xE351, 0xE357, 0xE35F, 0xE363, 
+    0xE369, 0xE375, 0xE377, 0xE37D, 0xE383, 0xE39F, 0xE3C5, 0xE3C9, 
+    0xE3D1, 0xE3E1, 0xE3FB, 0xE3FF, 0xE401, 0xE40B, 0xE417, 0xE419, 
+    0xE423, 0xE42B, 0xE431, 0xE43B, 0xE447, 0xE449, 0xE453, 0xE455, 
+    0xE46D, 0xE471, 0xE48F, 0xE4A9, 0xE4AF, 0xE4B5, 0xE4C7, 0xE4CD, 
+    0xE4D3, 0xE4E9, 0xE4EB, 0xE4F5, 0xE507, 0xE521, 0xE525, 0xE537, 
+    0xE53F, 0xE545, 0xE54B, 0xE557, 0xE567, 0xE56D, 0xE575, 0xE585, 
+    0xE58B, 0xE593, 0xE5A3, 0xE5A5, 0xE5CF, 0xE609, 0xE611, 0xE615, 
+    0xE61B, 0xE61D, 0xE621, 0xE629, 0xE639, 0xE63F, 0xE653, 0xE657, 
+    0xE663, 0xE66F, 0xE675, 0xE681, 0xE683, 0xE68D, 0xE68F, 0xE695, 
+    0xE6AB, 0xE6AD, 0xE6B7, 0xE6BD, 0xE6C5, 0xE6CB, 0xE6D5, 0xE6E3, 
+    0xE6E9, 0xE6EF, 0xE6F3, 0xE705, 0xE70D, 0xE717, 0xE71F, 0xE72F, 
+    0xE73D, 0xE747, 0xE749, 0xE753, 0xE755, 0xE761, 0xE767, 0xE76B, 
+    0xE77F, 0xE789, 0xE791, 0xE7C5, 0xE7CD, 0xE7D7, 0xE7DD, 0xE7DF, 
+    0xE7E9, 0xE7F1, 0xE7FB, 0xE801, 0xE807, 0xE80F, 0xE819, 0xE81B, 
+    0xE831, 0xE833, 0xE837, 0xE83D, 0xE84B, 0xE84F, 0xE851, 0xE869, 
+    0xE875, 0xE879, 0xE893, 0xE8A5, 0xE8A9, 0xE8AF, 0xE8BD, 0xE8DB, 
+    0xE8E1, 0xE8E5, 0xE8EB, 0xE8ED, 0xE903, 0xE90B, 0xE90F, 0xE915, 
+    0xE917, 0xE92D, 0xE933, 0xE93B, 0xE94B, 0xE951, 0xE95F, 0xE963, 
+    0xE969, 0xE97B, 0xE983, 0xE98F, 0xE995, 0xE9A1, 0xE9B9, 0xE9D7, 
+    0xE9E7, 0xE9EF, 0xEA11, 0xEA19, 0xEA2F, 0xEA35, 0xEA43, 0xEA4D, 
+    0xEA5F, 0xEA6D, 0xEA71, 0xEA7D, 0xEA85, 0xEA89, 0xEAAD, 0xEAB3, 
+    0xEAB9, 0xEABB, 0xEAC5, 0xEAC7, 0xEACB, 0xEADF, 0xEAE5, 0xEAEB, 
+    0xEAF5, 0xEB01, 0xEB07, 0xEB09, 0xEB31, 0xEB39, 0xEB3F, 0xEB5B, 
+    0xEB61, 0xEB63, 0xEB6F, 0xEB81, 0xEB85, 0xEB9D, 0xEBAB, 0xEBB1, 
+    0xEBB7, 0xEBC1, 0xEBD5, 0xEBDF, 0xEBED, 0xEBFD, 0xEC0B, 0xEC1B, 
+    0xEC21, 0xEC29, 0xEC4D, 0xEC51, 0xEC5D, 0xEC69, 0xEC6F, 0xEC7B, 
+    0xECAD, 0xECB9, 0xECBF, 0xECC3, 0xECC9, 0xECCF, 0xECD7, 0xECDD, 
+    0xECE7, 0xECE9, 0xECF3, 0xECF5, 0xED07, 0xED11, 0xED1F, 0xED2F, 
+    0xED37, 0xED3D, 0xED41, 0xED55, 0xED59, 0xED5B, 0xED65, 0xED6B, 
+    0xED79, 0xED8B, 0xED95, 0xEDBB, 0xEDC5, 0xEDD7, 0xEDD9, 0xEDE3, 
+    0xEDE5, 0xEDF1, 0xEDF5, 0xEDF7, 0xEDFB, 0xEE09, 0xEE0F, 0xEE19, 
+    0xEE21, 0xEE49, 0xEE4F, 0xEE63, 0xEE67, 0xEE73, 0xEE7B, 0xEE81, 
+    0xEEA3, 0xEEAB, 0xEEC1, 0xEEC9, 0xEED5, 0xEEDF, 0xEEE1, 0xEEF1, 
+    0xEF1B, 0xEF27, 0xEF2F, 0xEF45, 0xEF4D, 0xEF63, 0xEF6B, 0xEF71, 
+    0xEF93, 0xEF95, 0xEF9B, 0xEF9F, 0xEFAD, 0xEFB3, 0xEFC3, 0xEFC5, 
+    0xEFDB, 0xEFE1, 0xEFE9, 0xF001, 0xF017, 0xF01D, 0xF01F, 0xF02B, 
+    0xF02F, 0xF035, 0xF043, 0xF047, 0xF04F, 0xF067, 0xF06B, 0xF071, 
+    0xF077, 0xF079, 0xF08F, 0xF0A3, 0xF0A9, 0xF0AD, 0xF0BB, 0xF0BF, 
+    0xF0C5, 0xF0CB, 0xF0D3, 0xF0D9, 0xF0E3, 0xF0E9, 0xF0F1, 0xF0F7, 
+    0xF107, 0xF115, 0xF11B, 0xF121, 0xF137, 0xF13D, 0xF155, 0xF175, 
+    0xF17B, 0xF18D, 0xF193, 0xF1A5, 0xF1AF, 0xF1B7, 0xF1D5, 0xF1E7, 
+    0xF1ED, 0xF1FD, 0xF209, 0xF20F, 0xF21B, 0xF21D, 0xF223, 0xF227, 
+    0xF233, 0xF23B, 0xF241, 0xF257, 0xF25F, 0xF265, 0xF269, 0xF277, 
+    0xF281, 0xF293, 0xF2A7, 0xF2B1, 0xF2B3, 0xF2B9, 0xF2BD, 0xF2BF, 
+    0xF2DB, 0xF2ED, 0xF2EF, 0xF2F9, 0xF2FF, 0xF305, 0xF30B, 0xF319, 
+    0xF341, 0xF359, 0xF35B, 0xF35F, 0xF367, 0xF373, 0xF377, 0xF38B, 
+    0xF38F, 0xF3AF, 0xF3C1, 0xF3D1, 0xF3D7, 0xF3FB, 0xF403, 0xF409, 
+    0xF40D, 0xF413, 0xF421, 0xF425, 0xF42B, 0xF445, 0xF44B, 0xF455, 
+    0xF463, 0xF475, 0xF47F, 0xF485, 0xF48B, 0xF499, 0xF4A3, 0xF4A9, 
+    0xF4AF, 0xF4BD, 0xF4C3, 0xF4DB, 0xF4DF, 0xF4ED, 0xF503, 0xF50B, 
+    0xF517, 0xF521, 0xF529, 0xF535, 0xF547, 0xF551, 0xF563, 0xF56B, 
+    0xF583, 0xF58D, 0xF595, 0xF599, 0xF5B1, 0xF5B7, 0xF5C9, 0xF5CF, 
+    0xF5D1, 0xF5DB, 0xF5F9, 0xF5FB, 0xF605, 0xF607, 0xF60B, 0xF60D, 
+    0xF635, 0xF637, 0xF653, 0xF65B, 0xF661, 0xF667, 0xF679, 0xF67F, 
+    0xF689, 0xF697, 0xF69B, 0xF6AD, 0xF6CB, 0xF6DD, 0xF6DF, 0xF6EB, 
+    0xF709, 0xF70F, 0xF72D, 0xF731, 0xF743, 0xF74F, 0xF751, 0xF755, 
+    0xF763, 0xF769, 0xF773, 0xF779, 0xF781, 0xF787, 0xF791, 0xF79D, 
+    0xF79F, 0xF7A5, 0xF7B1, 0xF7BB, 0xF7BD, 0xF7CF, 0xF7D3, 0xF7E7, 
+    0xF7EB, 0xF7F1, 0xF7FF, 0xF805, 0xF80B, 0xF821, 0xF827, 0xF82D, 
+    0xF835, 0xF847, 0xF859, 0xF863, 0xF865, 0xF86F, 0xF871, 0xF877, 
+    0xF87B, 0xF881, 0xF88D, 0xF89F, 0xF8A1, 0xF8AB, 0xF8B3, 0xF8B7, 
+    0xF8C9, 0xF8CB, 0xF8D1, 0xF8D7, 0xF8DD, 0xF8E7, 0xF8EF, 0xF8F9, 
+    0xF8FF, 0xF911, 0xF91D, 0xF925, 0xF931, 0xF937, 0xF93B, 0xF941, 
+    0xF94F, 0xF95F, 0xF961, 0xF96D, 0xF971, 0xF977, 0xF99D, 0xF9A3, 
+    0xF9A9, 0xF9B9, 0xF9CD, 0xF9E9, 0xF9FD, 0xFA07, 0xFA0D, 0xFA13, 
+    0xFA21, 0xFA25, 0xFA3F, 0xFA43, 0xFA51, 0xFA5B, 0xFA6D, 0xFA7B, 
+    0xFA97, 0xFA99, 0xFA9D, 0xFAAB, 0xFABB, 0xFABD, 0xFAD9, 0xFADF, 
+    0xFAE7, 0xFAED, 0xFB0F, 0xFB17, 0xFB1B, 0xFB2D, 0xFB2F, 0xFB3F, 
+    0xFB47, 0xFB4D, 0xFB75, 0xFB7D, 0xFB8F, 0xFB93, 0xFBB1, 0xFBB7, 
+    0xFBC3, 0xFBC5, 0xFBE3, 0xFBE9, 0xFBF3, 0xFC01, 0xFC29, 0xFC37, 
+    0xFC41, 0xFC43, 0xFC4F, 0xFC59, 0xFC61, 0xFC65, 0xFC6D, 0xFC73,
+    0xFC79, 0xFC95, 0xFC97, 0xFC9B, 0xFCA7, 0xFCB5, 0xFCC5, 0xFCCD, 
+    0xFCEB, 0xFCFB, 0xFD0D, 0xFD0F, 0xFD19, 0xFD2B, 0xFD31, 0xFD51, 
+    0xFD55, 0xFD67, 0xFD6D, 0xFD6F, 0xFD7B, 0xFD85, 0xFD97, 0xFD99, 
+    0xFD9F, 0xFDA9, 0xFDB7, 0xFDC9, 0xFDE5, 0xFDEB, 0xFDF3, 0xFE03, 
+    0xFE05, 0xFE09, 0xFE1D, 0xFE27, 0xFE2F, 0xFE41, 0xFE4B, 0xFE4D, 
+    0xFE57, 0xFE5F, 0xFE63, 0xFE69, 0xFE75, 0xFE7B, 0xFE8F, 0xFE93, 
+    0xFE95, 0xFE9B, 0xFE9F, 0xFEB3, 0xFEBD, 0xFED7, 0xFEE9, 0xFEF3, 
+    0xFEF5, 0xFF07, 0xFF0D, 0xFF1D, 0xFF2B, 0xFF2F, 0xFF49, 0xFF4D, 
+    0xFF5B, 0xFF65, 0xFF71, 0xFF7F, 0xFF85, 0xFF8B, 0xFF8F, 0xFF9D, 
+    0xFFA7, 0xFFA9, 0xFFC7, 0xFFD9, 0xFFEF, 0xFFF1 };
+#endif
+
+#define UPPER_LIMIT    (sizeof(prime_tab) / sizeof(prime_tab[0]))
+
+/* figures out if a number is prime (MR test) */
+#ifdef CLEAN_STACK
+static int _is_prime(mp_int *N, int *result)
+#else
+int is_prime(mp_int *N, int *result)
+#endif
+{
+    long x, s, j;
+    int res;
+    mp_int n1, a, y, r;
+    mp_digit d;
+    
+    _ARGCHK(N != NULL);
+    _ARGCHK(result != NULL);
+
+    /* default to answer of no */
+    *result = 0;
+
+    /* divisible by any of the first primes? */
+    for (x = 0; x < (long)UPPER_LIMIT; x++) {
+        /* is N equal to a small prime? */
+        if (mp_cmp_d(N, prime_tab[x]) == 0) { 
+            *result = 1; 
+             return CRYPT_OK; 
+        }
+
+        /* is N mod prime_tab[x] == 0, then its divisible by it */
+        if (mp_mod_d(N, prime_tab[x], &d) != MP_OKAY) {
+           return CRYPT_MEM;
+        }
+
+        if (d == 0) {
+           return CRYPT_OK;
+        }
+    }
+
+    /* init variables */
+    if (mp_init_multi(&r, &n1, &a, &y, NULL) != MP_OKAY) {
+       return CRYPT_MEM;
+    }
+
+    /* n1 = N - 1 */
+    if (mp_sub_d(N, 1, &n1) != MP_OKAY) { goto error; }
+
+    /* r = N - 1 */
+    if (mp_copy(&n1, &r) != MP_OKAY)    { goto error; }
+
+    /* find s such that N = (2^s)r */
+    s = 0;
+    while (mp_iseven(&r) && mp_cmp_d(&r, 0)) {
+        ++s;
+        if (mp_div_2(&r, &r) != MP_OKAY) {
+           goto error;
+        }
+    }
+
+    for (x = 0; x < 16; x++) {
+        /* choose a */
+        mp_set(&a, prime_tab[x]);
+
+        /* compute y = a^r mod n */
+        if (mp_exptmod(&a, &r, N, &y) != MP_OKAY)             { goto error; }
+
+        /* (y != 1) AND (y != N-1) */
+        if ((mp_cmp_d(&y, 1) != 0) && (mp_cmp(&y, &n1) != 0)) {
+            /* while j <= s-1 and y != n-1 */
+            for (j = 1; (j <= (s-1)) && (mp_cmp(&y, &n1) != 0); j++) {
+                /* y = y^2 mod N */
+                if (mp_sqrmod(&y, N, &y) != MP_OKAY)          { goto error; }
+
+                /* if y == 1 return false */
+                if (mp_cmp_d(&y, 1) == 0)                     { goto ok; }
+            }
+
+            /* if y != n-1 return false */
+            if (mp_cmp(&y, &n1) != 0)                         { goto ok; }
+        }
+    }
+    *result = 1;
+ok:
+    res = CRYPT_OK;
+    goto done;
+error:
+    res = CRYPT_MEM;
+done:
+    mp_clear_multi(&a, &y, &n1, &r, NULL);
+    return res;
+}
+
+#ifdef CLEAN_STACK
+int is_prime(mp_int *N, int *result)
+{
+   int x;
+   x = _is_prime(N, result);
+   burn_stack(sizeof(long) * 3 + sizeof(int) + sizeof(mp_int) * 4 + sizeof(mp_digit));
+   return x;
+}
+#endif
+
+int rand_prime(mp_int *N, long len, prng_state *prng, int wprng)
+{
+   unsigned char buf[260];
+   int errno, step, ormask, res;
+
+   _ARGCHK(N != NULL);
+
+   /* pass a negative size if you want a prime congruent to 3 mod 4 */
+   if (len < 0) {
+      step = 4;
+      ormask = 3;
+      len = -len;
+   } else {
+      step = 2;
+      ormask = 1;
+   }
+
+   /* allow sizes between 2 and 256 bytes for a prime size */
+   if (len < 2 || len > 256) { 
+      return CRYPT_INVALID_PRIME_SIZE;
+   }
+   
+   /* valid PRNG? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno; 
+   }
+
+   /* read the prng */
+   if (prng_descriptor[wprng].read(buf+2, len, prng) != (unsigned long)len) { 
+      return CRYPT_ERROR_READPRNG; 
+   }
+
+   /* set sign byte to zero */
+   buf[0] = 0;
+
+   /* Set the top byte to 0x01 which makes the number a len*8 bit number */
+   buf[1] = 0x01;
+
+   /* set the LSB to the desired settings 
+    * (1 for any prime, 3 for primes congruent to 3 mod 4) 
+    */
+   buf[len+1] |= ormask;
+
+   /* read the number in */
+   if (mp_read_raw(N, buf, 2+len) != MP_OKAY) { 
+      return CRYPT_MEM; 
+   }
+
+   /* add the step size to it while N is not prime */
+   do {
+      if (mp_add_d(N, (mp_digit)step, N) != MP_OKAY) {
+         return CRYPT_MEM; 
+      }
+      if ((errno = is_prime(N, &res)) != CRYPT_OK) {
+         return errno;
+      }
+   } while (res == 0);
+
+#ifdef CLEAN_STACK   
+   zeromem(buf, sizeof(buf));
+#endif
+
+   return CRYPT_OK;
+}
+      
+#endif
+
+
+

+ 321 - 0
rc2.c

@@ -0,0 +1,321 @@
+/**********************************************************************\
+* To commemorate the 1996 RSA Data Security Conference, the following  *
+* code is released into the public domain by its author.  Prost!       *
+*                                                                      *
+* This cipher uses 16-bit words and little-endian byte ordering.       *
+* I wonder which processor it was optimized for?                       *
+*                                                                      *
+* Thanks to CodeView, SoftIce, and D86 for helping bring this code to  *
+* the public.                                                          *
+\**********************************************************************/
+
+#include <mycrypt.h>
+
+#ifdef RC2
+
+const struct _cipher_descriptor rc2_desc = {
+   "rc2",
+   12, 8, 128, 8, 16,
+   &rc2_setup,
+   &rc2_ecb_encrypt,
+   &rc2_ecb_decrypt,
+   &rc2_test,
+   &rc2_keysize
+};
+
+
+/**********************************************************************\
+* Expand a variable-length user key (between 1 and 128 bytes) to a     *
+* 64-short working rc2 key, of at most "bits" effective key bits.      *
+* The effective key bits parameter looks like an export control hack.  *
+* For normal use, it should always be set to 1024.  For convenience,   *
+* zero is accepted as an alias for 1024.                               *
+\**********************************************************************/
+
+   /* 256-entry permutation table, probably derived somehow from pi */
+    static const unsigned char permute[256] = {
+        217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157,
+        198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162,
+         23,154, 89,245,135,179, 79, 19, 97, 69,109,141,  9,129,125, 50,
+        189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130,
+         84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220,
+         18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38,
+        111,191, 14,218, 70,105,  7, 87, 39,242, 29,155,188,148, 67,  3,
+        248, 17,199,246,144,239, 62,231,  6,195,213, 47,200,102, 30,215,
+          8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42,
+        150, 26,210,113, 90, 21, 73,116, 75,159,208, 94,  4, 24,164,236,
+        194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57,
+        153,124, 58,133, 35,184,180,122,252,  2, 54, 91, 37, 85,151, 49,
+         45, 93,250,152,227,138,146,174,  5,223, 41, 16,103,108,186,201,
+        211,  0,230,207,225,158,168, 44, 99, 22,  1, 63, 88,226,137,169,
+         13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46,
+        197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173
+    };
+
+int rc2_setup(const unsigned char *key, int keylen, int rounds, symmetric_key *skey)
+{
+   unsigned *xkey = skey->rc2.xkey;
+   unsigned char tmp[128];
+   unsigned T8, TM;
+   int i, bits;
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (keylen < 8 || keylen > 128) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (rounds && rounds != 16) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   for (i = 0; i < keylen; i++) {
+       tmp[i] = key[i];
+   }
+
+    /* Phase 1: Expand input key to 128 bytes */
+    if (keylen < 128) {
+        for (i = keylen; i < 128; i++) {
+            tmp[i] = permute[(tmp[i - 1] + tmp[i - keylen]) & 255];
+        }
+    }
+    
+    /* Phase 2 - reduce effective key size to "bits" */
+    bits = keylen*8;
+    T8   = (bits+7)>>3;
+    TM   = (255 >> (7 & -bits));
+    tmp[128 - T8] = permute[tmp[128 - T8] & TM];
+    for (i = 127 - T8; i >= 0; i--) {
+        tmp[i] = permute[tmp[i + 1] ^ tmp[i + T8]];
+    }
+
+    /* Phase 3 - copy to xkey in little-endian order */
+    i = 63;
+    do {
+        xkey[i] =  (unsigned)tmp[2*i] + ((unsigned)tmp[2*i+1] << 8);
+    } while (i--);
+
+#ifdef CLEAN_STACK
+    zeromem(tmp, sizeof(tmp));
+#endif
+    
+    return CRYPT_OK;
+}
+
+/**********************************************************************\
+* Encrypt an 8-byte block of plaintext using the given key.            *
+\**********************************************************************/
+#ifdef CLEAN_STACK
+static void _rc2_ecb_encrypt( const unsigned char *plain,
+                            unsigned char *cipher,
+                            symmetric_key *skey)
+#else
+void rc2_ecb_encrypt( const unsigned char *plain,
+                            unsigned char *cipher,
+                            symmetric_key *skey)
+#endif
+{
+    unsigned *xkey = skey->rc2.xkey;
+    unsigned x76, x54, x32, x10, i;
+
+    _ARGCHK(plain != NULL);
+    _ARGCHK(cipher != NULL);
+    _ARGCHK(skey != NULL);
+
+    x76 = ((unsigned)plain[7] << 8) + (unsigned)plain[6];
+    x54 = ((unsigned)plain[5] << 8) + (unsigned)plain[4];
+    x32 = ((unsigned)plain[3] << 8) + (unsigned)plain[2];
+    x10 = ((unsigned)plain[1] << 8) + (unsigned)plain[0];
+
+    for (i = 0; i < 16; i++) {
+        x10 = (x10 + (x32 & ~x76) + (x54 & x76) + xkey[4*i+0]) & 0xFFFF;
+        x10 = ((x10 << 1) | (x10 >> 15)) & 0xFFFF;
+
+        x32 = (x32 + (x54 & ~x10) + (x76 & x10) + xkey[4*i+1]) & 0xFFFF;
+        x32 = ((x32 << 2) | (x32 >> 14)) & 0xFFFF;
+
+        x54 = (x54 + (x76 & ~x32) + (x10 & x32) + xkey[4*i+2]) & 0xFFFF;
+        x54 = ((x54 << 3) | (x54 >> 13)) & 0xFFFF;
+
+        x76 = (x76 + (x10 & ~x54) + (x32 & x54) + xkey[4*i+3]) & 0xFFFF;
+        x76 = ((x76 << 5) | (x76 >> 11)) & 0xFFFF;
+
+        if (i == 4 || i == 10) {
+            x10 = (x10 + xkey[x76 & 63]) & 0xFFFF;
+            x32 = (x32 + xkey[x10 & 63]) & 0xFFFF;
+            x54 = (x54 + xkey[x32 & 63]) & 0xFFFF;
+            x76 = (x76 + xkey[x54 & 63]) & 0xFFFF;
+        }
+    }
+
+    cipher[0] = (unsigned char)x10;
+    cipher[1] = (unsigned char)(x10 >> 8);
+    cipher[2] = (unsigned char)x32;
+    cipher[3] = (unsigned char)(x32 >> 8);
+    cipher[4] = (unsigned char)x54;
+    cipher[5] = (unsigned char)(x54 >> 8);
+    cipher[6] = (unsigned char)x76;
+    cipher[7] = (unsigned char)(x76 >> 8);
+}
+
+#ifdef CLEAN_STACK
+void rc2_ecb_encrypt( const unsigned char *plain,
+                            unsigned char *cipher,
+                            symmetric_key *skey)
+{
+    _rc2_ecb_encrypt(plain, cipher, skey);
+    burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 5);
+}
+#endif
+
+/**********************************************************************\
+* Decrypt an 8-byte block of ciphertext using the given key.           *
+\**********************************************************************/
+
+#ifdef CLEAN_STACK
+static void _rc2_ecb_decrypt( const unsigned char *cipher,
+                            unsigned char *plain,
+                            symmetric_key *skey)
+#else
+void rc2_ecb_decrypt( const unsigned char *cipher,
+                            unsigned char *plain,
+                            symmetric_key *skey)
+#endif
+{
+    unsigned x76, x54, x32, x10;
+    unsigned *xkey = skey->rc2.xkey;
+    int i;
+
+    _ARGCHK(plain != NULL);
+    _ARGCHK(cipher != NULL);
+    _ARGCHK(skey != NULL);
+
+    x76 = ((unsigned)cipher[7] << 8) + (unsigned)cipher[6];
+    x54 = ((unsigned)cipher[5] << 8) + (unsigned)cipher[4];
+    x32 = ((unsigned)cipher[3] << 8) + (unsigned)cipher[2];
+    x10 = ((unsigned)cipher[1] << 8) + (unsigned)cipher[0];
+
+    for (i = 15; i >= 0; i--) {
+        if (i == 4 || i == 10) {
+            x76 = (x76 - xkey[x54 & 63]) & 0xFFFF;
+            x54 = (x54 - xkey[x32 & 63]) & 0xFFFF;
+            x32 = (x32 - xkey[x10 & 63]) & 0xFFFF;
+            x10 = (x10 - xkey[x76 & 63]) & 0xFFFF;
+        }
+
+        x76 = ((x76 << 11) | (x76 >> 5)) & 0xFFFF;
+        x76 = (x76 - ((x10 & ~x54) + (x32 & x54) + xkey[4*i+3])) & 0xFFFF;
+
+        x54 = ((x54 << 13) | (x54 >> 3)) & 0xFFFF;
+        x54 = (x54 - ((x76 & ~x32) + (x10 & x32) + xkey[4*i+2])) & 0xFFFF;
+
+        x32 = ((x32 << 14) | (x32 >> 2)) & 0xFFFF;
+        x32 = (x32 - ((x54 & ~x10) + (x76 & x10) + xkey[4*i+1])) & 0xFFFF;
+
+        x10 = ((x10 << 15) | (x10 >> 1)) & 0xFFFF;
+        x10 = (x10 - ((x32 & ~x76) + (x54 & x76) + xkey[4*i+0])) & 0xFFFF;
+    }
+
+    plain[0] = (unsigned char)x10;
+    plain[1] = (unsigned char)(x10 >> 8);
+    plain[2] = (unsigned char)x32;
+    plain[3] = (unsigned char)(x32 >> 8);
+    plain[4] = (unsigned char)x54;
+    plain[5] = (unsigned char)(x54 >> 8);
+    plain[6] = (unsigned char)x76;
+    plain[7] = (unsigned char)(x76 >> 8);
+}
+
+#ifdef CLEAN_STACK
+void rc2_ecb_decrypt( const unsigned char *cipher,
+                            unsigned char *plain,
+                            symmetric_key *skey)
+{
+    _rc2_ecb_decrypt(cipher, plain, skey);
+    burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 4 + sizeof(int));
+}
+#endif
+
+int rc2_test(void)
+{
+   static const struct {
+        int keylen;
+        unsigned char key[16], pt[8], ct[8];
+   } tests[] = {
+
+   { 8,
+     { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+     { 0x30, 0x64, 0x9e, 0xdf, 0x9b, 0xe7, 0xd2, 0xc2 }
+
+   },
+   { 16,
+     { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
+       0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x22, 0x69, 0x55, 0x2a, 0xb0, 0xf8, 0x5c, 0xa6 }
+   }
+  };
+    int x, failed, errno;
+    symmetric_key skey;
+    unsigned char buf[2][8];
+
+    failed = 0;
+    for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+        zeromem(buf, sizeof(buf));
+        if ((errno = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
+           return errno;
+        }
+        
+        rc2_ecb_encrypt(tests[x].pt, buf[0], &skey);
+        rc2_ecb_decrypt(buf[0], buf[1], &skey);
+        
+        if (memcmp(buf[0], tests[x].ct, 8)) {
+#if 0
+           int y;
+           printf("\nTest %d failed to encrypt\n", x);
+           for (y = 0; y < 8; y++) {
+               printf("%02x ", buf[0][y]);
+           }
+           printf("\n");
+#endif 
+           failed = 1;
+        }
+
+        if (memcmp(buf[1], tests[x].pt, 8)) {
+#if 0
+           int y;
+           printf("\nTest %d failed to decrypt\n", x);
+           for (y = 0; y < 8; y++) {
+               printf("%02x ", buf[1][y]);
+           }
+           printf("\n");
+#endif
+           failed = 1;
+        }
+    }
+    
+    if (failed == 1) {
+        return CRYPT_FAIL_TESTVECTOR;
+    } else {
+        return CRYPT_OK;
+    }
+}
+
+int rc2_keysize(int *keysize)
+{
+   _ARGCHK(keysize != NULL);
+   if (*keysize < 8) {
+       return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 128) {
+       *keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+

+ 97 - 0
rc4.c

@@ -0,0 +1,97 @@
+#include "mycrypt.h"
+
+#ifdef RC4
+
+const struct _prng_descriptor rc4_desc = 
+{
+   "rc4",
+    &rc4_start,
+    &rc4_add_entropy,
+    &rc4_ready,
+    &rc4_read
+};
+
+int rc4_start(prng_state *prng)
+{
+    _ARGCHK(prng != NULL);
+
+    /* set keysize to zero */
+    prng->rc4.x = 0;
+    
+    return CRYPT_OK;
+}
+
+int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
+{
+    _ARGCHK(buf != NULL);
+    _ARGCHK(prng != NULL);
+
+    if (prng->rc4.x + len > 256) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    while (len--) {
+       prng->rc4.buf[prng->rc4.x++] = *buf++;
+    }
+
+    return CRYPT_OK;
+    
+}
+
+int rc4_ready(prng_state *prng)
+{
+    unsigned char key[256], tmp;
+    int keylen, x, y;
+
+    _ARGCHK(prng != NULL);
+
+    /* extract the key */
+    memcpy(key, prng->rc4.buf, 256);
+    keylen = prng->rc4.x;
+
+    /* make RC4 perm and shuffle */
+    for (x = 0; x < 256; x++) {
+        prng->rc4.buf[x] = x;
+    }
+
+    for (x = y = 0; x < 256; x++) {
+        y = (y + prng->rc4.buf[x] + key[x % keylen]) & 255;
+        tmp = prng->rc4.buf[x]; prng->rc4.buf[x] = prng->rc4.buf[y]; prng->rc4.buf[y] = tmp;
+    }
+    prng->rc4.x = x;
+    prng->rc4.y = y;
+
+#ifdef CLEAN_STACK
+    zeromem(key, sizeof(key));
+#endif
+
+    return CRYPT_OK;
+}
+
+unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng)
+{
+   int x, y; 
+   unsigned char *s, tmp;
+   unsigned long n;
+
+   _ARGCHK(buf != NULL);
+   _ARGCHK(prng != NULL);
+
+   n = len;
+   x = prng->rc4.x;
+   y = prng->rc4.y;
+   s = prng->rc4.buf;
+   while (len--) {
+      x = (x + 1) & 255;
+      y = (y + s[x]) & 255;
+      tmp = s[x]; s[x] = s[y]; s[y] = tmp;
+      tmp = (s[x] + s[y]) & 255;
+      *buf++ ^= s[tmp];
+   }
+   prng->rc4.x = x;
+   prng->rc4.y = y;
+   return n;
+}
+
+#endif
+

+ 234 - 0
rc5.c

@@ -0,0 +1,234 @@
+#include "mycrypt.h"
+
+#ifdef RC5
+
+const struct _cipher_descriptor rc5_desc =
+{
+    "rc5",
+    2,
+    8, 128, 8, 12,
+    &rc5_setup,
+    &rc5_ecb_encrypt,
+    &rc5_ecb_decrypt,
+    &rc5_test,
+    &rc5_keysize
+};
+
+#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;
+
+    _ARGCHK(skey != NULL);
+    _ARGCHK(key != NULL);
+
+    /* test parameters */
+    if (num_rounds == 0) { 
+       num_rounds = rc5_desc.default_rounds;
+    }
+
+    if (num_rounds < 12 || num_rounds > 24) { 
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* key must be between 64 and 1024 bits */
+    if (keylen < 8 || keylen > 128) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    /* copy the key into the L array */
+    for (A = i = j = 0; i < (unsigned long)keylen; ) { 
+        A = (A << 8) | ((unsigned long)(key[i++] & 255));
+        if (!(i & 3)) {
+           L[j++] = BSWAP(A);
+           A = 0;
+        }
+    }
+
+    if (keylen & 3) { 
+       A <<= (8 * (4 - (keylen&3))); 
+       L[j++] = BSWAP(A);
+    }
+
+    /* setup the S array */
+    t = 2 * (num_rounds + 1);
+    S[0] = 0xB7E15163UL;
+    for (i = 1; i < t; i++) S[i] = S[i - 1] + 0x9E3779B9UL;
+
+    /* mix buffer */
+    s = 3 * MAX(t, 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;
+    }
+    
+    /* copy to key */
+    for (i = 0; i < t; i++) {
+        skey->rc5.K[i] = S[i];
+    }
+    skey->rc5.rounds = num_rounds;
+    return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _rc5_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(unsigned long) * 122 + sizeof(int));
+   return x;
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#else
+void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#endif
+{
+   unsigned long A, B;
+   int r;
+   _ARGCHK(key != NULL);
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+
+   LOAD32L(A, &pt[0]);
+   LOAD32L(B, &pt[4]);
+   A += key->rc5.K[0];
+   B += key->rc5.K[1];
+   for (r = 0; r < key->rc5.rounds; r++) {
+       A = ROL(A ^ B, B) + key->rc5.K[r+r+2];
+       B = ROL(B ^ A, A) + key->rc5.K[r+r+3];
+   }
+   STORE32L(A, &ct[0]);
+   STORE32L(B, &ct[4]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#else
+void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#endif
+{
+   unsigned long A, B;
+   int r;
+   _ARGCHK(key != NULL);
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+
+   LOAD32L(A, &ct[0]);
+   LOAD32L(B, &ct[4]);
+   for (r = key->rc5.rounds - 1; r >= 0; r--) {
+       B = ROR(B - key->rc5.K[r+r+3], A) ^ A;
+       A = ROR(A - key->rc5.K[r+r+2], B) ^ B;
+   }
+   A -= key->rc5.K[0];
+   B -= key->rc5.K[1];
+   STORE32L(A, &pt[0]);
+   STORE32L(B, &pt[4]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+int rc5_test(void)
+{
+   static const struct {
+       unsigned char key[16], pt[8], ct[8];
+   } tests[] = {
+   {
+       { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51,
+         0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 },
+       { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d },
+       { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 }
+   },
+   {
+       { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f,
+         0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 },
+       { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 },
+       { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }
+   },
+   {
+       { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f,
+         0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf },
+       { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 },
+       { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc }
+   }
+   };
+   unsigned char buf[2][8];
+   int x, failed, errno;
+   symmetric_key key;
+
+   for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((errno = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) {
+         return errno;
+      }
+
+      /* encrypt and decrypt */
+      rc5_ecb_encrypt(tests[x].pt, buf[0], &key);
+      rc5_ecb_decrypt(buf[0], buf[1], &key);
+
+      /* compare */
+      if (memcmp(buf[0], tests[x].ct, 8)) {
+#if 0
+         int y;
+         printf("\nEncrypt test %d failed\n", x);
+         for (y = 0; y < 8; y++) printf("%02x ", buf[0][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+
+      if (memcmp(buf[1], tests[x].pt, 8)) {
+#if 0
+         int y;
+         printf("\nDecrypt test %d failed\n", x);
+         for (y = 0; y < 8; y++) printf("%02x ", buf[1][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+   }
+
+   if (failed == 1) {
+      return CRYPT_FAIL_TESTVECTOR;
+   } else {
+      return CRYPT_OK;
+   }
+}
+
+int rc5_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+   if (*desired_keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*desired_keysize > 128) {
+      *desired_keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+

+ 253 - 0
rc6.c

@@ -0,0 +1,253 @@
+#include "mycrypt.h"
+
+#ifdef RC6
+
+const struct _cipher_descriptor rc6_desc =
+{
+    "rc6",
+    3,
+    8, 128, 16, 20,
+    &rc6_setup,
+    &rc6_ecb_encrypt,
+    &rc6_ecb_decrypt,
+    &rc6_test,
+    &rc6_keysize
+};
+
+#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;
+
+    _ARGCHK(key != NULL);
+    _ARGCHK(skey != NULL);
+
+    /* test parameters */
+    if (num_rounds != 0 && num_rounds != 20) { 
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* key must be between 64 and 1024 bits */
+    if (keylen < 8 || keylen > 128) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    /* copy the key into the L array */
+    for (A = i = j = 0; i < (unsigned long)keylen; ) { 
+        A = (A << 8) | ((unsigned long)(key[i++] & 255));
+        if (!(i & 3)) {
+           L[j++] = BSWAP(A);
+           A = 0;
+        }
+    }
+
+    /* handle odd sized keys */
+    if (keylen & 3) { 
+       A <<= (8 * (4 - (keylen&3))); 
+       L[j++] = BSWAP(A); 
+    }
+
+    /* 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;
+
+    /* mix buffer */
+    s = 3 * MAX(t, 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;
+    }
+    
+    /* copy to key */
+    for (i = 0; i < t; i++) { 
+        skey->rc6.K[i] = S[i];
+    }
+    return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _rc6_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(unsigned long) * 122);
+   return x;
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#else
+void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#endif
+{
+   unsigned long a,b,c,d,t,u;
+   int r;
+   
+   _ARGCHK(key != NULL);
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   LOAD32L(a,&pt[0]);LOAD32L(b,&pt[4]);LOAD32L(c,&pt[8]);LOAD32L(d,&pt[12]);
+   b += key->rc6.K[0];
+   d += key->rc6.K[1];
+   for (r = 0; r < 20; r++) {
+       t = (b * (b + b + 1)); t = ROL(t, 5);
+       u = (d * (d + d + 1)); u = ROL(u, 5);
+       a = ROL(a^t,u) + key->rc6.K[r+r+2];
+       c = ROL(c^u,t) + key->rc6.K[r+r+3];
+       t = a; a = b; b = c; c = d; d = t;
+   }
+   a += key->rc6.K[42];
+   c += key->rc6.K[43];
+   STORE32L(a,&ct[0]);STORE32L(b,&ct[4]);STORE32L(c,&ct[8]);STORE32L(d,&ct[12]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#else
+void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#endif
+{
+   unsigned long a,b,c,d,t,u;
+   int r;
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   
+   LOAD32L(a,&ct[0]);LOAD32L(b,&ct[4]);LOAD32L(c,&ct[8]);LOAD32L(d,&ct[12]);
+   a -= key->rc6.K[42];
+   c -= key->rc6.K[43];
+   for (r = 19; r >= 0; r--) {
+       t = d; d = c; c = b; b = a; a = t;
+       t = (b * (b + b + 1)); t = ROL(t, 5);
+       u = (d * (d + d + 1)); u = ROL(u, 5);
+       c = ROR(c - key->rc6.K[r+r+3], t) ^ u;
+       a = ROR(a - key->rc6.K[r+r+2], u) ^ t;
+   }
+   b -= key->rc6.K[0];
+   d -= key->rc6.K[1];
+   STORE32L(a,&pt[0]);STORE32L(b,&pt[4]);STORE32L(c,&pt[8]);STORE32L(d,&pt[12]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+int rc6_test(void)
+{
+   static const struct {
+       int keylen;
+       unsigned char key[32], pt[16], ct[16];
+   } tests[] = {
+   {
+       16,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0x52, 0x4e, 0x19, 0x2f, 0x47, 0x15, 0xc6, 0x23,
+         0x1f, 0x51, 0xf6, 0x36, 0x7e, 0xa4, 0x3f, 0x18 }
+   },
+   {
+       24,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0x68, 0x83, 0x29, 0xd0, 0x19, 0xe5, 0x05, 0x04,
+         0x1e, 0x52, 0xe9, 0x2a, 0xf9, 0x52, 0x91, 0xd4 }
+   },
+   {
+       32,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
+         0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0xc8, 0x24, 0x18, 0x16, 0xf0, 0xd7, 0xe4, 0x89,
+         0x20, 0xad, 0x16, 0xa1, 0x67, 0x4e, 0x5d, 0x48 }
+   }
+   };
+   unsigned char buf[2][16];
+   int x, failed, errno;
+   symmetric_key key;
+
+   for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((errno = rc6_setup(tests[x].key, tests[x].keylen, 0, &key)) != CRYPT_OK) {
+         return errno;
+      }
+
+      /* encrypt and decrypt */
+      rc6_ecb_encrypt(tests[x].pt, buf[0], &key);
+      rc6_ecb_decrypt(buf[0], buf[1], &key);
+
+      /* compare */
+      if (memcmp(buf[0], tests[x].ct, 16)) {
+#if 0
+         int y;
+         printf("\nEncrypt test %d failed\n", x);
+         for (y = 0; y < 16; y++) printf("%02x ", buf[0][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+
+      if (memcmp(buf[1], tests[x].pt, 16)) {
+#if 0
+         int y;
+         printf("\nDecrypt test %d failed\n", x);
+         for (y = 0; y < 16; y++) printf("%02x ", buf[1][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+   }
+
+   if (failed == 1) {
+      return CRYPT_FAIL_TESTVECTOR;
+   } else {
+      return CRYPT_OK;
+   }
+}
+
+int rc6_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+   if (*desired_keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*desired_keysize > 128) {
+      *desired_keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif /*RC6*/
+
+

+ 436 - 0
rsa.c

@@ -0,0 +1,436 @@
+#include "mycrypt.h"
+
+#ifdef MRSA
+
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key)
+{
+   mp_int p, q, tmp1, tmp2, tmp3;
+   int res, errno;   
+
+   _ARGCHK(key != NULL);
+
+   if ((size < (1024/8)) || (size > (4096/8))) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if ((e < 3) || (!(e & 1))) {
+      return CRYPT_INVALID_ARG;
+   }
+ 
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if (mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+
+   /* make primes p and q (optimization provided by Wayne Scott) */
+   if (mp_set_int(&tmp3, e) != MP_OKAY) { goto error; }            /* tmp3 = e */
+
+   /* make prime "p" */
+   do {
+       if (rand_prime(&p, size/2, prng, wprng) != CRYPT_OK) { res = CRYPT_ERROR; goto done; }
+       if (mp_sub_d(&p, 1, &tmp1) != MP_OKAY)              { goto error; }  /* tmp1 = p-1 */
+       if (mp_gcd(&tmp1, &tmp3, &tmp2) != MP_OKAY)         { goto error; }  /* tmp2 = gcd(p-1, e) */
+   } while (mp_cmp_d(&tmp2, 1) != 0);
+       
+   /* make prime "q" */
+   do {
+       if (rand_prime(&q, size/2, prng, wprng) != CRYPT_OK) { res = CRYPT_ERROR; goto done; }
+       if (mp_sub_d(&q, 1, &tmp1) != MP_OKAY)              { goto error; } /* tmp1 = q-1 */
+       if (mp_gcd(&tmp1, &tmp3, &tmp2) != MP_OKAY)         { goto error; } /* tmp2 = gcd(q-1, e) */
+   } while (mp_cmp_d(&tmp2, 1) != 0);
+
+   /* tmp1 = lcm(p-1, q-1) */
+   if (mp_sub_d(&p, 1, &tmp2) != MP_OKAY)                  { goto error; } /* tmp2 = p-1 */
+                                                                           /* tmp1 = q-1 (previous do/while loop) */
+   if (mp_lcm(&tmp1, &tmp2, &tmp1) != MP_OKAY)             { goto error; } /* tmp1 = lcm(p-1, q-1) */
+
+   /* make key */
+   if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, 
+                     &key->qP, &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) {
+      goto error;
+   }
+
+   mp_set_int(&key->e, e);                                          /* key->e =  e */
+   if (mp_invmod(&key->e, &tmp1, &key->d) != MP_OKAY) goto error2;  /* key->d = 1/e mod lcm(p-1,q-1) */
+   if (mp_mul(&p, &q, &key->N) != MP_OKAY) goto error2;             /* key->N = pq */
+
+/* optimize for CRT now */
+   /* find d mod q-1 and d mod p-1 */
+   if (mp_sub_d(&p, 1, &tmp1) != MP_OKAY)                  { goto error2; } /* tmp1 = q-1 */
+   if (mp_sub_d(&q, 1, &tmp2) != MP_OKAY)                  { goto error2; } /* tmp2 = p-1 */
+
+   if (mp_mod(&key->d, &tmp1, &key->dP) != MP_OKAY)        { goto error2; } /* dP = d mod p-1 */
+   if (mp_mod(&key->d, &tmp2, &key->dQ) != MP_OKAY)        { goto error2; } /* dQ = d mod q-1 */
+  
+   if (mp_invmod(&q, &p, &key->qP) != MP_OKAY)             { goto error2; } /* qP = 1/q mod p */
+   if (mp_mulmod(&key->qP, &q, &key->N, &key->qP))         { goto error2; } /* qP = q * (1/q mod p) mod N */
+
+   if (mp_invmod(&p, &q, &key->pQ) != MP_OKAY)             { goto error2; } /* pQ = 1/p mod q */    
+   if (mp_mulmod(&key->pQ, &p, &key->N, &key->pQ))         { goto error2; } /* pQ = p * (1/p mod q) mod N */
+
+   if (mp_copy(&p, &key->p) != MP_OKAY)                    { goto error2; }
+   if (mp_copy(&q, &key->q) != MP_OKAY)                    { goto error2; }
+ 
+   res = CRYPT_OK;
+   key->type = PK_PRIVATE_OPTIMIZED;
+   goto done;
+error2:
+   mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, 
+                  &key->qP, &key->pQ, &key->p, &key->q, NULL);
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL);
+   return res;
+}
+
+void rsa_free(rsa_key *key)
+{
+   _ARGCHK(key != NULL);
+   mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, 
+                  &key->qP, &key->pQ, &key->p, &key->q, NULL);
+}
+
+int rsa_exptmod(const unsigned char *in,  unsigned long inlen,
+                      unsigned char *out, unsigned long *outlen, int which,
+                      rsa_key *key)
+{
+   mp_int tmp, tmpa, tmpb;
+   unsigned long x;
+   int res;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   if (which == PK_PRIVATE && (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED)) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* init and copy into tmp */
+   if (mp_init_multi(&tmp, &tmpa, &tmpb, NULL) != MP_OKAY)                { goto error; }
+   if (mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen) != MP_OKAY) { goto error; }
+   
+   /* sanity check on the input */
+   if (mp_cmp(&key->N, &tmp) == MP_LT) {
+      res = CRYPT_PK_INVALID_SIZE;
+      goto done;
+   }
+
+   /* are we using the private exponent and is the key optimized? */
+   if (which == PK_PRIVATE && key->type == PK_PRIVATE_OPTIMIZED) {
+      /* tmpa = tmp^dP mod p */
+      if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY)    { goto error; }
+
+      /* tmpb = tmp^dQ mod q */
+      if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY)    { goto error; }
+
+      /* tmp = tmpa*qP + tmpb*pQ mod N */
+      if (mp_mul(&tmpa, &key->qP, &tmpa) != MP_OKAY)                { goto error; }
+      if (mp_mul(&tmpb, &key->pQ, &tmpb) != MP_OKAY)                { goto error; }
+      if (mp_addmod(&tmpa, &tmpb, &key->N, &tmp) != MP_OKAY)        { goto error; }
+   } else {
+      /* exptmod it */
+      if (mp_exptmod(&tmp, which==PK_PRIVATE?&key->d:&key->e, &key->N, &tmp) != MP_OKAY) { goto error; }
+   }
+
+   /* read it back */
+   x = mp_raw_size(&tmp)-1;
+   if (x > *outlen) {
+      res = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+   *outlen = x;
+
+   /* convert it */
+   mp_to_unsigned_bin(&tmp, out);
+
+   /* clean up and return */
+   res = CRYPT_OK;
+   goto done;
+error:
+   res = CRYPT_MEM;
+done:
+   mp_clear_multi(&tmp, &tmpa, &tmpb, NULL);
+   return res;
+}
+
+int rsa_signpad(const unsigned char *in,  unsigned long inlen, 
+                      unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   if (*outlen < (3 * inlen)) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* check inlen */
+   if ((inlen <= 0) || inlen > 512) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+   
+   for (y = x = 0; x < inlen; x++)
+       out[y++] = 0xFF;
+   for (x = 0; x < inlen; x++)
+       out[y++] = in[x];
+   for (x = 0; x < inlen; x++)
+       out[y++] = 0xFF;
+   *outlen = 3 * inlen;
+   return CRYPT_OK;
+}
+
+int rsa_pad(const unsigned char *in,  unsigned long inlen, 
+                  unsigned char *out, unsigned long *outlen, 
+                  int wprng, prng_state *prng)
+{
+   unsigned char buf[2048];
+   unsigned long x;
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   /* is output big enough? */
+   if (*outlen < (3 * inlen)) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* get random padding required */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno; 
+   }
+
+   /* check inlen */
+   if ((inlen <= 0) || inlen > 512) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+
+   if (prng_descriptor[wprng].read(buf, inlen*2-2, prng) != (inlen*2 - 2))  {
+       return CRYPT_ERROR_READPRNG;
+   }
+
+   /* pad it like a sandwitch (sp?) 
+    *
+    * Looks like 0xFF R1 M R2 0xFF
+    * 
+    * Where R1/R2 are random and exactly equal to the length of M minus one byte.  
+    */
+   for (x = 0; x < inlen-1; x++) { 
+       out[x+1] = buf[x]; 
+   }
+
+   for (x = 0; x < inlen; x++) {
+       out[x+inlen] = in[x];
+   }
+
+   for (x = 0; x < inlen-1; x++) {
+       out[x+inlen+inlen] = buf[x+inlen-1];
+   }
+
+   /* last and first bytes are 0xFF */
+   out[0] = 0xFF;
+   out[inlen+inlen+inlen-1] = 0xFF;
+
+   /* clear up and return */
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   *outlen = inlen*3;
+   return CRYPT_OK;
+}
+
+int rsa_signdepad(const unsigned char *in,  unsigned long inlen, 
+                    unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   if (*outlen < inlen/3) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* check padding bytes */
+   for (x = 0; x < inlen/3; x++) {
+       if (in[x] != 0xFF || in[x+(inlen/3)+(inlen/3)] != 0xFF) {
+          return CRYPT_INVALID_PACKET;
+       }
+   }
+   for (x = 0; x < inlen/3; x++) 
+       out[x] = in[x+(inlen/3)];
+   *outlen = inlen/3;
+   return CRYPT_OK;
+}
+
+int rsa_depad(const unsigned char *in,  unsigned long inlen, 
+                    unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+
+   if (*outlen < inlen/3) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   for (x = 0; x < inlen/3; x++) 
+       out[x] = in[x+(inlen/3)];
+   *outlen = inlen/3;
+   return CRYPT_OK;
+}
+
+#define OUTPUT_BIGNUM(num, buf2, y, z)         \
+{                                              \
+      z = mp_raw_size(num);                    \
+      STORE32L(z, buf2+y);                     \
+      y += 4;                                  \
+      mp_toraw(num, buf2+y);                   \
+      y += z;                                  \
+}
+
+
+#define INPUT_BIGNUM(num, in, x, y)                              \
+{                                                                \
+     /* load value */                                            \
+     LOAD32L(x, in+y);                                           \
+     y += 4;                                                     \
+                                                                 \
+     /* sanity check... */                                       \
+     if (x > 1024) {                                             \
+        goto error2;                                             \
+     }                                                           \
+                                                                 \
+     /* load it */                                               \
+     if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\
+        goto error2;                                             \
+     }                                                           \
+     y += x;                                                     \
+}
+
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
+{
+   unsigned char buf2[5120];
+   unsigned long y, z;
+
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* type valid? */
+   if (!(key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) && 
+        (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED)) { 
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   /* start at offset y=PACKET_SIZE */
+   y = PACKET_SIZE;
+
+   /* output key type */
+   buf2[y++] = type;
+
+   /* output modulus */
+   OUTPUT_BIGNUM(&key->N, buf2, y, z);
+  
+   /* output public key */
+   OUTPUT_BIGNUM(&key->e, buf2, y, z);
+
+   if (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED) {
+      OUTPUT_BIGNUM(&key->d, buf2, y, z);
+   }
+
+   if (type == PK_PRIVATE_OPTIMIZED) {
+      OUTPUT_BIGNUM(&key->dQ, buf2, y, z);
+      OUTPUT_BIGNUM(&key->dP, buf2, y, z);
+      OUTPUT_BIGNUM(&key->pQ, buf2, y, z);
+      OUTPUT_BIGNUM(&key->qP, buf2, y, z);
+      OUTPUT_BIGNUM(&key->p, buf2, y, z);
+      OUTPUT_BIGNUM(&key->q, buf2, y, z);
+   }
+
+   /* check size */
+   if (*outlen < y) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store packet header */
+   packet_store_header(buf2, PACKET_SECT_RSA, PACKET_SUB_KEY, y);
+
+   /* copy to the user buffer */
+   memcpy(out, buf2, y);
+   *outlen = y;
+
+   /* clear stack and return */
+#ifdef CLEAN_STACK
+   zeromem(buf2, sizeof(buf2));
+#endif
+   return CRYPT_OK;
+}
+
+int rsa_import(const unsigned char *in, rsa_key *key)
+{
+   unsigned long x, y;
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(key != NULL);
+
+   /* test packet header */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { 
+      return errno;
+   }
+
+   /* init key */
+   if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, 
+                     &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) {
+      return CRYPT_MEM;
+   }
+
+   /* get key type */
+   y = PACKET_SIZE;
+   key->type = in[y++];
+
+   /* load the modulus  */
+   INPUT_BIGNUM(&key->N, in, x, y);
+
+   /* load public exponent */
+   INPUT_BIGNUM(&key->e, in, x, y);
+
+   /* get private exponent */
+   if (key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) {
+      INPUT_BIGNUM(&key->d, in, x, y);
+   }
+
+   /* get CRT private data if required */
+   if (key->type == PK_PRIVATE_OPTIMIZED) {
+      INPUT_BIGNUM(&key->dQ, in, x, y);
+      INPUT_BIGNUM(&key->dP, in, x, y);
+      INPUT_BIGNUM(&key->pQ, in, x, y);
+      INPUT_BIGNUM(&key->qP, in, x, y);
+      INPUT_BIGNUM(&key->p, in, x, y);
+      INPUT_BIGNUM(&key->q, in, x, y);
+   }
+
+   return CRYPT_OK;
+error2:
+   mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, 
+                  &key->pQ, &key->qP, &key->p, &key->q, NULL);
+   return CRYPT_MEM;
+}
+
+#include "rsa_sys.c"
+
+#endif /* RSA */
+
+

+ 584 - 0
rsa_sys.c

@@ -0,0 +1,584 @@
+#ifdef PK_PACKET
+
+int rsa_encrypt(const unsigned char *in,  unsigned long len, 
+                      unsigned char *out, unsigned long *outlen,
+                      prng_state *prng, int wprng, int cipher, 
+                      rsa_key *key)
+{
+   unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096];
+   symmetric_CTR ctr;
+   unsigned long x, y, blklen, rsa_size;
+   int keylen, errno;;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* are the parameters valid? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* setup the CTR key */
+   keylen = 32;                                                             /* default to 256-bit keys */
+   if ((errno = cipher_descriptor[cipher].keysize(&keylen)) != CRYPT_OK) {
+      return errno;
+   }
+
+   blklen = cipher_descriptor[cipher].block_length;
+   if (prng_descriptor[wprng].read(sym_key, keylen, prng) != (unsigned long)keylen) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   if (prng_descriptor[wprng].read(sym_IV, blklen, prng) != blklen) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   /* setup CTR mode */
+   if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* rsa_pad the symmetric key */
+   y = sizeof(rsa_in); 
+   if ((errno = rsa_pad(sym_key, keylen, rsa_in, &y, wprng, prng)) != CRYPT_OK) {
+      return errno;
+   }
+   
+   /* rsa encrypt it */
+   rsa_size = sizeof(rsa_out);
+   if ((errno = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check size */
+   if (*outlen < (PACKET_SIZE+9+rsa_size+blklen+len)) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* now lets make the header */
+   y = PACKET_SIZE;
+   out[y++] = cipher_descriptor[cipher].ID;
+
+   /* store the size of the RSA value */
+   STORE32L(rsa_size, (out+y));
+   y += 4;
+
+   /* store the rsa value */
+   for (x = 0; x < rsa_size; x++, y++) {
+       out[y] = rsa_out[x];
+   }
+
+   /* store the IV used */
+   for (x = 0; x < blklen; x++, y++) {
+       out[y] = sym_IV[x];
+   }
+       
+   /* store the length */
+   STORE32L(len, (out+y));
+   y += 4;
+
+   /* encrypt the message */
+   if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) {
+      return errno;
+   }
+
+   y += len;
+
+   /* store the header */
+   packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED, y);
+   
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(sym_key, sizeof(sym_key));
+   zeromem(sym_IV, sizeof(sym_IV));
+   zeromem(&ctr, sizeof(ctr));
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+
+   *outlen = y;
+   return CRYPT_OK;
+}
+
+int rsa_decrypt(const unsigned char *in,  unsigned long len, 
+                      unsigned char *out, unsigned long *outlen, 
+                      rsa_key *key)
+{
+   unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096];
+   symmetric_CTR ctr;
+   unsigned long x, y, z, keylen, blklen, rsa_size;
+   int cipher, errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* check the header */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* grab cipher name */
+   y = PACKET_SIZE;
+   cipher = find_cipher_id(in[y++]);
+   if (cipher == -1) {
+      return CRYPT_INVALID_CIPHER;
+   }
+   keylen = MIN(cipher_descriptor[cipher].max_key_length, 32);
+   blklen = cipher_descriptor[cipher].block_length;
+
+   /* grab length of the rsa key */
+   LOAD32L(rsa_size, (in+y))
+   y += 4;
+
+   /* read it in */
+   for (x = 0; x < rsa_size; x++, y++) {
+       rsa_in[x] = in[y];
+   }
+
+   /* decrypt it */
+   x = sizeof(rsa_out);
+   if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* depad it */
+   z = sizeof(sym_key);
+   if ((errno = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* read the IV in */
+   for (x = 0; x < blklen; x++, y++) {
+       sym_IV[x] = in[y];
+   }
+
+   /* setup CTR mode */
+   if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get len */
+   LOAD32L(len, (in+y));
+   y += 4;
+
+   /* check size */
+   if (*outlen < len) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* decrypt the message */
+   if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) {
+      return errno;
+   }
+   
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(sym_key, sizeof(sym_key));
+   zeromem(sym_IV, sizeof(sym_IV));
+   zeromem(&ctr, sizeof(ctr));
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+/* Signature Message Format 
+offset    |  length   |    Contents
+----------------------------------------------------------------------
+0         |    1      | hash ID
+1         |    4      | length of rsa_pad'ed signature
+5         |    p      | the rsa_pad'ed signature
+*/
+
+int rsa_sign(const unsigned char *in,  unsigned long inlen, 
+                   unsigned char *out, unsigned long *outlen, 
+                   int hash, rsa_key *key)
+{
+   unsigned long hashlen, rsa_size, x, y, z;
+   unsigned char rsa_in[4096], rsa_out[4096];
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* type of key? */
+   if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* are the parameters valid? */
+   if ((errno = hash_is_valid(hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* hash it */
+   hashlen = hash_descriptor[hash].hashsize;
+   z = sizeof(rsa_in);
+   if ((errno = hash_memory(hash, in, inlen, rsa_in, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* pad it */
+   x = sizeof(rsa_in);
+   if ((errno = rsa_signpad(rsa_in, hashlen, rsa_out, &x)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* sign it */
+   rsa_size = sizeof(rsa_in);
+   if ((errno = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check size */
+   if (*outlen < (PACKET_SIZE+4+rsa_size)) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* now lets output the message */
+   y = PACKET_SIZE;
+   out[y++] = hash_descriptor[hash].ID;
+
+   /* output the len */
+   STORE32L(rsa_size, (out+y));
+   y += 4;
+
+   /* store the signature */
+   for (x = 0; x < rsa_size; x++, y++) {
+       out[y] = rsa_in[x];
+   }
+
+   /* store header */
+   packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED, y);
+
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   *outlen = y;
+   return CRYPT_OK;
+}
+
+int rsa_verify(const unsigned char *sig, const unsigned char *msg,
+                     unsigned long inlen, int *stat,
+                     rsa_key *key)
+{
+   unsigned long hashlen, rsa_size, x, y, z, w;
+   int hash, errno;
+   unsigned char rsa_in[4096], rsa_out[4096];
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(msg != NULL);
+   _ARGCHK(stat != NULL);
+   _ARGCHK(key != NULL);
+
+   /* always be incorrect by default */
+   *stat = 0;
+
+   /* verify header */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* grab hash name */
+   y = PACKET_SIZE;
+   hash = find_hash_id(sig[y++]);
+   if (hash == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+   hashlen = hash_descriptor[hash].hashsize;
+
+   /* get the len */
+   LOAD32L(rsa_size, (sig+y));
+   y += 4;
+
+   /* load the signature */
+   for (x = 0; x < rsa_size; x++, y++) {
+       rsa_in[x] = sig[y];
+   }
+
+   /* exptmod it */
+   x = sizeof(rsa_in);
+   if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* depad it */
+   z = sizeof(rsa_in);
+   if ((errno = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check? */
+   w = sizeof(rsa_out);
+   if ((errno = hash_memory(hash, msg, inlen, rsa_out, &w)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((z == hashlen) && (!memcmp(rsa_in, rsa_out, hashlen))) {
+      *stat = 1;
+   }
+
+#ifdef CLEAN_STACK
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+/* these are smaller routines written by Clay Culver.  They do the same function as the rsa_encrypt/decrypt 
+ * except that they are used to RSA encrypt/decrypt a single value and not a packet.
+ */
+int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen,
+                    unsigned char *outkey, unsigned long *outlen,
+                    prng_state *prng, int wprng, rsa_key *key)
+{
+   unsigned char rsa_in[4096], rsa_out[4096];
+   unsigned long x, y, rsa_size;
+   int errno;
+
+   _ARGCHK(inkey != NULL);
+   _ARGCHK(outkey != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* are the parameters valid? */
+   if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
+      return errno; 
+   }
+
+   /* rsa_pad the symmetric key */
+   y = sizeof(rsa_in); 
+   if ((errno = rsa_pad(inkey, inlen, rsa_in, &y, wprng, prng)) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   
+   /* rsa encrypt it */
+   rsa_size = sizeof(rsa_out);
+   if ((errno = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+
+   /* check size */
+   if (*outlen < (PACKET_SIZE+4+rsa_size)) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* now lets make the header */
+   y = PACKET_SIZE;
+   
+   /* store the size of the RSA value */
+   STORE32L(rsa_size, (outkey+y));
+   y += 4;
+
+   /* store the rsa value */
+   for (x = 0; x < rsa_size; x++, y++) {
+       outkey[y] = rsa_out[x];
+   }
+
+   /* store header */
+   packet_store_header(outkey, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY, y);
+
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   *outlen = y;
+   return CRYPT_OK;
+}
+
+int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, 
+                    unsigned long *keylen, rsa_key *key)
+{
+   unsigned char sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096];
+   unsigned long x, y, z, i, rsa_size;
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(outkey != NULL);
+   _ARGCHK(keylen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* check the header */
+   if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* grab length of the rsa key */
+   y = PACKET_SIZE;
+   LOAD32L(rsa_size, (in+y))
+   y += 4;
+
+   /* read it in */
+   for (x = 0; x < rsa_size; x++, y++) {
+       rsa_in[x] = in[y];
+   }
+
+   /* decrypt it */
+   x = sizeof(rsa_out);
+   if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) 
+      return errno;
+
+   /* depad it */
+   z = sizeof(sym_key);
+   if ((errno = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check size */
+   if (*keylen < z) { 
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   for (i = 0; i < z; i++) {
+     outkey[i] = sym_key[i];
+   }
+   
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(sym_key, sizeof(sym_key));
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   *keylen = z;
+   return CRYPT_OK;
+}
+
+int rsa_sign_hash(const unsigned char *in,  unsigned long inlen, 
+                        unsigned char *out, unsigned long *outlen, 
+                        rsa_key *key)
+{
+   unsigned long rsa_size, x, y;
+   unsigned char rsa_in[4096], rsa_out[4096];
+   int errno;
+
+   _ARGCHK(in != NULL);
+   _ARGCHK(out != NULL);
+   _ARGCHK(outlen != NULL);
+   _ARGCHK(key != NULL);
+
+   /* type of key? */
+   if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* pad it */
+   x = sizeof(rsa_out);
+   if ((errno = rsa_signpad(in, inlen, rsa_out, &x)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* sign it */
+   rsa_size = sizeof(rsa_in);
+   if ((errno = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check size */
+   if (*outlen < (PACKET_SIZE+4+rsa_size)) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* now lets output the message */
+   y = PACKET_SIZE;
+
+   /* output the len */
+   STORE32L(rsa_size, (out+y));
+   y += 4;
+
+   /* store the signature */
+   for (x = 0; x < rsa_size; x++, y++) {
+       out[y] = rsa_in[x];
+   }
+
+   /* store header */
+   packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED, y);
+
+#ifdef CLEAN_STACK
+   /* clean up */
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   *outlen = y;
+   return CRYPT_OK;
+}
+
+int rsa_verify_hash(const unsigned char *sig, const unsigned char *md,
+                          int *stat, rsa_key *key)
+{
+   unsigned long rsa_size, x, y, z;
+   unsigned char rsa_in[4096], rsa_out[4096];
+   int errno;
+
+   _ARGCHK(sig != NULL);
+   _ARGCHK(md != NULL);
+   _ARGCHK(stat != NULL);
+   _ARGCHK(key != NULL);
+
+   /* always be incorrect by default */
+   *stat = 0;
+
+   /* verify header */
+   if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* get the len */
+   y = PACKET_SIZE;
+   LOAD32L(rsa_size, (sig+y));
+   y += 4;
+
+   /* load the signature */
+   for (x = 0; x < rsa_size; x++, y++) {
+       rsa_in[x] = sig[y];
+   }
+
+   /* exptmod it */
+   x = sizeof(rsa_in);
+   if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* depad it */
+   z = sizeof(rsa_in);
+   if ((errno = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* check? */
+   if (!memcmp(rsa_in, md, z)) {
+      *stat = 1;
+   }
+
+#ifdef CLEAN_STACK
+   zeromem(rsa_in, sizeof(rsa_in));
+   zeromem(rsa_out, sizeof(rsa_out));
+#endif
+   return CRYPT_OK;
+}
+

+ 506 - 0
safer+.c

@@ -0,0 +1,506 @@
+#include "mycrypt.h"
+
+#ifdef SAFERP
+
+const struct _cipher_descriptor saferp_desc =
+{
+    "safer+",
+    4,
+    16, 32, 16, 8,
+    &saferp_setup,
+    &saferp_ecb_encrypt,
+    &saferp_ecb_decrypt,
+    &saferp_test,
+    &saferp_keysize
+};
+
+/* ROUND(b,i) 
+ *
+ * This is one forward key application.  Note the basic form is 
+ * key addition, substitution, key addition.  The safer_ebox and safer_lbox 
+ * are the exponentiation box and logarithm boxes respectively.  
+ * The value of 'i' is the current round number which allows this 
+ * function to be unrolled massively.  Most of SAFER+'s speed 
+ * comes from not having to compute indirect accesses into the 
+ * array of 16 bytes b[0..15] which is the block of data
+*/
+
+extern const unsigned char safer_ebox[], safer_lbox[];
+
+#define ROUND(b, i)                                                                        \
+    b[0]  = (safer_ebox[(b[0] ^ skey->saferp.K[i][0]) & 255] + skey->saferp.K[i+1][0]) & 255;    \
+    b[1]  = safer_lbox[(b[1] + skey->saferp.K[i][1]) & 255] ^ skey->saferp.K[i+1][1];            \
+    b[2]  = safer_lbox[(b[2] + skey->saferp.K[i][2]) & 255] ^ skey->saferp.K[i+1][2];            \
+    b[3]  = (safer_ebox[(b[3] ^ skey->saferp.K[i][3]) & 255] + skey->saferp.K[i+1][3]) & 255;    \
+    b[4]  = (safer_ebox[(b[4] ^ skey->saferp.K[i][4]) & 255] + skey->saferp.K[i+1][4]) & 255;    \
+    b[5]  = safer_lbox[(b[5] + skey->saferp.K[i][5]) & 255] ^ skey->saferp.K[i+1][5];            \
+    b[6]  = safer_lbox[(b[6] + skey->saferp.K[i][6]) & 255] ^ skey->saferp.K[i+1][6];            \
+    b[7]  = (safer_ebox[(b[7] ^ skey->saferp.K[i][7]) & 255] + skey->saferp.K[i+1][7]) & 255;    \
+    b[8]  = (safer_ebox[(b[8] ^ skey->saferp.K[i][8]) & 255] + skey->saferp.K[i+1][8]) & 255;    \
+    b[9]  = safer_lbox[(b[9] + skey->saferp.K[i][9]) & 255] ^ skey->saferp.K[i+1][9];            \
+    b[10] = safer_lbox[(b[10] + skey->saferp.K[i][10]) & 255] ^ skey->saferp.K[i+1][10];         \
+    b[11] = (safer_ebox[(b[11] ^ skey->saferp.K[i][11]) & 255] + skey->saferp.K[i+1][11]) & 255; \
+    b[12] = (safer_ebox[(b[12] ^ skey->saferp.K[i][12]) & 255] + skey->saferp.K[i+1][12]) & 255; \
+    b[13] = safer_lbox[(b[13] + skey->saferp.K[i][13]) & 255] ^ skey->saferp.K[i+1][13];         \
+    b[14] = safer_lbox[(b[14] + skey->saferp.K[i][14]) & 255] ^ skey->saferp.K[i+1][14];         \
+    b[15] = (safer_ebox[(b[15] ^ skey->saferp.K[i][15]) & 255] + skey->saferp.K[i+1][15]) & 255;        
+
+/* This is one inverse key application */
+#define iROUND(b, i)                                                                       \
+    b[0]  = safer_lbox[(b[0] - skey->saferp.K[i+1][0]) & 255] ^ skey->saferp.K[i][0];            \
+    b[1]  = (safer_ebox[(b[1] ^ skey->saferp.K[i+1][1]) & 255] - skey->saferp.K[i][1]) & 255;    \
+    b[2]  = (safer_ebox[(b[2] ^ skey->saferp.K[i+1][2]) & 255] - skey->saferp.K[i][2]) & 255;    \
+    b[3]  = safer_lbox[(b[3] - skey->saferp.K[i+1][3]) & 255] ^ skey->saferp.K[i][3];            \
+    b[4]  = safer_lbox[(b[4] - skey->saferp.K[i+1][4]) & 255] ^ skey->saferp.K[i][4];            \
+    b[5]  = (safer_ebox[(b[5] ^ skey->saferp.K[i+1][5]) & 255] - skey->saferp.K[i][5]) & 255;    \
+    b[6]  = (safer_ebox[(b[6] ^ skey->saferp.K[i+1][6]) & 255] - skey->saferp.K[i][6]) & 255;    \
+    b[7]  = safer_lbox[(b[7] - skey->saferp.K[i+1][7]) & 255] ^ skey->saferp.K[i][7];            \
+    b[8]  = safer_lbox[(b[8] - skey->saferp.K[i+1][8]) & 255] ^ skey->saferp.K[i][8];            \
+    b[9]  = (safer_ebox[(b[9] ^ skey->saferp.K[i+1][9]) & 255] - skey->saferp.K[i][9]) & 255;    \
+    b[10] = (safer_ebox[(b[10] ^ skey->saferp.K[i+1][10]) & 255] - skey->saferp.K[i][10]) & 255; \
+    b[11] = safer_lbox[(b[11] - skey->saferp.K[i+1][11]) & 255] ^ skey->saferp.K[i][11];         \
+    b[12] = safer_lbox[(b[12] - skey->saferp.K[i+1][12]) & 255] ^ skey->saferp.K[i][12];         \
+    b[13] = (safer_ebox[(b[13] ^ skey->saferp.K[i+1][13]) & 255] - skey->saferp.K[i][13]) & 255; \
+    b[14] = (safer_ebox[(b[14] ^ skey->saferp.K[i+1][14]) & 255] - skey->saferp.K[i][14]) & 255; \
+    b[15] = safer_lbox[(b[15] - skey->saferp.K[i+1][15]) & 255] ^ skey->saferp.K[i][15];
+
+/* This is a forward single layer PHT transform.  */
+#define PHT(b)                                               \
+    b[0]  = (b[0] + (b[1] = (b[0] + b[1]) & 255)) & 255;     \
+    b[2]  = (b[2] + (b[3] = (b[3] + b[2]) & 255)) & 255;     \
+    b[4]  = (b[4] + (b[5] = (b[5] + b[4]) & 255)) & 255;     \
+    b[6]  = (b[6] + (b[7] = (b[7] + b[6]) & 255)) & 255;     \
+    b[8]  = (b[8] + (b[9] = (b[9] + b[8]) & 255)) & 255;     \
+    b[10] = (b[10] + (b[11] = (b[11] + b[10]) & 255)) & 255; \
+    b[12] = (b[12] + (b[13] = (b[13] + b[12]) & 255)) & 255; \
+    b[14] = (b[14] + (b[15] = (b[15] + b[14]) & 255)) & 255;    
+
+/* This is an inverse single layer PHT transform */
+#define iPHT(b)                                               \
+    b[15] = (b[15] - (b[14] = (b[14] - b[15]) & 255)) & 255;  \
+    b[13] = (b[13] - (b[12] = (b[12] - b[13]) & 255)) & 255;  \
+    b[11] = (b[11] - (b[10] = (b[10] - b[11]) & 255)) & 255;  \
+    b[9]  = (b[9] - (b[8] = (b[8] - b[9]) & 255)) & 255;      \
+    b[7]  = (b[7] - (b[6] = (b[6] - b[7]) & 255)) & 255;      \
+    b[5]  = (b[5] - (b[4] = (b[4] - b[5]) & 255)) & 255;      \
+    b[3]  = (b[3] - (b[2] = (b[2] - b[3]) & 255)) & 255;      \
+    b[1]  = (b[1] - (b[0] = (b[0] - b[1]) & 255)) & 255;      \
+
+/* This is the "Armenian" Shuffle.  It takes the input from b and stores it in b2 */
+#define SHUF(b, b2)                                              \
+    b2[0] = b[8]; b2[1] = b[11]; b2[2] = b[12]; b2[3] = b[15];   \
+    b2[4] = b[2]; b2[5] = b[1]; b2[6] = b[6]; b2[7] = b[5];      \
+    b2[8] = b[10]; b2[9] = b[9]; b2[10] = b[14]; b2[11] = b[13]; \
+    b2[12] = b[0]; b2[13] = b[7]; b2[14] = b[4]; b2[15] = b[3];
+
+/* This is the inverse shuffle.  It takes from b and gives to b2 */
+#define iSHUF(b, b2)                                               \
+    b2[0] = b[12]; b2[1] = b[5]; b2[2] = b[4]; b2[3] = b[15];      \
+    b2[4] = b[14]; b2[5] = b[7]; b2[6] = b[6]; b2[7] = b[13];      \
+    b2[8] = b[0]; b2[9] = b[9]; b2[10] = b[8]; b2[11] = b[1];      \
+    b2[12] = b[2]; b2[13] = b[11]; b2[14] = b[10]; b2[15] = b[3];
+
+/* The complete forward Linear Transform layer.  
+ * Note that alternating usage of b and b2.  
+ * Each round of LT starts in 'b' and ends in 'b2'.  
+ */
+#define LT(b, b2)             \
+    PHT(b);  SHUF(b, b2);     \
+    PHT(b2); SHUF(b2, b);     \
+    PHT(b);  SHUF(b, b2);     \
+    PHT(b2); 
+
+/* This is the inverse linear transform layer.  */
+#define iLT(b, b2)            \
+    iPHT(b);                  \
+    iSHUF(b, b2); iPHT(b2);   \
+    iSHUF(b2, b); iPHT(b);    \
+    iSHUF(b, b2); iPHT(b2);
+    
+#ifdef SAFERP_SMALL    
+
+static void _round(unsigned char *b, int i, symmetric_key *skey) 
+{
+   ROUND(b, i);
+}
+
+static void _iround(unsigned char *b, int i, symmetric_key *skey)
+{
+   iROUND(b, i);
+}
+
+static void _lt(unsigned char *b, unsigned char *b2)
+{
+   LT(b, b2);
+}
+
+static void _ilt(unsigned char *b, unsigned char *b2)
+{
+   iLT(b, b2);
+}   
+
+#undef ROUND
+#define ROUND(b, i) _round(b, i, skey)
+
+#undef iROUND
+#define iROUND(b, i) _iround(b, i, skey)
+
+#undef LT
+#define LT(b, b2) _lt(b, b2)
+
+#undef iLT
+#define iLT(b, b2) _ilt(b, b2)
+
+#endif
+
+/* These are the 33, 128-bit bias words for the key schedule */
+const unsigned char safer_bias[33][16] = {
+{  70, 151, 177, 186, 163, 183,  16,  10, 197,  55, 179, 201,  90,  40, 172, 100},
+{ 236, 171, 170, 198, 103, 149,  88,  13, 248, 154, 246, 110, 102, 220,   5,  61},
+{ 138, 195, 216, 137, 106, 233,  54,  73,  67, 191, 235, 212, 150, 155, 104, 160},
+{  93,  87, 146,  31, 213, 113,  92, 187,  34, 193, 190, 123, 188, 153,  99, 148},
+{  42,  97, 184,  52,  50,  25, 253, 251,  23,  64, 230,  81,  29,  65,  68, 143},
+{ 221,   4, 128, 222, 231,  49, 214, 127,   1, 162, 247,  57, 218, 111,  35, 202},
+{  58, 208,  28, 209,  48,  62,  18, 161, 205,  15, 224, 168, 175, 130,  89,  44},
+{ 125, 173, 178, 239, 194, 135, 206, 117,   6,  19,   2, 144,  79,  46, 114,  51},
+{ 192, 141, 207, 169, 129, 226, 196,  39,  47, 108, 122, 159,  82, 225,  21,  56},
+{ 252,  32,  66, 199,   8, 228,   9,  85,  94, 140,  20, 118,  96, 255, 223, 215},
+{ 250,  11,  33,   0,  26, 249, 166, 185, 232, 158,  98,  76, 217, 145,  80, 210},
+{  24, 180,   7, 132, 234,  91, 164, 200,  14, 203,  72, 105,  75,  78, 156,  53},
+{  69,  77,  84, 229,  37,  60,  12,  74, 139,  63, 204, 167, 219, 107, 174, 244},
+{  45, 243, 124, 109, 157, 181,  38, 116, 242, 147,  83, 176, 240,  17, 237, 131},
+{ 182,   3,  22, 115,  59,  30, 142, 112, 189, 134,  27,  71, 126,  36,  86, 241},
+{ 136,  70, 151, 177, 186, 163, 183,  16,  10, 197,  55, 179, 201,  90,  40, 172},
+{ 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, 241,  51, 239},
+{  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20, 129, 151, 113, 202},
+{ 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160,   4, 180, 133,  74, 246},
+{  84, 182, 223,  12,  26, 142, 222, 224,  57, 252,  32, 155,  36,  78, 169, 152},
+{ 171, 242,  96, 208, 108, 234, 250, 199, 217,   0, 212,  31, 110,  67, 188, 236},
+{ 137, 254, 122,  93,  73, 201,  50, 194, 249, 154, 248, 109,  22, 219,  89, 150},
+{ 233, 205, 230,  70,  66, 143,  10, 193, 204, 185, 101, 176, 210, 198, 172,  30},
+{  98,  41,  46,  14, 116,  80,   2,  90, 195,  37, 123, 138,  42,  91, 240,   6},
+{  71, 111, 112, 157, 126,  16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104},
+{ 117, 125, 228, 237, 128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175},
+{ 229,  25,  97, 253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35},
+{ 200,   5, 225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7},
+{  40,   1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207},
+{   8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247},
+{  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177, 255},
+{  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, 241,  51}};
+
+int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   unsigned x, y;
+   unsigned char t[33];
+   static const int rounds[3] = { 8, 12, 16 };
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* check arguments */
+   if (keylen != 16 && keylen != 24 && keylen != 32) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* Is the number of rounds valid?  Either use zero for default or
+    * 8,12,16 rounds for 16,24,32 byte keys 
+    */
+   if (num_rounds != 0 && num_rounds != rounds[(keylen/8)-2]) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* 128 bit key version */
+   if (keylen == 16) {
+       /* copy key into t */
+       for (x = y = 0; x < 16; x++) { 
+           t[x] = key[x]; 
+           y ^= key[x]; 
+       }
+       t[16] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) {
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       /* make the 16 other keys as a transformation of the first key */
+       for (x = 1; x < 17; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 17; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+
+           /* select and add */
+           for (y = 0; y < 16; y++) {
+               skey->saferp.K[x][y] = (t[(x+y)%17] + safer_bias[x-1][y]) & 255;
+           }
+       }
+       skey->saferp.rounds = 8;
+   } else if (keylen == 24) {
+       /* copy key into t */
+       for (x = y = 0; x < 24; x++) { 
+           t[x] = key[x]; 
+           y ^= key[x]; 
+       }
+       t[24] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) {
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       for (x = 1; x < 25; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 25; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+
+           /* select and add */
+           for (y = 0; y < 16; y++) { 
+               skey->saferp.K[x][y] = (t[(x+y)%25] + safer_bias[x-1][y]) & 255;
+           }
+       }
+       skey->saferp.rounds = 12;
+   } else {
+       /* copy key into t */
+       for (x = y = 0; x < 32; x++) { 
+           t[x] = key[x]; 
+           y ^= key[x]; 
+       }
+       t[32] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) { 
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       for (x = 1; x < 33; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 33; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+           
+           /* select and add */
+           for (y = 0; y < 16; y++) {
+               skey->saferp.K[x][y] = (t[(x+y)%33] + safer_bias[x-1][y]) & 255;
+           }
+       }
+       skey->saferp.rounds = 16;
+   }
+#ifdef CLEAN_STACK
+   zeromem(t, sizeof(t));
+#endif
+   return CRYPT_OK;
+}
+
+void saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   unsigned char b[16];
+   int x;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* do eight rounds */
+   for (x = 0; x < 16; x++) {
+       b[x] = pt[x];
+   }
+   ROUND(b,  0);  LT(b, ct);
+   ROUND(ct, 2);  LT(ct, b);
+   ROUND(b,  4);  LT(b, ct);
+   ROUND(ct, 6);  LT(ct, b);
+   ROUND(b,  8);  LT(b, ct);
+   ROUND(ct, 10); LT(ct, b);
+   ROUND(b,  12); LT(b, ct);
+   ROUND(ct, 14); LT(ct, b);
+   /* 192-bit key? */
+   if (skey->saferp.rounds > 8) {
+      ROUND(b, 16);  LT(b, ct);
+      ROUND(ct, 18); LT(ct, b);
+      ROUND(b, 20);  LT(b, ct);
+      ROUND(ct, 22); LT(ct, b);
+   }
+   /* 256-bit key? */
+   if (skey->saferp.rounds > 12) {
+      ROUND(b, 24);  LT(b, ct);
+      ROUND(ct, 26); LT(ct, b);
+      ROUND(b, 28);  LT(b, ct);
+      ROUND(ct, 30); LT(ct, b);
+   }
+   ct[0] = b[0] ^ skey->saferp.K[skey->saferp.rounds*2][0];
+   ct[1] = (b[1] + skey->saferp.K[skey->saferp.rounds*2][1]) & 255;
+   ct[2] = (b[2] + skey->saferp.K[skey->saferp.rounds*2][2]) & 255;
+   ct[3] = b[3] ^ skey->saferp.K[skey->saferp.rounds*2][3];
+   ct[4] = b[4] ^ skey->saferp.K[skey->saferp.rounds*2][4];
+   ct[5] = (b[5] + skey->saferp.K[skey->saferp.rounds*2][5]) & 255;
+   ct[6] = (b[6] + skey->saferp.K[skey->saferp.rounds*2][6]) & 255;
+   ct[7] = b[7] ^ skey->saferp.K[skey->saferp.rounds*2][7];
+   ct[8] = b[8] ^ skey->saferp.K[skey->saferp.rounds*2][8];
+   ct[9] = (b[9] + skey->saferp.K[skey->saferp.rounds*2][9]) & 255;
+   ct[10] = (b[10] + skey->saferp.K[skey->saferp.rounds*2][10]) & 255;
+   ct[11] = b[11] ^ skey->saferp.K[skey->saferp.rounds*2][11];
+   ct[12] = b[12] ^ skey->saferp.K[skey->saferp.rounds*2][12];
+   ct[13] = (b[13] + skey->saferp.K[skey->saferp.rounds*2][13]) & 255;
+   ct[14] = (b[14] + skey->saferp.K[skey->saferp.rounds*2][14]) & 255;
+   ct[15] = b[15] ^ skey->saferp.K[skey->saferp.rounds*2][15];
+#ifdef CLEAN_STACK
+   zeromem(b, sizeof(b));
+#endif
+}
+
+void saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   unsigned char b[16];
+   int x;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* do eight rounds */
+   b[0] = ct[0] ^ skey->saferp.K[skey->saferp.rounds*2][0];
+   b[1] = (ct[1] - skey->saferp.K[skey->saferp.rounds*2][1]) & 255;
+   b[2] = (ct[2] - skey->saferp.K[skey->saferp.rounds*2][2]) & 255;
+   b[3] = ct[3] ^ skey->saferp.K[skey->saferp.rounds*2][3];
+   b[4] = ct[4] ^ skey->saferp.K[skey->saferp.rounds*2][4];
+   b[5] = (ct[5] - skey->saferp.K[skey->saferp.rounds*2][5]) & 255;
+   b[6] = (ct[6] - skey->saferp.K[skey->saferp.rounds*2][6]) & 255;
+   b[7] = ct[7] ^ skey->saferp.K[skey->saferp.rounds*2][7];
+   b[8] = ct[8] ^ skey->saferp.K[skey->saferp.rounds*2][8];
+   b[9] = (ct[9] - skey->saferp.K[skey->saferp.rounds*2][9]) & 255;
+   b[10] = (ct[10] - skey->saferp.K[skey->saferp.rounds*2][10]) & 255;
+   b[11] = ct[11] ^ skey->saferp.K[skey->saferp.rounds*2][11];
+   b[12] = ct[12] ^ skey->saferp.K[skey->saferp.rounds*2][12];
+   b[13] = (ct[13] - skey->saferp.K[skey->saferp.rounds*2][13]) & 255;
+   b[14] = (ct[14] - skey->saferp.K[skey->saferp.rounds*2][14]) & 255;
+   b[15] = ct[15] ^ skey->saferp.K[skey->saferp.rounds*2][15];
+   /* 256-bit key? */
+   if (skey->saferp.rounds > 12) {
+      iLT(b, pt); iROUND(pt, 30);
+      iLT(pt, b); iROUND(b, 28);
+      iLT(b, pt); iROUND(pt, 26);
+      iLT(pt, b); iROUND(b, 24);
+   }
+   /* 192-bit key? */
+   if (skey->saferp.rounds > 8) {
+      iLT(b, pt); iROUND(pt, 22);
+      iLT(pt, b); iROUND(b, 20);
+      iLT(b, pt); iROUND(pt, 18);
+      iLT(pt, b); iROUND(b, 16);
+   }
+   iLT(b, pt); iROUND(pt, 14);
+   iLT(pt, b); iROUND(b, 12);
+   iLT(b, pt); iROUND(pt,10);
+   iLT(pt, b); iROUND(b, 8);
+   iLT(b, pt); iROUND(pt,6);
+   iLT(pt, b); iROUND(b, 4);
+   iLT(b, pt); iROUND(pt,2);
+   iLT(pt, b); iROUND(b, 0);
+   for (x = 0; x < 16; x++) {
+       pt[x] = b[x];
+   }
+#ifdef CLEAN_STACK
+   zeromem(b, sizeof(b));
+#endif
+}
+
+int saferp_test(void)
+{
+   static const unsigned char key128[16] = 
+       { 41, 35, 190, 132, 225, 108, 214, 174, 
+         82, 144, 73, 241, 241, 187, 233, 235 };
+   static const unsigned char pt128[16] = 
+       { 179, 166, 219, 60, 135, 12, 62, 153, 
+         36, 94, 13, 28, 6, 183, 71, 222 };
+   static const unsigned char ct128[16] =
+       { 224, 31, 182, 10, 12, 255, 84, 70, 
+         127, 13, 89, 249, 9, 57, 165, 220 };
+
+   static const unsigned char key192[24] = 
+       { 72, 211, 143, 117, 230, 217, 29, 42, 
+         229, 192, 247, 43, 120, 129, 135, 68, 
+         14, 95, 80, 0, 212, 97, 141, 190 };
+   static const unsigned char pt192[16] = 
+       { 123, 5, 21, 7, 59, 51, 130, 31, 
+         24, 112, 146, 218, 100, 84, 206, 177 };
+   static const unsigned char ct192[16] = 
+       { 92, 136, 4, 63, 57, 95, 100, 0, 
+         150, 130, 130, 16, 193, 111, 219, 133 };
+
+   static const unsigned char key256[32] =
+       { 243, 168, 141, 254, 190, 242, 235, 113, 
+         255, 160, 208, 59, 117, 6, 140, 126,
+         135, 120, 115, 77, 208, 190, 130, 190, 
+         219, 194, 70, 65, 43, 140, 250, 48 };
+   static const unsigned char pt256[16] = 
+       { 127, 112, 240, 167, 84, 134, 50, 149, 
+         170, 91, 104, 19, 11, 230, 252, 245 };
+   static const unsigned char ct256[16] = 
+       { 88, 11, 25, 36, 172, 229, 202, 213, 
+         170, 65, 105, 153, 220, 104, 153, 138 };
+
+   unsigned char buf[2][16];
+   symmetric_key skey;
+   int errno;
+
+   /* test 128-bit key */
+   if ((errno = saferp_setup(key128, 16, 0, &skey)) != CRYPT_OK)  {
+      return errno;
+   }
+   saferp_ecb_encrypt(pt128, buf[0], &skey);
+   saferp_ecb_decrypt(buf[0], buf[1], &skey);
+
+   /* compare */
+   if (memcmp(buf[0], &ct128, 16) || memcmp(buf[1], &pt128, 16)) { 
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* test 192-bit key */
+   if ((errno = saferp_setup(key192, 24, 0, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+   saferp_ecb_encrypt(pt192, buf[0], &skey);
+   saferp_ecb_decrypt(buf[0], buf[1], &skey);
+
+   /* compare */
+   if (memcmp(buf[0], &ct192, 16) || memcmp(buf[1], &pt192, 16)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* test 256-bit key */
+   if ((errno = saferp_setup(key256, 32, 0, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+   saferp_ecb_encrypt(pt256, buf[0], &skey);
+   saferp_ecb_decrypt(buf[0], buf[1], &skey);
+
+   /* compare */
+   if (memcmp(buf[0], &ct256, 16) || memcmp(buf[1], &pt256, 16)) { 
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+}
+
+int saferp_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+   
+   if (*desired_keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*desired_keysize < 24) {
+      *desired_keysize = 16;
+      return CRYPT_OK;
+   } else if (*desired_keysize < 32) {
+      *desired_keysize = 24;
+      return CRYPT_OK;
+   } else {
+      *desired_keysize = 32;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+
+

+ 421 - 0
safer.c

@@ -0,0 +1,421 @@
+/*******************************************************************************
+*
+* FILE:           safer.c
+*
+* DESCRIPTION:    block-cipher algorithm SAFER (Secure And Fast Encryption
+*                 Routine) in its four versions: SAFER K-64, SAFER K-128,
+*                 SAFER SK-64 and SAFER SK-128.
+*
+* AUTHOR:         Richard De Moliner ([email protected])
+*                 Signal and Information Processing Laboratory
+*                 Swiss Federal Institute of Technology
+*                 CH-8092 Zuerich, Switzerland
+*
+* DATE:           September 9, 1995
+*
+* CHANGE HISTORY:
+*
+*******************************************************************************/
+
+#include <mycrypt.h>
+
+#ifdef SAFER
+
+const struct _cipher_descriptor 
+   safer_k64_desc = {
+   "safer-k64", 
+   8, 8, 8, 8, SAFER_K64_DEFAULT_NOF_ROUNDS,
+   &safer_k64_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_k64_test,
+   &safer_64_keysize
+   },
+
+   safer_sk64_desc = {
+   "safer-sk64",
+   9, 8, 8, 8, SAFER_SK64_DEFAULT_NOF_ROUNDS,
+   &safer_sk64_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk64_test,
+   &safer_64_keysize
+   },
+
+   safer_k128_desc = {
+   "safer-k128",
+   10, 16, 16, 8, SAFER_K128_DEFAULT_NOF_ROUNDS,
+   &safer_k128_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk128_test,
+   &safer_128_keysize
+   },
+
+   safer_sk128_desc = {
+   "safer-sk128",
+   11, 16, 16, 8, SAFER_SK128_DEFAULT_NOF_ROUNDS,
+   &safer_sk128_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk128_test,
+   &safer_128_keysize
+   };
+
+/******************* Constants ************************************************/
+// #define TAB_LEN      256
+
+/******************* Assertions ***********************************************/
+
+/******************* Macros ***************************************************/
+#define ROL8(x, n)   ((unsigned char)((unsigned int)(x) << (n)\
+                                     |(unsigned int)((x) & 0xFF) >> (8 - (n))))
+#define EXP(x)       safer_ebox[(x) & 0xFF]
+#define LOG(x)       safer_lbox[(x) & 0xFF]
+#define PHT(x, y)    { y += x; x += y; }
+#define IPHT(x, y)   { x -= y; y -= x; }
+
+/******************* Types ****************************************************/
+extern const unsigned char safer_ebox[], safer_lbox[];
+
+#ifdef CLEAN_STACK
+static void _Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+#else
+static void Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+#endif
+{   unsigned int i, j;
+    unsigned char ka[SAFER_BLOCK_LEN + 1];
+    unsigned char kb[SAFER_BLOCK_LEN + 1];
+
+    if (SAFER_MAX_NOF_ROUNDS < nof_rounds)
+        nof_rounds = SAFER_MAX_NOF_ROUNDS;
+    *key++ = (unsigned char)nof_rounds;
+    ka[SAFER_BLOCK_LEN] = 0;
+    kb[SAFER_BLOCK_LEN] = 0;
+    for (j = 0; j < SAFER_BLOCK_LEN; j++)
+    {
+        ka[SAFER_BLOCK_LEN] ^= ka[j] = ROL8(userkey_1[j], 5);
+        kb[SAFER_BLOCK_LEN] ^= kb[j] = *key++ = userkey_2[j];
+    }
+    for (i = 1; i <= nof_rounds; i++)
+    {
+        for (j = 0; j < SAFER_BLOCK_LEN + 1; j++)
+        {
+            ka[j] = ROL8(ka[j], 6);
+            kb[j] = ROL8(kb[j], 6);
+        }
+        for (j = 0; j < SAFER_BLOCK_LEN; j++)
+            if (strengthened)
+                *key++ = (ka[(j + 2 * i - 1) % (SAFER_BLOCK_LEN + 1)]
+                                + safer_ebox[safer_ebox[18 * i + j + 1]]) & 0xFF;
+            else
+                *key++ = (ka[j] + safer_ebox[safer_ebox[18 * i + j + 1]]) & 0xFF;
+        for (j = 0; j < SAFER_BLOCK_LEN; j++)
+            if (strengthened)
+                *key++ = (kb[(j + 2 * i) % (SAFER_BLOCK_LEN + 1)]
+                                + safer_ebox[safer_ebox[18 * i + j + 10]]) & 0xFF;
+            else
+                *key++ = (kb[j] + safer_ebox[safer_ebox[18 * i + j + 10]]) & 0xFF;
+    }
+    
+#ifdef CLEAN_STACK
+    zeromem(ka, sizeof(ka));
+    zeromem(kb, sizeof(kb));
+#endif
+}
+
+#ifdef CLEAN_STACK
+static void Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+{
+   _Safer_Expand_Userkey(userkey_1, userkey_2, nof_rounds, strengthened, key);
+   burn_stack(sizeof(unsigned char) * (2 * (SAFER_BLOCK_LEN + 1)) + sizeof(unsigned int)*2);
+}
+#endif
+
+int safer_k64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key, numrounds?numrounds:SAFER_K64_DEFAULT_NOF_ROUNDS, 0, skey->safer.key);
+   return CRYPT_OK;
+}
+   
+int safer_sk64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key, numrounds?numrounds:SAFER_SK64_DEFAULT_NOF_ROUNDS, 1, skey->safer.key);
+   return CRYPT_OK;
+}
+
+int safer_k128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key+8, numrounds?numrounds:SAFER_K128_DEFAULT_NOF_ROUNDS, 0, skey->safer.key);
+   return CRYPT_OK;
+}
+
+int safer_sk128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key+8, numrounds?numrounds:SAFER_SK128_DEFAULT_NOF_ROUNDS, 1, skey->safer.key);
+   return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+static void _safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#else
+void safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#endif
+{   unsigned char a, b, c, d, e, f, g, h, t;
+    unsigned int round;
+    unsigned char *key;
+
+    _ARGCHK(block_in != NULL);
+    _ARGCHK(block_out != NULL);
+    _ARGCHK(skey != NULL);
+
+    key = skey->safer.key;
+    a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3];
+    e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7];
+    if (SAFER_MAX_NOF_ROUNDS < (round = *key)) round = SAFER_MAX_NOF_ROUNDS;
+    while(round--)
+    {
+        a ^= *++key; b += *++key; c += *++key; d ^= *++key;
+        e ^= *++key; f += *++key; g += *++key; h ^= *++key;
+        a = EXP(a) + *++key; b = LOG(b) ^ *++key;
+        c = LOG(c) ^ *++key; d = EXP(d) + *++key;
+        e = EXP(e) + *++key; f = LOG(f) ^ *++key;
+        g = LOG(g) ^ *++key; h = EXP(h) + *++key;
+        PHT(a, b); PHT(c, d); PHT(e, f); PHT(g, h);
+        PHT(a, c); PHT(e, g); PHT(b, d); PHT(f, h);
+        PHT(a, e); PHT(b, f); PHT(c, g); PHT(d, h);
+        t = b; b = e; e = c; c = t; t = d; d = f; f = g; g = t;
+    }
+    a ^= *++key; b += *++key; c += *++key; d ^= *++key;
+    e ^= *++key; f += *++key; g += *++key; h ^= *++key;
+    block_out[0] = a & 0xFF; block_out[1] = b & 0xFF;
+    block_out[2] = c & 0xFF; block_out[3] = d & 0xFF;
+    block_out[4] = e & 0xFF; block_out[5] = f & 0xFF;
+    block_out[6] = g & 0xFF; block_out[7] = h & 0xFF;
+}
+
+#ifdef CLEAN_STACK
+void safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+{
+    _safer_ecb_encrypt(block_in, block_out, skey);
+    burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *));
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#else
+void safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#endif
+{   unsigned char a, b, c, d, e, f, g, h, t;
+    unsigned int round;
+    unsigned char *key;
+
+    _ARGCHK(block_in != NULL);
+    _ARGCHK(block_out != NULL);
+    _ARGCHK(skey != NULL);
+
+    key = skey->safer.key;
+    a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3];
+    e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7];
+    if (SAFER_MAX_NOF_ROUNDS < (round = *key)) round = SAFER_MAX_NOF_ROUNDS;
+    key += SAFER_BLOCK_LEN * (1 + 2 * round);
+    h ^= *key; g -= *--key; f -= *--key; e ^= *--key;
+    d ^= *--key; c -= *--key; b -= *--key; a ^= *--key;
+    while (round--)
+    {
+        t = e; e = b; b = c; c = t; t = f; f = d; d = g; g = t;
+        IPHT(a, e); IPHT(b, f); IPHT(c, g); IPHT(d, h);
+        IPHT(a, c); IPHT(e, g); IPHT(b, d); IPHT(f, h);
+        IPHT(a, b); IPHT(c, d); IPHT(e, f); IPHT(g, h);
+        h -= *--key; g ^= *--key; f ^= *--key; e -= *--key;
+        d -= *--key; c ^= *--key; b ^= *--key; a -= *--key;
+        h = LOG(h) ^ *--key; g = EXP(g) - *--key;
+        f = EXP(f) - *--key; e = LOG(e) ^ *--key;
+        d = LOG(d) ^ *--key; c = EXP(c) - *--key;
+        b = EXP(b) - *--key; a = LOG(a) ^ *--key;
+    }
+    block_out[0] = a & 0xFF; block_out[1] = b & 0xFF;
+    block_out[2] = c & 0xFF; block_out[3] = d & 0xFF;
+    block_out[4] = e & 0xFF; block_out[5] = f & 0xFF;
+    block_out[6] = g & 0xFF; block_out[7] = h & 0xFF;
+}
+
+#ifdef CLEAN_STACK
+void safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+{
+    _safer_ecb_decrypt(block_in, block_out, skey);
+    burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *));
+}
+#endif
+
+int safer_64_keysize(int *keysize)
+{
+   _ARGCHK(keysize != NULL);
+   if (*keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else {
+      *keysize = 8;
+      return CRYPT_OK;
+   }
+}
+
+int safer_128_keysize(int *keysize)
+{
+   _ARGCHK(keysize != NULL);
+   if (*keysize < 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else {
+      *keysize = 16;
+      return CRYPT_OK;
+   }
+}
+
+int safer_k64_test(void)
+{
+   static const unsigned char k64_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              k64_key[] = { 8, 7, 6, 5, 4, 3, 2, 1 },
+                              k64_ct[]  = { 200, 242, 156, 221, 135, 120, 62, 217 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int errno;
+
+   /* test K64 */
+   if ((errno = safer_k64_setup(k64_key, 8, 6, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+   safer_ecb_encrypt(k64_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (memcmp(buf[0], k64_ct, 8) || memcmp(buf[1], k64_pt, 8)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+}
+
+
+int safer_sk64_test(void)
+{
+   static const unsigned char sk64_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk64_key[] = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk64_ct[]  = { 95, 206, 155, 162, 5, 132, 56, 199 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int errno;
+
+   /* test SK64 */
+   if ((errno = safer_sk64_setup(sk64_key, 8, 6, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+
+   safer_ecb_encrypt(sk64_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (memcmp(buf[0], sk64_ct, 8) || memcmp(buf[1], sk64_pt, 8)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+}
+
+int safer_sk128_test(void)
+{
+   static const unsigned char sk128_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk128_key[] = { 1, 2, 3, 4, 5, 6, 7, 8,
+                                              0, 0, 0, 0, 0, 0, 0, 0 },
+                              sk128_ct[]  = { 255, 120, 17, 228, 179, 167, 46, 113 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int errno;
+
+   /* test SK128 */
+   if ((errno = safer_sk128_setup(sk128_key, 16, 0, &skey)) != CRYPT_OK) {
+      return errno;
+   }
+   safer_ecb_encrypt(sk128_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (memcmp(buf[0], sk128_ct, 8) || memcmp(buf[1], sk128_pt, 8)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+

+ 48 - 0
safer_tab.c

@@ -0,0 +1,48 @@
+#include "mycrypt.h"
+
+#if defined(SAFERP) || defined(SAFER)
+
+/* This is the box defined by ebox[x] = 45^x mod 257.  
+ * Its assumed that the value "256" corresponds to zero. */
+const unsigned char safer_ebox[256] = {
+  1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207,  63, 
+  8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247, 
+ 64,  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177, 
+255, 167,  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, 
+241,  51, 239, 218,  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20, 
+129, 151, 113, 202,  95, 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160, 
+  4, 180, 133,  74, 246,  19,  84, 182, 223,  12,  26, 142, 222, 224,  57, 252, 
+ 32, 155,  36,  78, 169, 152, 158, 171, 242,  96, 208, 108, 234, 250, 199, 217, 
+  0, 212,  31, 110,  67, 188, 236,  83, 137, 254, 122,  93,  73, 201,  50, 194, 
+249, 154, 248, 109,  22, 219,  89, 150,  68, 233, 205, 230,  70,  66, 143,  10, 
+193, 204, 185, 101, 176, 210, 198, 172,  30,  65,  98,  41,  46,  14, 116,  80, 
+  2,  90, 195,  37, 123, 138,  42,  91, 240,   6,  13,  71, 111, 112, 157, 126, 
+ 16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104,  54, 117, 125, 228, 237, 
+128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175, 165, 229,  25,  97, 
+253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35,  33, 200,   5, 
+225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7,  58,  40
+};
+
+/* This is the inverse of ebox or the base 45 logarithm */
+const unsigned char safer_lbox[256] = {
+128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248,
+192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130,
+112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37, 
+201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15, 
+ 32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198, 
+175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84, 
+121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188, 
+189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217,
+208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158, 
+210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42, 
+ 95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219,
+164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29, 
+ 41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14, 
+122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104, 
+109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66, 
+184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48
+};
+
+#endif
+
+

+ 719 - 0
serpent.c

@@ -0,0 +1,719 @@
+#include "mycrypt.h"
+
+#ifdef SERPENT
+
+const struct _cipher_descriptor serpent_desc =
+{
+    "serpent",
+    5,
+    16, 32, 16, 32,
+    &serpent_setup,
+    &serpent_ecb_encrypt,
+    &serpent_ecb_decrypt,
+    &serpent_test,
+    &serpent_keysize
+};
+
+/* These defines are derived from Brian Gladman's work.  Contact him at [email protected] 
+ *
+ * Available on the web at http://fp.gladman.plus.com/cryptography_technology/aes/index.htm
+ */
+#define sb0(a,b,c,d,e,f,g,h)    \
+    t1 = a ^ d;     \
+    t2 = a & d;     \
+    t3 = c ^ t1;    \
+    t6 = b & t1;    \
+    t4 = b ^ t3;    \
+    t10 = ~t3;      \
+    h = t2 ^ t4;    \
+    t7 = a ^ t6;    \
+    t14 = ~t7;      \
+    t8 = c | t7;    \
+    t11 = t3 ^ t7;  \
+    g = t4 ^ t8;    \
+    t12 = h & t11;  \
+    f = t10 ^ t12;  \
+    e = t12 ^ t14
+
+/* 15 terms */
+
+#define ib0(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = a ^ b;     \
+    t3 = t1 | t2;   \
+    t4 = d ^ t3;    \
+    t7 = d & t2;    \
+    t5 = c ^ t4;    \
+    t8 = t1 ^ t7;   \
+    g = t2 ^ t5;    \
+    t11 = a & t4;   \
+    t9 = g & t8;    \
+    t14 = t5 ^ t8;  \
+    f = t4 ^ t9;    \
+    t12 = t5 | f;   \
+    h = t11 ^ t12;  \
+    e = h ^ t14
+
+/* 14 terms!  */
+
+#define sb1(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = b ^ t1;    \
+    t3 = a | t2;    \
+    t4 = d | t2;    \
+    t5 = c ^ t3;    \
+    g = d ^ t5;     \
+    t7 = b ^ t4;    \
+    t8 = t2 ^ g;    \
+    t9 = t5 & t7;   \
+    h = t8 ^ t9;    \
+    t11 = t5 ^ t7;  \
+    f = h ^ t11;    \
+    t13 = t8 & t11; \
+    e = t5 ^ t13
+
+/* 17 terms */
+
+#define ib1(a,b,c,d,e,f,g,h)    \
+    t1 = a ^ d;     \
+    t2 = a & b;     \
+    t3 = b ^ c;     \
+    t4 = a ^ t3;    \
+    t5 = b | d;     \
+    t7 = c | t1;    \
+    h = t4 ^ t5;    \
+    t8 = b ^ t7;    \
+    t11 = ~t2;      \
+    t9 = t4 & t8;   \
+    f = t1 ^ t9;    \
+    t13 = t9 ^ t11; \
+    t12 = h & f;    \
+    g = t12 ^ t13;  \
+    t15 = a & d;    \
+    t16 = c ^ t13;  \
+    e = t15 ^ t16
+
+/* 16 terms */
+
+#define sb2(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = b ^ d;     \
+    t3 = c & t1;    \
+    t13 = d | t1;   \
+    e = t2 ^ t3;    \
+    t5 = c ^ t1;    \
+    t6 = c ^ e;     \
+    t7 = b & t6;    \
+    t10 = e | t5;   \
+    h = t5 ^ t7;    \
+    t9 = d | t7;    \
+    t11 = t9 & t10; \
+    t14 = t2 ^ h;   \
+    g = a ^ t11;    \
+    t15 = g ^ t13;  \
+    f = t14 ^ t15
+
+/* 16 terms */
+
+#define ib2(a,b,c,d,e,f,g,h)    \
+    t1 = b ^ d;     \
+    t2 = ~t1;       \
+    t3 = a ^ c;     \
+    t4 = c ^ t1;    \
+    t7 = a | t2;    \
+    t5 = b & t4;    \
+    t8 = d ^ t7;    \
+    t11 = ~t4;      \
+    e = t3 ^ t5;    \
+    t9 = t3 | t8;   \
+    t14 = d & t11;  \
+    h = t1 ^ t9;    \
+    t12 = e | h;    \
+    f = t11 ^ t12;  \
+    t15 = t3 ^ t12; \
+    g = t14 ^ t15
+
+/* 17 terms */
+
+#define sb3(a,b,c,d,e,f,g,h)    \
+    t1 = a ^ c;     \
+    t2 = d ^ t1;    \
+    t3 = a & t2;    \
+    t4 = d ^ t3;    \
+    t5 = b & t4;    \
+    g = t2 ^ t5;    \
+    t7 = a | g;     \
+    t8 = b | d;     \
+    t11 = a | d;    \
+    t9 = t4 & t7;   \
+    f = t8 ^ t9;    \
+    t12 = b ^ t11;  \
+    t13 = g ^ t9;   \
+    t15 = t3 ^ t8;  \
+    h = t12 ^ t13;  \
+    t16 = c & t15;  \
+    e = t12 ^ t16
+
+/* 16 term solution that performs less well than 17 term one
+   in my environment (PPro/PII)                                  
+
+#define sb3(a,b,c,d,e,f,g,h)    \
+    t1 = a ^ b;     \
+    t2 = a & c;     \
+    t3 = a | d;     \
+    t4 = c ^ d;     \
+    t5 = t1 & t3;   \
+    t6 = t2 | t5;   \
+    g = t4 ^ t6;    \
+    t8 = b ^ t3;    \
+    t9 = t6 ^ t8;   \
+    t10 = t4 & t9;  \
+    e = t1 ^ t10;   \
+    t12 = g & e;    \
+    f = t9 ^ t12;   \
+    t14 = b | d;    \
+    t15 = t4 ^ t12; \
+    h = t14 ^ t15
+*/
+
+/* 17 terms */
+
+#define ib3(a,b,c,d,e,f,g,h)    \
+    t1 = b ^ c;     \
+    t2 = b | c;     \
+    t3 = a ^ c;     \
+    t7 = a ^ d;     \
+    t4 = t2 ^ t3;   \
+    t5 = d | t4;    \
+    t9 = t2 ^ t7;   \
+    e = t1 ^ t5;    \
+    t8 = t1 | t5;   \
+    t11 = a & t4;   \
+    g = t8 ^ t9;    \
+    t12 = e | t9;   \
+    f = t11 ^ t12;  \
+    t14 = a & g;    \
+    t15 = t2 ^ t14; \
+    t16 = e & t15;  \
+    h = t4 ^ t16
+
+/* 15 terms */
+
+#define sb4(a,b,c,d,e,f,g,h)    \
+    t1 = a ^ d;     \
+    t2 = d & t1;    \
+    t3 = c ^ t2;    \
+    t4 = b | t3;    \
+    h = t1 ^ t4;    \
+    t6 = ~b;        \
+    t7 = t1 | t6;   \
+    e = t3 ^ t7;    \
+    t9 = a & e;     \
+    t10 = t1 ^ t6;  \
+    t11 = t4 & t10; \
+    g = t9 ^ t11;   \
+    t13 = a ^ t3;   \
+    t14 = t10 & g;  \
+    f = t13 ^ t14
+
+/* 17 terms */
+
+#define ib4(a,b,c,d,e,f,g,h)    \
+    t1 = c ^ d;     \
+    t2 = c | d;     \
+    t3 = b ^ t2;    \
+    t4 = a & t3;    \
+    f = t1 ^ t4;    \
+    t6 = a ^ d;     \
+    t7 = b | d;     \
+    t8 = t6 & t7;   \
+    h = t3 ^ t8;    \
+    t10 = ~a;       \
+    t11 = c ^ h;    \
+    t12 = t10 | t11;\
+    e = t3 ^ t12;   \
+    t14 = c | t4;   \
+    t15 = t7 ^ t14; \
+    t16 = h | t10;  \
+    g = t15 ^ t16
+
+/* 16 terms */
+
+#define sb5(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = a ^ b;     \
+    t3 = a ^ d;     \
+    t4 = c ^ t1;    \
+    t5 = t2 | t3;   \
+    e = t4 ^ t5;    \
+    t7 = d & e;     \
+    t8 = t2 ^ e;    \
+    t10 = t1 | e;   \
+    f = t7 ^ t8;    \
+    t11 = t2 | t7;  \
+    t12 = t3 ^ t10; \
+    t14 = b ^ t7;   \
+    g = t11 ^ t12;  \
+    t15 = f & t12;  \
+    h = t14 ^ t15
+
+/* 16 terms */
+
+#define ib5(a,b,c,d,e,f,g,h)    \
+    t1 = ~c;        \
+    t2 = b & t1;    \
+    t3 = d ^ t2;    \
+    t4 = a & t3;    \
+    t5 = b ^ t1;    \
+    h = t4 ^ t5;    \
+    t7 = b | h;     \
+    t8 = a & t7;    \
+    f = t3 ^ t8;    \
+    t10 = a | d;    \
+    t11 = t1 ^ t7;  \
+    e = t10 ^ t11;  \
+    t13 = a ^ c;    \
+    t14 = b & t10;  \
+    t15 = t4 | t13; \
+    g = t14 ^ t15
+
+/* 15 terms */
+
+#define sb6(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = a ^ d;     \
+    t3 = b ^ t2;    \
+    t4 = t1 | t2;   \
+    t5 = c ^ t4;    \
+    f = b ^ t5;     \
+    t13 = ~t5;      \
+    t7 = t2 | f;    \
+    t8 = d ^ t7;    \
+    t9 = t5 & t8;   \
+    g = t3 ^ t9;    \
+    t11 = t5 ^ t8;  \
+    e = g ^ t11;    \
+    t14 = t3 & t11; \
+    h = t13 ^ t14
+
+/* 15 terms */
+
+#define ib6(a,b,c,d,e,f,g,h)    \
+    t1 = ~a;        \
+    t2 = a ^ b;     \
+    t3 = c ^ t2;    \
+    t4 = c | t1;    \
+    t5 = d ^ t4;    \
+    t13 = d & t1;   \
+    f = t3 ^ t5;    \
+    t7 = t3 & t5;   \
+    t8 = t2 ^ t7;   \
+    t9 = b | t8;    \
+    h = t5 ^ t9;    \
+    t11 = b | h;    \
+    e = t8 ^ t11;   \
+    t14 = t3 ^ t11; \
+    g = t13 ^ t14
+
+/* 17 terms */
+
+#define sb7(a,b,c,d,e,f,g,h)    \
+    t1 = ~c;        \
+    t2 = b ^ c;     \
+    t3 = b | t1;    \
+    t4 = d ^ t3;    \
+    t5 = a & t4;    \
+    t7 = a ^ d;     \
+    h = t2 ^ t5;    \
+    t8 = b ^ t5;    \
+    t9 = t2 | t8;   \
+    t11 = d & t3;   \
+    f = t7 ^ t9;    \
+    t12 = t5 ^ f;   \
+    t15 = t1 | t4;  \
+    t13 = h & t12;  \
+    g = t11 ^ t13;  \
+    t16 = t12 ^ g;  \
+    e = t15 ^ t16
+
+/* 17 terms */
+
+#define ib7(a,b,c,d,e,f,g,h)    \
+    t1 = a & b;     \
+    t2 = a | b;     \
+    t3 = c | t1;    \
+    t4 = d & t2;    \
+    h = t3 ^ t4;    \
+    t6 = ~d;        \
+    t7 = b ^ t4;    \
+    t8 = h ^ t6;    \
+    t11 = c ^ t7;   \
+    t9 = t7 | t8;   \
+    f = a ^ t9;     \
+    t12 = d | f;    \
+    e = t11 ^ t12;  \
+    t14 = a & h;    \
+    t15 = t3 ^ f;   \
+    t16 = e ^ t14;  \
+    g = t15 ^ t16
+
+#define k_xor(r,a,b,c,d)             \
+    a ^= skey->serpent.K[4 * (r) + 0]; \
+    b ^= skey->serpent.K[4 * (r) + 1]; \
+    c ^= skey->serpent.K[4 * (r) + 2]; \
+    d ^= skey->serpent.K[4 * (r) + 3]
+
+#define k_set(r,a,b,c,d)   \
+    a = lkey[4 * (r) +  8];  \
+    b = lkey[4 * (r) +  9];  \
+    c = lkey[4 * (r) + 10];  \
+    d = lkey[4 * (r) + 11]
+
+#define k_get(r,a,b,c,d)            \
+    skey->serpent.K[4 * (r) + 0] = a; \
+    skey->serpent.K[4 * (r) + 1] = b; \
+    skey->serpent.K[4 * (r) + 2] = c; \
+    skey->serpent.K[4 * (r) + 3] = d
+
+/* the linear transformation and its inverse    */
+
+#define rot(a,b,c,d)    \
+    a = ROL(a, 13);    \
+    c = ROL(c, 3);     \
+    d ^= c ^ (a << 3);  \
+    b ^= a ^ c;         \
+    d = ROL(d, 7);     \
+    b = ROL(b, 1);     \
+    a ^= b ^ d;         \
+    c ^= d ^ (b << 7);  \
+    a = ROL(a, 5);     \
+    c = ROL(c, 22)
+
+#define irot(a,b,c,d)   \
+    c = ROR(c, 22);    \
+    a = ROR(a, 5);     \
+    c ^= d ^ (b << 7);  \
+    a ^= b ^ d;         \
+    d = ROR(d, 7);     \
+    b = ROR(b, 1);     \
+    d ^= c ^ (a << 3);  \
+    b ^= a ^ c;         \
+    c = ROR(c, 3);     \
+    a = ROR(a, 13)
+    
+#ifdef CLEAN_STACK
+static int _serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+    unsigned long lkey[140], t, a, b, c, d, e, f, g, h, x;
+    unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
+    unsigned char buf[32];
+
+    _ARGCHK(key != NULL);
+    _ARGCHK(skey != NULL);
+
+    /* check rounds */
+    if (num_rounds != 0 && num_rounds != 32) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* check keylen */
+    if (keylen < 16 || keylen > 32) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    /* copy key and expand to 32bytes as required */
+    for (x = 0; x < (unsigned long)keylen; x++) {
+        buf[x] = key[x];
+    }
+
+    if (x < 32) {
+       buf[x++] = 0x01;
+       while (x < 32) {
+           buf[x++] = 0;
+       }
+    }
+
+    /* copy key into 32-bit words */
+    for (x = 0; x < 8; x++) {
+        LOAD32L(lkey[x], &buf[x*4]);
+    }
+
+    /* expand using the LFSR to 140 words */
+    for (x = 0; x < 132; x++) {
+        t = lkey[x] ^ lkey[x+3] ^ lkey[x+5] ^ lkey[x+7] ^ x ^ 0x9E3779B9UL;
+        lkey[x + 8] = ROL(t, 11);
+    }
+
+    /* perform the substituions */
+    for (x = 0; x < 32; ) {
+       k_set( x,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+       k_set( x,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
+    }
+    k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h);
+    return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _serpent_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(unsigned long)*166 + sizeof(unsigned char)*32);
+   return x;
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+    unsigned long a,b,c,d,e,f,g,h;
+    unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(skey != NULL);
+
+    LOAD32L(a, &pt[0]);LOAD32L(b, &pt[4]);LOAD32L(c, &pt[8]);LOAD32L(d, &pt[12]);
+    k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); 
+    k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
+    k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
+    k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d);
+    STORE32L(a, &ct[0]);STORE32L(b, &ct[4]);STORE32L(c, &ct[8]);STORE32L(d, &ct[12]);
+}
+
+#ifdef CLEAN_STACK
+void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   _serpent_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(unsigned long)*24);
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+    unsigned long a,b,c,d,e,f,g,h;
+    unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(skey != NULL);
+
+    LOAD32L(a, &ct[0]);LOAD32L(b, &ct[4]);LOAD32L(c, &ct[8]);LOAD32L(d, &ct[12]);
+    k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h);
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d);
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h);
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d);
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h);
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d);
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h);
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d);
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h);
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d);
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h);
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d);
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h);
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d);
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h);
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d);
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h);
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d);
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h);
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d);
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h);
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d);
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h);
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d);
+    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h);
+    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d);
+    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h);
+    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d);
+    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h);
+    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d);
+    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h);
+    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d);
+    STORE32L(a, &pt[0]);STORE32L(b, &pt[4]);STORE32L(c, &pt[8]);STORE32L(d, &pt[12]);
+}
+
+#ifdef CLEAN_STACK
+void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   _serpent_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(unsigned long)*24);
+}
+#endif
+
+int serpent_test(void)
+{
+   static const struct {
+       int keylen;
+       unsigned char key[32], pt[16], ct[16];
+   } tests[] = {
+   {
+      16,
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0xdd, 0xd2, 0x6b, 0x98, 0xa5, 0xff, 0xd8, 0x2c,
+        0x05, 0x34, 0x5a, 0x9d, 0xad, 0xbf, 0xaf, 0x49 }
+   },
+   {
+      16,
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
+      { 0x4a, 0xe9, 0xa2, 0x0b, 0x2b, 0x14, 0xa1, 0x02,
+        0x90, 0xcb, 0xb8, 0x20, 0xb7, 0xff, 0xb5, 0x10 }
+   },
+   {
+      24,
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 },
+      { 0xe1, 0x1b, 0x01, 0x52, 0x4e, 0xa1, 0xf4, 0x65, 
+        0xa2, 0xa2, 0x00, 0x43, 0xeb, 0x9f, 0x7e, 0x8a }
+   },
+   {
+      32,
+      { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0xe0, 0x88, 0x5d, 0x44, 0x60, 0x37, 0x34, 0x69,
+        0xd1, 0xfa, 0x6c, 0x36, 0xa6, 0xe1, 0xc5, 0x2f }
+   },
+   {
+      32,
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x17, 0xc6, 0x25, 0x8e, 0x60, 0x09, 0xe2, 0x82,
+        0x66, 0x18, 0x69, 0xd5, 0x25, 0xf7, 0xd2, 0x04 }
+   },
+   {
+      32,
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+      { 0x9f, 0xe1, 0x43, 0x25, 0x0d, 0x00, 0xe2, 0x56, 
+        0x96, 0xb0, 0x1e, 0x0a, 0x2e, 0xd0, 0x5d, 0xb3 }
+   }
+   };
+
+   unsigned char buf[2][16];
+   int x, failed, errno;
+   symmetric_key key;
+
+   for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((errno = serpent_setup(tests[x].key, tests[x].keylen, 0, &key))!= CRYPT_OK) {
+         return errno;
+      }
+
+      /* encrypt and decrypt */
+      serpent_ecb_encrypt(tests[x].pt, buf[0], &key);
+      serpent_ecb_decrypt(buf[0], buf[1], &key);
+
+      /* compare */
+      if (memcmp(buf[0], tests[x].ct, 16)) {
+#if 0
+         int y;
+         printf("\nEncrypt test %d failed\n", x);
+         for (y = 0; y < 16; y++) printf("%02x ", buf[0][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+
+      if (memcmp(buf[1], tests[x].pt, 16)) {
+#if 0
+         int y;
+         printf("\nDecrypt test %d failed\n", x);
+         for (y = 0; y < 16; y++) printf("%02x ", buf[1][y]);
+         printf("\n");
+#endif
+         failed = 1;
+      }
+   }
+
+   if (failed == 1) {
+      return CRYPT_FAIL_TESTVECTOR;
+   } else {
+      return CRYPT_OK;
+   }
+}
+
+int serpent_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize != NULL);
+
+   if (*desired_keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*desired_keysize > 32)
+      *desired_keysize = 32;
+   return CRYPT_OK;
+}
+
+#endif
+
+

+ 232 - 0
sha1.c

@@ -0,0 +1,232 @@
+#include "mycrypt.h"
+
+#ifdef SHA1
+
+const struct _hash_descriptor sha1_desc =
+{
+    "sha1",
+    2,
+    20,
+    64,
+    &sha1_init,
+    &sha1_process,
+    &sha1_done,
+    &sha1_test
+};
+
+#define F0(x,y,z)  ( (x&y) | ((~x)&z) )
+#define F1(x,y,z)  (x ^ y ^ z)
+#define F2(x,y,z)  ((x & y) | (z & (x | y)))
+#define F3(x,y,z)  (x ^ y ^ z)
+
+#ifdef CLEAN_STACK
+static void _sha1_compress(hash_state *md)
+#else
+static void sha1_compress(hash_state *md)
+#endif
+{
+    unsigned long a,b,c,d,e,W[80],i,j;
+
+    _ARGCHK(md != NULL);
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32H(W[i], md->sha1.buf + (4*i));
+    }
+
+    /* copy state */
+    a = md->sha1.state[0];
+    b = md->sha1.state[1];
+    c = md->sha1.state[2];
+    d = md->sha1.state[3];
+    e = md->sha1.state[4];
+
+    /* 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);
+    }
+
+    /* 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; 
+    }
+
+    /* 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; 
+    }
+
+    /* 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; 
+    }
+
+    /* 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;
+    }
+
+    /* store */
+    md->sha1.state[0] = md->sha1.state[0] + a;
+    md->sha1.state[1] = md->sha1.state[1] + b;
+    md->sha1.state[2] = md->sha1.state[2] + c;
+    md->sha1.state[3] = md->sha1.state[3] + d;
+    md->sha1.state[4] = md->sha1.state[4] + e;
+}
+
+#ifdef CLEAN_STACK
+static void sha1_compress(hash_state *md)
+{
+   _sha1_compress(md);
+   burn_stack(sizeof(unsigned long) * 87);
+}
+#endif
+
+void sha1_init(hash_state * md)
+{
+   _ARGCHK(md != NULL);
+   md->sha1.state[0] = 0x67452301UL;
+   md->sha1.state[1] = 0xefcdab89UL;
+   md->sha1.state[2] = 0x98badcfeUL;
+   md->sha1.state[3] = 0x10325476UL;
+   md->sha1.state[4] = 0xc3d2e1f0UL;
+   md->sha1.curlen = 0;
+   md->sha1.length = 0;
+}
+
+void sha1_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+
+    while (len) {
+        n = MIN(len, (64 - md->sha1.curlen));
+        memcpy(md->sha1.buf + md->sha1.curlen, buf, n);
+        md->sha1.curlen += n;
+        buf             += n;
+        len             -= n;
+
+        /* is 64 bytes full? */
+        if (md->sha1.curlen == 64) {
+            sha1_compress(md);
+            md->sha1.length += 512;
+            md->sha1.curlen = 0;
+        }
+    }
+}
+
+void sha1_done(hash_state * md, unsigned char *hash)
+{
+    int i;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->sha1.length += md->sha1.curlen * 8;
+
+    /* append the '1' bit */
+    md->sha1.buf[md->sha1.curlen++] = 0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha1.curlen > 56) {
+        while (md->sha1.curlen < 64) {
+            md->sha1.buf[md->sha1.curlen++] = 0;
+        }
+        sha1_compress(md);
+        md->sha1.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->sha1.curlen < 56) {
+        md->sha1.buf[md->sha1.curlen++] = 0;
+    }
+
+    /* store length */
+    STORE64H(md->sha1.length, md->sha1.buf+56);
+    sha1_compress(md);
+
+    /* copy output */
+    for (i = 0; i < 5; i++) {
+        STORE32H(md->sha1.state[i], hash+(4*i));
+    }
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int  sha1_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[20];
+  } tests[] = {
+    { "abc",
+      { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+        0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+        0x9c, 0xd0, 0xd8, 0x9d }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+        0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+        0xE5, 0x46, 0x70, 0xF1 }
+    }, 
+    { NULL, { 0 }}
+  };
+
+  int failed, i;
+  unsigned char tmp[20];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      sha1_init(&md);
+      sha1_process(&md, tests[i].msg, strlen(tests[i].msg));
+      sha1_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 20)) {
+#if 0
+         int j;
+         printf("\nSHA-1 Test %d failed\nGot (as a result): ", i);
+         for (j = 0; j < 20; j++) {
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+#endif
+
+

+ 229 - 0
sha256.c

@@ -0,0 +1,229 @@
+#include "mycrypt.h"
+
+#ifdef SHA256 
+
+const struct _hash_descriptor sha256_desc =
+{
+    "sha256",
+    0,
+    32,
+    64,
+    &sha256_init,
+    &sha256_process,
+    &sha256_done,
+    &sha256_test
+};
+
+/* the K array */
+static const unsigned long K[64] = {
+    0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+    0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+    0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+    0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+    0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+    0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+    0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+    0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+    0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+    0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+    0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+    0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+    0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+#define Ch(x,y,z)       ((x & y) ^ (~x & z))
+#define Maj(x,y,z)      ((x & y) ^ (x & z) ^ (y & z))
+#define S(x, n)	        ROR((x),(n))
+#define R(x, n)	        (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+/* compress 512-bits */
+#ifdef CLEAN_STACK
+static void _sha256_compress(hash_state * md)
+#else
+static void sha256_compress(hash_state * md)
+#endif
+{
+    unsigned long S[8], W[64], t0, t1;
+    int i;
+
+    _ARGCHK(md != NULL);
+
+    /* copy state into S */
+    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++) {
+        LOAD32H(W[i], md->sha256.buf + (4*i));
+    }
+
+    /* fill W[16..63] */
+    for (i = 16; i < 64; i++)
+        W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+
+    /* Compress */
+    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]);
+        S[7] = S[6];
+        S[6] = S[5];
+        S[5] = S[4];
+        S[4] = S[3] + t0;
+        S[3] = S[2];
+        S[2] = S[1];
+        S[1] = S[0];
+        S[0] = t0 + t1;
+    }
+
+    /* feedback */
+    for (i = 0; i < 8; i++) {
+        md->sha256.state[i] = md->sha256.state[i] + S[i];
+    }
+}
+
+#ifdef CLEAN_STACK
+static void sha256_compress(hash_state * md)
+{
+    _sha256_compress(md);
+    burn_stack(sizeof(unsigned long) * 74);
+}
+#endif
+
+/* init the sha256 state */
+void sha256_init(hash_state * md)
+{
+    _ARGCHK(md != NULL);
+
+    md->sha256.curlen = 0;
+    md->sha256.length = 0;
+    md->sha256.state[0] = 0x6A09E667UL;
+    md->sha256.state[1] = 0xBB67AE85UL;
+    md->sha256.state[2] = 0x3C6EF372UL;
+    md->sha256.state[3] = 0xA54FF53AUL;
+    md->sha256.state[4] = 0x510E527FUL;
+    md->sha256.state[5] = 0x9B05688CUL;
+    md->sha256.state[6] = 0x1F83D9ABUL;
+    md->sha256.state[7] = 0x5BE0CD19UL;
+}
+
+void sha256_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+
+    while (len) {
+        n = MIN(len, (64 - md->sha256.curlen));
+        memcpy(md->sha256.buf + md->sha256.curlen, buf, n);
+        md->sha256.curlen += n;
+        buf            += n;
+        len            -= n;
+
+        /* is 64 bytes full? */
+        if (md->sha256.curlen == 64) {
+            sha256_compress(md);
+            md->sha256.length += 512;
+            md->sha256.curlen = 0;
+        }
+    }
+}
+
+void sha256_done(hash_state * md, unsigned char *hash)
+{
+    int i;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->sha256.length += md->sha256.curlen * 8;
+
+    /* append the '1' bit */
+    md->sha256.buf[md->sha256.curlen++] = 0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha256.curlen > 56) {
+        while (md->sha256.curlen < 64) {
+            md->sha256.buf[md->sha256.curlen++] = 0;
+        }
+        sha256_compress(md);
+        md->sha256.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->sha256.curlen < 56) {
+        md->sha256.buf[md->sha256.curlen++] = 0;
+    }
+
+    /* store length */
+    STORE64H(md->sha256.length, md->sha256.buf+56);
+    sha256_compress(md);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE32H(md->sha256.state[i], hash+(4*i));
+    }
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int  sha256_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[32];
+  } tests[] = {
+    { "abc",
+      { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+        0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+        0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+        0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 
+        0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+        0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 
+        0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }
+    },
+    { NULL, { 0 } }
+  };
+
+  int failed, i;
+  unsigned char tmp[32];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      sha256_init(&md);
+      sha256_process(&md, tests[i].msg, strlen(tests[i].msg));
+      sha256_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 32)) {
+#if 0
+         int j;
+         printf("\nSHA-256 Test %d failed\nGot (as a result): ", i);
+         for (j = 0; j < 32; j++) {
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+#endif
+
+

+ 107 - 0
sha384.c

@@ -0,0 +1,107 @@
+/* included in sha512.c */
+
+const struct _hash_descriptor sha384_desc =
+{
+    "sha384",
+    4,
+    48,
+    128,
+    &sha384_init,
+    &sha384_process,
+    &sha384_done,
+    &sha384_test
+};
+
+void sha384_init(hash_state * md)
+{
+    _ARGCHK(md != NULL);
+
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0xcbbb9d5dc1059ed8);
+    md->sha512.state[1] = CONST64(0x629a292a367cd507);
+    md->sha512.state[2] = CONST64(0x9159015a3070dd17);
+    md->sha512.state[3] = CONST64(0x152fecd8f70e5939);
+    md->sha512.state[4] = CONST64(0x67332667ffc00b31);
+    md->sha512.state[5] = CONST64(0x8eb44a8768581511);
+    md->sha512.state[6] = CONST64(0xdb0c2e0d64f98fa7);
+    md->sha512.state[7] = CONST64(0x47b5481dbefa4fa4);
+}
+
+void sha384_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+   _ARGCHK(md != NULL);
+   _ARGCHK(buf != NULL);
+   sha512_process(md, buf, len);
+}
+
+void sha384_done(hash_state * md, unsigned char *hash)
+{
+   unsigned char buf[64];
+
+   _ARGCHK(md != NULL);
+   _ARGCHK(hash != NULL);
+
+   sha512_done(md, buf);
+   memcpy(hash, buf, 48);
+#ifdef CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+}
+
+int  sha384_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[48];
+  } tests[] = {
+    { "abc",
+      { 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
+        0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
+        0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+        0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
+        0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
+        0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+      { 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8,
+        0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47,
+        0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2,
+        0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12,
+        0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9,
+        0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 }
+    },
+    { NULL, { 0 }}
+  };
+
+  int failed, i;
+  unsigned char tmp[48];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      sha384_init(&md);
+      sha384_process(&md, tests[i].msg, strlen(tests[i].msg));
+      sha384_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 48)) {
+#if 0
+         int j;
+         printf("\nSHA-384 Test %d failed\nGot (as a result): ", i);
+         for (j = 0; j < 48; j++) {
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+
+
+
+

+ 272 - 0
sha512.c

@@ -0,0 +1,272 @@
+#include "mycrypt.h"
+
+#ifdef SHA512
+
+const struct _hash_descriptor sha512_desc =
+{
+    "sha512",
+    5,
+    64,
+    128,
+    &sha512_init,
+    &sha512_process,
+    &sha512_done,
+    &sha512_test
+};
+
+/* the K array */
+static const ulong64 K[80] = {
+CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), 
+CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), 
+CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), 
+CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), 
+CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), 
+CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), 
+CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), 
+CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), 
+CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), 
+CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), 
+CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), 
+CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), 
+CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), 
+CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), 
+CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), 
+CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), 
+CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), 
+CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), 
+CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), 
+CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z)       ((x & y) ^ (~x & z))
+#define Maj(x,y,z)      ((x & y) ^ (x & z) ^ (y & z))
+#define S(x, n)         ROR64((x),(n))
+#define R(x, n)         (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)n))
+#define Sigma0(x)       (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x)       (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x)       (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x)       (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+
+/* compress 1024-bits */
+#ifdef CLEAN_STACK
+static void _sha512_compress(hash_state * md)
+#else
+static void sha512_compress(hash_state * md)
+#endif
+{
+    ulong64 S[8], W[80], t0, t1;
+    int i;
+
+    _ARGCHK(md != NULL);
+
+    /* copy state into S */
+    for (i = 0; i < 8; i++)
+        S[i] = md->sha512.state[i];
+
+    /* copy the state into 1024-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD64H(W[i], md->sha512.buf + (8*i));
+    }
+
+    /* fill W[16..79] */
+    for (i = 16; i < 80; i++)
+        W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+
+    /* Compress */
+    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]);
+        S[7] = S[6];
+        S[6] = S[5];
+        S[5] = S[4];
+        S[4] = S[3] + t0;
+        S[3] = S[2];
+        S[2] = S[1];
+        S[1] = S[0];
+        S[0] = t0 + t1;
+    }
+
+    /* feedback */
+    for (i = 0; i < 8; i++) {
+        md->sha512.state[i] = md->sha512.state[i] + S[i];
+    }
+}
+
+/* compress 1024-bits */
+#ifdef CLEAN_STACK
+static void sha512_compress(hash_state * md)
+{
+    _sha512_compress(md);
+    burn_stack(sizeof(ulong64) * 90 + sizeof(int));
+}
+#endif
+
+/* init the sha512 state */
+void sha512_init(hash_state * md)
+{
+    _ARGCHK(md != NULL);
+
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0x6a09e667f3bcc908);
+    md->sha512.state[1] = CONST64(0xbb67ae8584caa73b);
+    md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b);
+    md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1);
+    md->sha512.state[4] = CONST64(0x510e527fade682d1);
+    md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f);
+    md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b);
+    md->sha512.state[7] = CONST64(0x5be0cd19137e2179);
+}
+
+void sha512_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+    while (len) {
+        n = MIN(len, (128 - md->sha512.curlen));
+        memcpy(md->sha512.buf + md->sha512.curlen, buf, n);
+        md->sha512.curlen += n;
+        buf               += n;
+        len               -= n;
+
+        /* is 64 bytes full? */
+        if (md->sha512.curlen == 128) {
+            sha512_compress(md);
+            md->sha512.length += 1024;
+            md->sha512.curlen = 0;
+        }
+    }
+}
+
+void sha512_done(hash_state * md, unsigned char *hash)
+{
+    int i;
+
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->sha512.length += md->sha512.curlen * CONST64(8);
+
+    /* append the '1' bit */
+    md->sha512.buf[md->sha512.curlen++] = 0x80;
+
+    /* if the length is currently above 112 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha512.curlen > 112) {
+        while (md->sha512.curlen < 128) {
+            md->sha512.buf[md->sha512.curlen++] = 0;
+        }
+        sha512_compress(md);
+        md->sha512.curlen = 0;
+    }
+
+    /* pad upto 120 bytes of zeroes 
+     * note: that from 112 to 120 is the 64 MSB of the length.  We assume that you won't hash
+     * > 2^64 bits of data... :-)
+     */
+    while (md->sha512.curlen < 120) {
+        md->sha512.buf[md->sha512.curlen++] = 0;
+    }
+
+    /* store length */
+    STORE64H(md->sha512.length, md->sha512.buf+120);
+    sha512_compress(md);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE64H(md->sha512.state[i], hash+(8*i));
+    }
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int  sha512_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[64];
+  } tests[] = {
+    { "abc",
+     { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
+       0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
+       0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+       0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
+       0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
+       0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+       0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
+       0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+     { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
+       0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
+       0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
+       0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
+       0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
+       0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
+       0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
+       0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 }
+    },
+    { NULL, { 0 }}
+  };
+
+  int failed, i;
+  unsigned char tmp[64];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      sha512_init(&md);
+      sha512_process(&md, tests[i].msg, strlen(tests[i].msg));
+      sha512_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 64)) {
+#if 0
+         int j;
+         printf("\nSHA-512 Test %d failed\nGot (as a result): ", i);
+         for (j = 0; j < 64; j++) {
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+#ifdef SHA384
+   #include "sha384.c"
+#endif
+
+#endif
+
+
+

+ 42 - 0
sprng.c

@@ -0,0 +1,42 @@
+/* A secure PRNG using the RNG functions.  Basically this is a
+ * wrapper that allows you to use a secure RNG as a PRNG
+ * in the various other functions.
+ */
+#include "mycrypt.h"
+
+#ifdef SPRNG
+
+const struct _prng_descriptor sprng_desc =
+{
+    "sprng",
+    &sprng_start,
+    &sprng_add_entropy,
+    &sprng_ready,
+    &sprng_read
+};
+
+int sprng_start(prng_state *prng)
+{
+   return CRYPT_OK;  
+}
+
+int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
+{
+   return CRYPT_OK;
+}
+
+int sprng_ready(prng_state *prng)
+{
+   return CRYPT_OK;
+}
+
+unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng)
+{
+   _ARGCHK(buf != NULL);
+   return rng_get_bytes(buf, len, NULL);
+}
+
+#endif
+
+
+ 

+ 47 - 0
strings.c

@@ -0,0 +1,47 @@
+/* Future releases will make use of this */
+#include "mycrypt.h"
+
+static const char *err_2_str[] =
+{
+   "CRYPT_OK",
+   "CRYPT_ERROR",
+
+   "Invalid keysize for block cipher.",
+   "Invalid number of rounds for block cipher.",
+   "Algorithm failed test vectors.",
+
+   "Buffer overflow.",
+   "Invalid input packet.",
+
+   "Invalid number of bits for a PRNG.",
+   "Error reading the PRNG.",
+
+   "Invalid cipher specified.",
+   "Invalid hash specified.",
+   "Invalid PRNG specified.",
+
+   "Out of memory.",
+
+   "Invalid PK key or key type specified for function.",
+   "A private PK key is required.",
+
+   "Invalid argument provided.",
+
+   "Invalid PK type.",
+   "Invalid PK system.",
+   "Duplicate PK key found on keyring.",
+   "Key not found in keyring.",
+   "Invalid sized parameter.",
+
+   "Invalid size for prime."
+};
+
+const char *error_to_string(int errno)
+{
+   if (errno < 0 || errno > (int)(sizeof(err_2_str)/sizeof(err_2_str[0]))) {
+      return "Invalid error code.";
+   } else {
+      return err_2_str[errno];
+   }   
+}
+

+ 775 - 0
tiger.c

@@ -0,0 +1,775 @@
+#include "mycrypt.h"
+
+#ifdef TIGER
+
+const struct _hash_descriptor tiger_desc =
+{
+    "tiger",
+    1,
+    24,
+    64,
+    &tiger_init,
+    &tiger_process,
+    &tiger_done,
+    &tiger_test
+};
+
+#define t1 (table)
+#define t2 (table+256)
+#define t3 (table+256*2)
+#define t4 (table+256*3)
+
+#define save_abc  aa = a; bb = b; cc = c;
+
+static const ulong64 table[4*256] = {
+    CONST64(0x02AAB17CF7E90C5E) /*    0 */, CONST64(0xAC424B03E243A8EC) /*    1 */,
+    CONST64(0x72CD5BE30DD5FCD3) /*    2 */, CONST64(0x6D019B93F6F97F3A) /*    3 */,
+    CONST64(0xCD9978FFD21F9193) /*    4 */, CONST64(0x7573A1C9708029E2) /*    5 */,
+    CONST64(0xB164326B922A83C3) /*    6 */, CONST64(0x46883EEE04915870) /*    7 */,
+    CONST64(0xEAACE3057103ECE6) /*    8 */, CONST64(0xC54169B808A3535C) /*    9 */,
+    CONST64(0x4CE754918DDEC47C) /*   10 */, CONST64(0x0AA2F4DFDC0DF40C) /*   11 */,
+    CONST64(0x10B76F18A74DBEFA) /*   12 */, CONST64(0xC6CCB6235AD1AB6A) /*   13 */,
+    CONST64(0x13726121572FE2FF) /*   14 */, CONST64(0x1A488C6F199D921E) /*   15 */,
+    CONST64(0x4BC9F9F4DA0007CA) /*   16 */, CONST64(0x26F5E6F6E85241C7) /*   17 */,
+    CONST64(0x859079DBEA5947B6) /*   18 */, CONST64(0x4F1885C5C99E8C92) /*   19 */,
+    CONST64(0xD78E761EA96F864B) /*   20 */, CONST64(0x8E36428C52B5C17D) /*   21 */,
+    CONST64(0x69CF6827373063C1) /*   22 */, CONST64(0xB607C93D9BB4C56E) /*   23 */,
+    CONST64(0x7D820E760E76B5EA) /*   24 */, CONST64(0x645C9CC6F07FDC42) /*   25 */,
+    CONST64(0xBF38A078243342E0) /*   26 */, CONST64(0x5F6B343C9D2E7D04) /*   27 */,
+    CONST64(0xF2C28AEB600B0EC6) /*   28 */, CONST64(0x6C0ED85F7254BCAC) /*   29 */,
+    CONST64(0x71592281A4DB4FE5) /*   30 */, CONST64(0x1967FA69CE0FED9F) /*   31 */,
+    CONST64(0xFD5293F8B96545DB) /*   32 */, CONST64(0xC879E9D7F2A7600B) /*   33 */,
+    CONST64(0x860248920193194E) /*   34 */, CONST64(0xA4F9533B2D9CC0B3) /*   35 */,
+    CONST64(0x9053836C15957613) /*   36 */, CONST64(0xDB6DCF8AFC357BF1) /*   37 */,
+    CONST64(0x18BEEA7A7A370F57) /*   38 */, CONST64(0x037117CA50B99066) /*   39 */,
+    CONST64(0x6AB30A9774424A35) /*   40 */, CONST64(0xF4E92F02E325249B) /*   41 */,
+    CONST64(0x7739DB07061CCAE1) /*   42 */, CONST64(0xD8F3B49CECA42A05) /*   43 */,
+    CONST64(0xBD56BE3F51382F73) /*   44 */, CONST64(0x45FAED5843B0BB28) /*   45 */,
+    CONST64(0x1C813D5C11BF1F83) /*   46 */, CONST64(0x8AF0E4B6D75FA169) /*   47 */,
+    CONST64(0x33EE18A487AD9999) /*   48 */, CONST64(0x3C26E8EAB1C94410) /*   49 */,
+    CONST64(0xB510102BC0A822F9) /*   50 */, CONST64(0x141EEF310CE6123B) /*   51 */,
+    CONST64(0xFC65B90059DDB154) /*   52 */, CONST64(0xE0158640C5E0E607) /*   53 */,
+    CONST64(0x884E079826C3A3CF) /*   54 */, CONST64(0x930D0D9523C535FD) /*   55 */,
+    CONST64(0x35638D754E9A2B00) /*   56 */, CONST64(0x4085FCCF40469DD5) /*   57 */,
+    CONST64(0xC4B17AD28BE23A4C) /*   58 */, CONST64(0xCAB2F0FC6A3E6A2E) /*   59 */,
+    CONST64(0x2860971A6B943FCD) /*   60 */, CONST64(0x3DDE6EE212E30446) /*   61 */,
+    CONST64(0x6222F32AE01765AE) /*   62 */, CONST64(0x5D550BB5478308FE) /*   63 */,
+    CONST64(0xA9EFA98DA0EDA22A) /*   64 */, CONST64(0xC351A71686C40DA7) /*   65 */,
+    CONST64(0x1105586D9C867C84) /*   66 */, CONST64(0xDCFFEE85FDA22853) /*   67 */,
+    CONST64(0xCCFBD0262C5EEF76) /*   68 */, CONST64(0xBAF294CB8990D201) /*   69 */,
+    CONST64(0xE69464F52AFAD975) /*   70 */, CONST64(0x94B013AFDF133E14) /*   71 */,
+    CONST64(0x06A7D1A32823C958) /*   72 */, CONST64(0x6F95FE5130F61119) /*   73 */,
+    CONST64(0xD92AB34E462C06C0) /*   74 */, CONST64(0xED7BDE33887C71D2) /*   75 */,
+    CONST64(0x79746D6E6518393E) /*   76 */, CONST64(0x5BA419385D713329) /*   77 */,
+    CONST64(0x7C1BA6B948A97564) /*   78 */, CONST64(0x31987C197BFDAC67) /*   79 */,
+    CONST64(0xDE6C23C44B053D02) /*   80 */, CONST64(0x581C49FED002D64D) /*   81 */,
+    CONST64(0xDD474D6338261571) /*   82 */, CONST64(0xAA4546C3E473D062) /*   83 */,
+    CONST64(0x928FCE349455F860) /*   84 */, CONST64(0x48161BBACAAB94D9) /*   85 */,
+    CONST64(0x63912430770E6F68) /*   86 */, CONST64(0x6EC8A5E602C6641C) /*   87 */,
+    CONST64(0x87282515337DDD2B) /*   88 */, CONST64(0x2CDA6B42034B701B) /*   89 */,
+    CONST64(0xB03D37C181CB096D) /*   90 */, CONST64(0xE108438266C71C6F) /*   91 */,
+    CONST64(0x2B3180C7EB51B255) /*   92 */, CONST64(0xDF92B82F96C08BBC) /*   93 */,
+    CONST64(0x5C68C8C0A632F3BA) /*   94 */, CONST64(0x5504CC861C3D0556) /*   95 */,
+    CONST64(0xABBFA4E55FB26B8F) /*   96 */, CONST64(0x41848B0AB3BACEB4) /*   97 */,
+    CONST64(0xB334A273AA445D32) /*   98 */, CONST64(0xBCA696F0A85AD881) /*   99 */,
+    CONST64(0x24F6EC65B528D56C) /*  100 */, CONST64(0x0CE1512E90F4524A) /*  101 */,
+    CONST64(0x4E9DD79D5506D35A) /*  102 */, CONST64(0x258905FAC6CE9779) /*  103 */,
+    CONST64(0x2019295B3E109B33) /*  104 */, CONST64(0xF8A9478B73A054CC) /*  105 */,
+    CONST64(0x2924F2F934417EB0) /*  106 */, CONST64(0x3993357D536D1BC4) /*  107 */,
+    CONST64(0x38A81AC21DB6FF8B) /*  108 */, CONST64(0x47C4FBF17D6016BF) /*  109 */,
+    CONST64(0x1E0FAADD7667E3F5) /*  110 */, CONST64(0x7ABCFF62938BEB96) /*  111 */,
+    CONST64(0xA78DAD948FC179C9) /*  112 */, CONST64(0x8F1F98B72911E50D) /*  113 */,
+    CONST64(0x61E48EAE27121A91) /*  114 */, CONST64(0x4D62F7AD31859808) /*  115 */,
+    CONST64(0xECEBA345EF5CEAEB) /*  116 */, CONST64(0xF5CEB25EBC9684CE) /*  117 */,
+    CONST64(0xF633E20CB7F76221) /*  118 */, CONST64(0xA32CDF06AB8293E4) /*  119 */,
+    CONST64(0x985A202CA5EE2CA4) /*  120 */, CONST64(0xCF0B8447CC8A8FB1) /*  121 */,
+    CONST64(0x9F765244979859A3) /*  122 */, CONST64(0xA8D516B1A1240017) /*  123 */,
+    CONST64(0x0BD7BA3EBB5DC726) /*  124 */, CONST64(0xE54BCA55B86ADB39) /*  125 */,
+    CONST64(0x1D7A3AFD6C478063) /*  126 */, CONST64(0x519EC608E7669EDD) /*  127 */,
+    CONST64(0x0E5715A2D149AA23) /*  128 */, CONST64(0x177D4571848FF194) /*  129 */,
+    CONST64(0xEEB55F3241014C22) /*  130 */, CONST64(0x0F5E5CA13A6E2EC2) /*  131 */,
+    CONST64(0x8029927B75F5C361) /*  132 */, CONST64(0xAD139FABC3D6E436) /*  133 */,
+    CONST64(0x0D5DF1A94CCF402F) /*  134 */, CONST64(0x3E8BD948BEA5DFC8) /*  135 */,
+    CONST64(0xA5A0D357BD3FF77E) /*  136 */, CONST64(0xA2D12E251F74F645) /*  137 */,
+    CONST64(0x66FD9E525E81A082) /*  138 */, CONST64(0x2E0C90CE7F687A49) /*  139 */,
+    CONST64(0xC2E8BCBEBA973BC5) /*  140 */, CONST64(0x000001BCE509745F) /*  141 */,
+    CONST64(0x423777BBE6DAB3D6) /*  142 */, CONST64(0xD1661C7EAEF06EB5) /*  143 */,
+    CONST64(0xA1781F354DAACFD8) /*  144 */, CONST64(0x2D11284A2B16AFFC) /*  145 */,
+    CONST64(0xF1FC4F67FA891D1F) /*  146 */, CONST64(0x73ECC25DCB920ADA) /*  147 */,
+    CONST64(0xAE610C22C2A12651) /*  148 */, CONST64(0x96E0A810D356B78A) /*  149 */,
+    CONST64(0x5A9A381F2FE7870F) /*  150 */, CONST64(0xD5AD62EDE94E5530) /*  151 */,
+    CONST64(0xD225E5E8368D1427) /*  152 */, CONST64(0x65977B70C7AF4631) /*  153 */,
+    CONST64(0x99F889B2DE39D74F) /*  154 */, CONST64(0x233F30BF54E1D143) /*  155 */,
+    CONST64(0x9A9675D3D9A63C97) /*  156 */, CONST64(0x5470554FF334F9A8) /*  157 */,
+    CONST64(0x166ACB744A4F5688) /*  158 */, CONST64(0x70C74CAAB2E4AEAD) /*  159 */,
+    CONST64(0xF0D091646F294D12) /*  160 */, CONST64(0x57B82A89684031D1) /*  161 */,
+    CONST64(0xEFD95A5A61BE0B6B) /*  162 */, CONST64(0x2FBD12E969F2F29A) /*  163 */,
+    CONST64(0x9BD37013FEFF9FE8) /*  164 */, CONST64(0x3F9B0404D6085A06) /*  165 */,
+    CONST64(0x4940C1F3166CFE15) /*  166 */, CONST64(0x09542C4DCDF3DEFB) /*  167 */,
+    CONST64(0xB4C5218385CD5CE3) /*  168 */, CONST64(0xC935B7DC4462A641) /*  169 */,
+    CONST64(0x3417F8A68ED3B63F) /*  170 */, CONST64(0xB80959295B215B40) /*  171 */,
+    CONST64(0xF99CDAEF3B8C8572) /*  172 */, CONST64(0x018C0614F8FCB95D) /*  173 */,
+    CONST64(0x1B14ACCD1A3ACDF3) /*  174 */, CONST64(0x84D471F200BB732D) /*  175 */,
+    CONST64(0xC1A3110E95E8DA16) /*  176 */, CONST64(0x430A7220BF1A82B8) /*  177 */,
+    CONST64(0xB77E090D39DF210E) /*  178 */, CONST64(0x5EF4BD9F3CD05E9D) /*  179 */,
+    CONST64(0x9D4FF6DA7E57A444) /*  180 */, CONST64(0xDA1D60E183D4A5F8) /*  181 */,
+    CONST64(0xB287C38417998E47) /*  182 */, CONST64(0xFE3EDC121BB31886) /*  183 */,
+    CONST64(0xC7FE3CCC980CCBEF) /*  184 */, CONST64(0xE46FB590189BFD03) /*  185 */,
+    CONST64(0x3732FD469A4C57DC) /*  186 */, CONST64(0x7EF700A07CF1AD65) /*  187 */,
+    CONST64(0x59C64468A31D8859) /*  188 */, CONST64(0x762FB0B4D45B61F6) /*  189 */,
+    CONST64(0x155BAED099047718) /*  190 */, CONST64(0x68755E4C3D50BAA6) /*  191 */,
+    CONST64(0xE9214E7F22D8B4DF) /*  192 */, CONST64(0x2ADDBF532EAC95F4) /*  193 */,
+    CONST64(0x32AE3909B4BD0109) /*  194 */, CONST64(0x834DF537B08E3450) /*  195 */,
+    CONST64(0xFA209DA84220728D) /*  196 */, CONST64(0x9E691D9B9EFE23F7) /*  197 */,
+    CONST64(0x0446D288C4AE8D7F) /*  198 */, CONST64(0x7B4CC524E169785B) /*  199 */,
+    CONST64(0x21D87F0135CA1385) /*  200 */, CONST64(0xCEBB400F137B8AA5) /*  201 */,
+    CONST64(0x272E2B66580796BE) /*  202 */, CONST64(0x3612264125C2B0DE) /*  203 */,
+    CONST64(0x057702BDAD1EFBB2) /*  204 */, CONST64(0xD4BABB8EACF84BE9) /*  205 */,
+    CONST64(0x91583139641BC67B) /*  206 */, CONST64(0x8BDC2DE08036E024) /*  207 */,
+    CONST64(0x603C8156F49F68ED) /*  208 */, CONST64(0xF7D236F7DBEF5111) /*  209 */,
+    CONST64(0x9727C4598AD21E80) /*  210 */, CONST64(0xA08A0896670A5FD7) /*  211 */,
+    CONST64(0xCB4A8F4309EBA9CB) /*  212 */, CONST64(0x81AF564B0F7036A1) /*  213 */,
+    CONST64(0xC0B99AA778199ABD) /*  214 */, CONST64(0x959F1EC83FC8E952) /*  215 */,
+    CONST64(0x8C505077794A81B9) /*  216 */, CONST64(0x3ACAAF8F056338F0) /*  217 */,
+    CONST64(0x07B43F50627A6778) /*  218 */, CONST64(0x4A44AB49F5ECCC77) /*  219 */,
+    CONST64(0x3BC3D6E4B679EE98) /*  220 */, CONST64(0x9CC0D4D1CF14108C) /*  221 */,
+    CONST64(0x4406C00B206BC8A0) /*  222 */, CONST64(0x82A18854C8D72D89) /*  223 */,
+    CONST64(0x67E366B35C3C432C) /*  224 */, CONST64(0xB923DD61102B37F2) /*  225 */,
+    CONST64(0x56AB2779D884271D) /*  226 */, CONST64(0xBE83E1B0FF1525AF) /*  227 */,
+    CONST64(0xFB7C65D4217E49A9) /*  228 */, CONST64(0x6BDBE0E76D48E7D4) /*  229 */,
+    CONST64(0x08DF828745D9179E) /*  230 */, CONST64(0x22EA6A9ADD53BD34) /*  231 */,
+    CONST64(0xE36E141C5622200A) /*  232 */, CONST64(0x7F805D1B8CB750EE) /*  233 */,
+    CONST64(0xAFE5C7A59F58E837) /*  234 */, CONST64(0xE27F996A4FB1C23C) /*  235 */,
+    CONST64(0xD3867DFB0775F0D0) /*  236 */, CONST64(0xD0E673DE6E88891A) /*  237 */,
+    CONST64(0x123AEB9EAFB86C25) /*  238 */, CONST64(0x30F1D5D5C145B895) /*  239 */,
+    CONST64(0xBB434A2DEE7269E7) /*  240 */, CONST64(0x78CB67ECF931FA38) /*  241 */,
+    CONST64(0xF33B0372323BBF9C) /*  242 */, CONST64(0x52D66336FB279C74) /*  243 */,
+    CONST64(0x505F33AC0AFB4EAA) /*  244 */, CONST64(0xE8A5CD99A2CCE187) /*  245 */,
+    CONST64(0x534974801E2D30BB) /*  246 */, CONST64(0x8D2D5711D5876D90) /*  247 */,
+    CONST64(0x1F1A412891BC038E) /*  248 */, CONST64(0xD6E2E71D82E56648) /*  249 */,
+    CONST64(0x74036C3A497732B7) /*  250 */, CONST64(0x89B67ED96361F5AB) /*  251 */,
+    CONST64(0xFFED95D8F1EA02A2) /*  252 */, CONST64(0xE72B3BD61464D43D) /*  253 */,
+    CONST64(0xA6300F170BDC4820) /*  254 */, CONST64(0xEBC18760ED78A77A) /*  255 */,
+    CONST64(0xE6A6BE5A05A12138) /*  256 */, CONST64(0xB5A122A5B4F87C98) /*  257 */,
+    CONST64(0x563C6089140B6990) /*  258 */, CONST64(0x4C46CB2E391F5DD5) /*  259 */,
+    CONST64(0xD932ADDBC9B79434) /*  260 */, CONST64(0x08EA70E42015AFF5) /*  261 */,
+    CONST64(0xD765A6673E478CF1) /*  262 */, CONST64(0xC4FB757EAB278D99) /*  263 */,
+    CONST64(0xDF11C6862D6E0692) /*  264 */, CONST64(0xDDEB84F10D7F3B16) /*  265 */,
+    CONST64(0x6F2EF604A665EA04) /*  266 */, CONST64(0x4A8E0F0FF0E0DFB3) /*  267 */,
+    CONST64(0xA5EDEEF83DBCBA51) /*  268 */, CONST64(0xFC4F0A2A0EA4371E) /*  269 */,
+    CONST64(0xE83E1DA85CB38429) /*  270 */, CONST64(0xDC8FF882BA1B1CE2) /*  271 */,
+    CONST64(0xCD45505E8353E80D) /*  272 */, CONST64(0x18D19A00D4DB0717) /*  273 */,
+    CONST64(0x34A0CFEDA5F38101) /*  274 */, CONST64(0x0BE77E518887CAF2) /*  275 */,
+    CONST64(0x1E341438B3C45136) /*  276 */, CONST64(0xE05797F49089CCF9) /*  277 */,
+    CONST64(0xFFD23F9DF2591D14) /*  278 */, CONST64(0x543DDA228595C5CD) /*  279 */,
+    CONST64(0x661F81FD99052A33) /*  280 */, CONST64(0x8736E641DB0F7B76) /*  281 */,
+    CONST64(0x15227725418E5307) /*  282 */, CONST64(0xE25F7F46162EB2FA) /*  283 */,
+    CONST64(0x48A8B2126C13D9FE) /*  284 */, CONST64(0xAFDC541792E76EEA) /*  285 */,
+    CONST64(0x03D912BFC6D1898F) /*  286 */, CONST64(0x31B1AAFA1B83F51B) /*  287 */,
+    CONST64(0xF1AC2796E42AB7D9) /*  288 */, CONST64(0x40A3A7D7FCD2EBAC) /*  289 */,
+    CONST64(0x1056136D0AFBBCC5) /*  290 */, CONST64(0x7889E1DD9A6D0C85) /*  291 */,
+    CONST64(0xD33525782A7974AA) /*  292 */, CONST64(0xA7E25D09078AC09B) /*  293 */,
+    CONST64(0xBD4138B3EAC6EDD0) /*  294 */, CONST64(0x920ABFBE71EB9E70) /*  295 */,
+    CONST64(0xA2A5D0F54FC2625C) /*  296 */, CONST64(0xC054E36B0B1290A3) /*  297 */,
+    CONST64(0xF6DD59FF62FE932B) /*  298 */, CONST64(0x3537354511A8AC7D) /*  299 */,
+    CONST64(0xCA845E9172FADCD4) /*  300 */, CONST64(0x84F82B60329D20DC) /*  301 */,
+    CONST64(0x79C62CE1CD672F18) /*  302 */, CONST64(0x8B09A2ADD124642C) /*  303 */,
+    CONST64(0xD0C1E96A19D9E726) /*  304 */, CONST64(0x5A786A9B4BA9500C) /*  305 */,
+    CONST64(0x0E020336634C43F3) /*  306 */, CONST64(0xC17B474AEB66D822) /*  307 */,
+    CONST64(0x6A731AE3EC9BAAC2) /*  308 */, CONST64(0x8226667AE0840258) /*  309 */,
+    CONST64(0x67D4567691CAECA5) /*  310 */, CONST64(0x1D94155C4875ADB5) /*  311 */,
+    CONST64(0x6D00FD985B813FDF) /*  312 */, CONST64(0x51286EFCB774CD06) /*  313 */,
+    CONST64(0x5E8834471FA744AF) /*  314 */, CONST64(0xF72CA0AEE761AE2E) /*  315 */,
+    CONST64(0xBE40E4CDAEE8E09A) /*  316 */, CONST64(0xE9970BBB5118F665) /*  317 */,
+    CONST64(0x726E4BEB33DF1964) /*  318 */, CONST64(0x703B000729199762) /*  319 */,
+    CONST64(0x4631D816F5EF30A7) /*  320 */, CONST64(0xB880B5B51504A6BE) /*  321 */,
+    CONST64(0x641793C37ED84B6C) /*  322 */, CONST64(0x7B21ED77F6E97D96) /*  323 */,
+    CONST64(0x776306312EF96B73) /*  324 */, CONST64(0xAE528948E86FF3F4) /*  325 */,
+    CONST64(0x53DBD7F286A3F8F8) /*  326 */, CONST64(0x16CADCE74CFC1063) /*  327 */,
+    CONST64(0x005C19BDFA52C6DD) /*  328 */, CONST64(0x68868F5D64D46AD3) /*  329 */,
+    CONST64(0x3A9D512CCF1E186A) /*  330 */, CONST64(0x367E62C2385660AE) /*  331 */,
+    CONST64(0xE359E7EA77DCB1D7) /*  332 */, CONST64(0x526C0773749ABE6E) /*  333 */,
+    CONST64(0x735AE5F9D09F734B) /*  334 */, CONST64(0x493FC7CC8A558BA8) /*  335 */,
+    CONST64(0xB0B9C1533041AB45) /*  336 */, CONST64(0x321958BA470A59BD) /*  337 */,
+    CONST64(0x852DB00B5F46C393) /*  338 */, CONST64(0x91209B2BD336B0E5) /*  339 */,
+    CONST64(0x6E604F7D659EF19F) /*  340 */, CONST64(0xB99A8AE2782CCB24) /*  341 */,
+    CONST64(0xCCF52AB6C814C4C7) /*  342 */, CONST64(0x4727D9AFBE11727B) /*  343 */,
+    CONST64(0x7E950D0C0121B34D) /*  344 */, CONST64(0x756F435670AD471F) /*  345 */,
+    CONST64(0xF5ADD442615A6849) /*  346 */, CONST64(0x4E87E09980B9957A) /*  347 */,
+    CONST64(0x2ACFA1DF50AEE355) /*  348 */, CONST64(0xD898263AFD2FD556) /*  349 */,
+    CONST64(0xC8F4924DD80C8FD6) /*  350 */, CONST64(0xCF99CA3D754A173A) /*  351 */,
+    CONST64(0xFE477BACAF91BF3C) /*  352 */, CONST64(0xED5371F6D690C12D) /*  353 */,
+    CONST64(0x831A5C285E687094) /*  354 */, CONST64(0xC5D3C90A3708A0A4) /*  355 */,
+    CONST64(0x0F7F903717D06580) /*  356 */, CONST64(0x19F9BB13B8FDF27F) /*  357 */,
+    CONST64(0xB1BD6F1B4D502843) /*  358 */, CONST64(0x1C761BA38FFF4012) /*  359 */,
+    CONST64(0x0D1530C4E2E21F3B) /*  360 */, CONST64(0x8943CE69A7372C8A) /*  361 */,
+    CONST64(0xE5184E11FEB5CE66) /*  362 */, CONST64(0x618BDB80BD736621) /*  363 */,
+    CONST64(0x7D29BAD68B574D0B) /*  364 */, CONST64(0x81BB613E25E6FE5B) /*  365 */,
+    CONST64(0x071C9C10BC07913F) /*  366 */, CONST64(0xC7BEEB7909AC2D97) /*  367 */,
+    CONST64(0xC3E58D353BC5D757) /*  368 */, CONST64(0xEB017892F38F61E8) /*  369 */,
+    CONST64(0xD4EFFB9C9B1CC21A) /*  370 */, CONST64(0x99727D26F494F7AB) /*  371 */,
+    CONST64(0xA3E063A2956B3E03) /*  372 */, CONST64(0x9D4A8B9A4AA09C30) /*  373 */,
+    CONST64(0x3F6AB7D500090FB4) /*  374 */, CONST64(0x9CC0F2A057268AC0) /*  375 */,
+    CONST64(0x3DEE9D2DEDBF42D1) /*  376 */, CONST64(0x330F49C87960A972) /*  377 */,
+    CONST64(0xC6B2720287421B41) /*  378 */, CONST64(0x0AC59EC07C00369C) /*  379 */,
+    CONST64(0xEF4EAC49CB353425) /*  380 */, CONST64(0xF450244EEF0129D8) /*  381 */,
+    CONST64(0x8ACC46E5CAF4DEB6) /*  382 */, CONST64(0x2FFEAB63989263F7) /*  383 */,
+    CONST64(0x8F7CB9FE5D7A4578) /*  384 */, CONST64(0x5BD8F7644E634635) /*  385 */,
+    CONST64(0x427A7315BF2DC900) /*  386 */, CONST64(0x17D0C4AA2125261C) /*  387 */,
+    CONST64(0x3992486C93518E50) /*  388 */, CONST64(0xB4CBFEE0A2D7D4C3) /*  389 */,
+    CONST64(0x7C75D6202C5DDD8D) /*  390 */, CONST64(0xDBC295D8E35B6C61) /*  391 */,
+    CONST64(0x60B369D302032B19) /*  392 */, CONST64(0xCE42685FDCE44132) /*  393 */,
+    CONST64(0x06F3DDB9DDF65610) /*  394 */, CONST64(0x8EA4D21DB5E148F0) /*  395 */,
+    CONST64(0x20B0FCE62FCD496F) /*  396 */, CONST64(0x2C1B912358B0EE31) /*  397 */,
+    CONST64(0xB28317B818F5A308) /*  398 */, CONST64(0xA89C1E189CA6D2CF) /*  399 */,
+    CONST64(0x0C6B18576AAADBC8) /*  400 */, CONST64(0xB65DEAA91299FAE3) /*  401 */,
+    CONST64(0xFB2B794B7F1027E7) /*  402 */, CONST64(0x04E4317F443B5BEB) /*  403 */,
+    CONST64(0x4B852D325939D0A6) /*  404 */, CONST64(0xD5AE6BEEFB207FFC) /*  405 */,
+    CONST64(0x309682B281C7D374) /*  406 */, CONST64(0xBAE309A194C3B475) /*  407 */,
+    CONST64(0x8CC3F97B13B49F05) /*  408 */, CONST64(0x98A9422FF8293967) /*  409 */,
+    CONST64(0x244B16B01076FF7C) /*  410 */, CONST64(0xF8BF571C663D67EE) /*  411 */,
+    CONST64(0x1F0D6758EEE30DA1) /*  412 */, CONST64(0xC9B611D97ADEB9B7) /*  413 */,
+    CONST64(0xB7AFD5887B6C57A2) /*  414 */, CONST64(0x6290AE846B984FE1) /*  415 */,
+    CONST64(0x94DF4CDEACC1A5FD) /*  416 */, CONST64(0x058A5BD1C5483AFF) /*  417 */,
+    CONST64(0x63166CC142BA3C37) /*  418 */, CONST64(0x8DB8526EB2F76F40) /*  419 */,
+    CONST64(0xE10880036F0D6D4E) /*  420 */, CONST64(0x9E0523C9971D311D) /*  421 */,
+    CONST64(0x45EC2824CC7CD691) /*  422 */, CONST64(0x575B8359E62382C9) /*  423 */,
+    CONST64(0xFA9E400DC4889995) /*  424 */, CONST64(0xD1823ECB45721568) /*  425 */,
+    CONST64(0xDAFD983B8206082F) /*  426 */, CONST64(0xAA7D29082386A8CB) /*  427 */,
+    CONST64(0x269FCD4403B87588) /*  428 */, CONST64(0x1B91F5F728BDD1E0) /*  429 */,
+    CONST64(0xE4669F39040201F6) /*  430 */, CONST64(0x7A1D7C218CF04ADE) /*  431 */,
+    CONST64(0x65623C29D79CE5CE) /*  432 */, CONST64(0x2368449096C00BB1) /*  433 */,
+    CONST64(0xAB9BF1879DA503BA) /*  434 */, CONST64(0xBC23ECB1A458058E) /*  435 */,
+    CONST64(0x9A58DF01BB401ECC) /*  436 */, CONST64(0xA070E868A85F143D) /*  437 */,
+    CONST64(0x4FF188307DF2239E) /*  438 */, CONST64(0x14D565B41A641183) /*  439 */,
+    CONST64(0xEE13337452701602) /*  440 */, CONST64(0x950E3DCF3F285E09) /*  441 */,
+    CONST64(0x59930254B9C80953) /*  442 */, CONST64(0x3BF299408930DA6D) /*  443 */,
+    CONST64(0xA955943F53691387) /*  444 */, CONST64(0xA15EDECAA9CB8784) /*  445 */,
+    CONST64(0x29142127352BE9A0) /*  446 */, CONST64(0x76F0371FFF4E7AFB) /*  447 */,
+    CONST64(0x0239F450274F2228) /*  448 */, CONST64(0xBB073AF01D5E868B) /*  449 */,
+    CONST64(0xBFC80571C10E96C1) /*  450 */, CONST64(0xD267088568222E23) /*  451 */,
+    CONST64(0x9671A3D48E80B5B0) /*  452 */, CONST64(0x55B5D38AE193BB81) /*  453 */,
+    CONST64(0x693AE2D0A18B04B8) /*  454 */, CONST64(0x5C48B4ECADD5335F) /*  455 */,
+    CONST64(0xFD743B194916A1CA) /*  456 */, CONST64(0x2577018134BE98C4) /*  457 */,
+    CONST64(0xE77987E83C54A4AD) /*  458 */, CONST64(0x28E11014DA33E1B9) /*  459 */,
+    CONST64(0x270CC59E226AA213) /*  460 */, CONST64(0x71495F756D1A5F60) /*  461 */,
+    CONST64(0x9BE853FB60AFEF77) /*  462 */, CONST64(0xADC786A7F7443DBF) /*  463 */,
+    CONST64(0x0904456173B29A82) /*  464 */, CONST64(0x58BC7A66C232BD5E) /*  465 */,
+    CONST64(0xF306558C673AC8B2) /*  466 */, CONST64(0x41F639C6B6C9772A) /*  467 */,
+    CONST64(0x216DEFE99FDA35DA) /*  468 */, CONST64(0x11640CC71C7BE615) /*  469 */,
+    CONST64(0x93C43694565C5527) /*  470 */, CONST64(0xEA038E6246777839) /*  471 */,
+    CONST64(0xF9ABF3CE5A3E2469) /*  472 */, CONST64(0x741E768D0FD312D2) /*  473 */,
+    CONST64(0x0144B883CED652C6) /*  474 */, CONST64(0xC20B5A5BA33F8552) /*  475 */,
+    CONST64(0x1AE69633C3435A9D) /*  476 */, CONST64(0x97A28CA4088CFDEC) /*  477 */,
+    CONST64(0x8824A43C1E96F420) /*  478 */, CONST64(0x37612FA66EEEA746) /*  479 */,
+    CONST64(0x6B4CB165F9CF0E5A) /*  480 */, CONST64(0x43AA1C06A0ABFB4A) /*  481 */,
+    CONST64(0x7F4DC26FF162796B) /*  482 */, CONST64(0x6CBACC8E54ED9B0F) /*  483 */,
+    CONST64(0xA6B7FFEFD2BB253E) /*  484 */, CONST64(0x2E25BC95B0A29D4F) /*  485 */,
+    CONST64(0x86D6A58BDEF1388C) /*  486 */, CONST64(0xDED74AC576B6F054) /*  487 */,
+    CONST64(0x8030BDBC2B45805D) /*  488 */, CONST64(0x3C81AF70E94D9289) /*  489 */,
+    CONST64(0x3EFF6DDA9E3100DB) /*  490 */, CONST64(0xB38DC39FDFCC8847) /*  491 */,
+    CONST64(0x123885528D17B87E) /*  492 */, CONST64(0xF2DA0ED240B1B642) /*  493 */,
+    CONST64(0x44CEFADCD54BF9A9) /*  494 */, CONST64(0x1312200E433C7EE6) /*  495 */,
+    CONST64(0x9FFCC84F3A78C748) /*  496 */, CONST64(0xF0CD1F72248576BB) /*  497 */,
+    CONST64(0xEC6974053638CFE4) /*  498 */, CONST64(0x2BA7B67C0CEC4E4C) /*  499 */,
+    CONST64(0xAC2F4DF3E5CE32ED) /*  500 */, CONST64(0xCB33D14326EA4C11) /*  501 */,
+    CONST64(0xA4E9044CC77E58BC) /*  502 */, CONST64(0x5F513293D934FCEF) /*  503 */,
+    CONST64(0x5DC9645506E55444) /*  504 */, CONST64(0x50DE418F317DE40A) /*  505 */,
+    CONST64(0x388CB31A69DDE259) /*  506 */, CONST64(0x2DB4A83455820A86) /*  507 */,
+    CONST64(0x9010A91E84711AE9) /*  508 */, CONST64(0x4DF7F0B7B1498371) /*  509 */,
+    CONST64(0xD62A2EABC0977179) /*  510 */, CONST64(0x22FAC097AA8D5C0E) /*  511 */,
+    CONST64(0xF49FCC2FF1DAF39B) /*  512 */, CONST64(0x487FD5C66FF29281) /*  513 */,
+    CONST64(0xE8A30667FCDCA83F) /*  514 */, CONST64(0x2C9B4BE3D2FCCE63) /*  515 */,
+    CONST64(0xDA3FF74B93FBBBC2) /*  516 */, CONST64(0x2FA165D2FE70BA66) /*  517 */,
+    CONST64(0xA103E279970E93D4) /*  518 */, CONST64(0xBECDEC77B0E45E71) /*  519 */,
+    CONST64(0xCFB41E723985E497) /*  520 */, CONST64(0xB70AAA025EF75017) /*  521 */,
+    CONST64(0xD42309F03840B8E0) /*  522 */, CONST64(0x8EFC1AD035898579) /*  523 */,
+    CONST64(0x96C6920BE2B2ABC5) /*  524 */, CONST64(0x66AF4163375A9172) /*  525 */,
+    CONST64(0x2174ABDCCA7127FB) /*  526 */, CONST64(0xB33CCEA64A72FF41) /*  527 */,
+    CONST64(0xF04A4933083066A5) /*  528 */, CONST64(0x8D970ACDD7289AF5) /*  529 */,
+    CONST64(0x8F96E8E031C8C25E) /*  530 */, CONST64(0xF3FEC02276875D47) /*  531 */,
+    CONST64(0xEC7BF310056190DD) /*  532 */, CONST64(0xF5ADB0AEBB0F1491) /*  533 */,
+    CONST64(0x9B50F8850FD58892) /*  534 */, CONST64(0x4975488358B74DE8) /*  535 */,
+    CONST64(0xA3354FF691531C61) /*  536 */, CONST64(0x0702BBE481D2C6EE) /*  537 */,
+    CONST64(0x89FB24057DEDED98) /*  538 */, CONST64(0xAC3075138596E902) /*  539 */,
+    CONST64(0x1D2D3580172772ED) /*  540 */, CONST64(0xEB738FC28E6BC30D) /*  541 */,
+    CONST64(0x5854EF8F63044326) /*  542 */, CONST64(0x9E5C52325ADD3BBE) /*  543 */,
+    CONST64(0x90AA53CF325C4623) /*  544 */, CONST64(0xC1D24D51349DD067) /*  545 */,
+    CONST64(0x2051CFEEA69EA624) /*  546 */, CONST64(0x13220F0A862E7E4F) /*  547 */,
+    CONST64(0xCE39399404E04864) /*  548 */, CONST64(0xD9C42CA47086FCB7) /*  549 */,
+    CONST64(0x685AD2238A03E7CC) /*  550 */, CONST64(0x066484B2AB2FF1DB) /*  551 */,
+    CONST64(0xFE9D5D70EFBF79EC) /*  552 */, CONST64(0x5B13B9DD9C481854) /*  553 */,
+    CONST64(0x15F0D475ED1509AD) /*  554 */, CONST64(0x0BEBCD060EC79851) /*  555 */,
+    CONST64(0xD58C6791183AB7F8) /*  556 */, CONST64(0xD1187C5052F3EEE4) /*  557 */,
+    CONST64(0xC95D1192E54E82FF) /*  558 */, CONST64(0x86EEA14CB9AC6CA2) /*  559 */,
+    CONST64(0x3485BEB153677D5D) /*  560 */, CONST64(0xDD191D781F8C492A) /*  561 */,
+    CONST64(0xF60866BAA784EBF9) /*  562 */, CONST64(0x518F643BA2D08C74) /*  563 */,
+    CONST64(0x8852E956E1087C22) /*  564 */, CONST64(0xA768CB8DC410AE8D) /*  565 */,
+    CONST64(0x38047726BFEC8E1A) /*  566 */, CONST64(0xA67738B4CD3B45AA) /*  567 */,
+    CONST64(0xAD16691CEC0DDE19) /*  568 */, CONST64(0xC6D4319380462E07) /*  569 */,
+    CONST64(0xC5A5876D0BA61938) /*  570 */, CONST64(0x16B9FA1FA58FD840) /*  571 */,
+    CONST64(0x188AB1173CA74F18) /*  572 */, CONST64(0xABDA2F98C99C021F) /*  573 */,
+    CONST64(0x3E0580AB134AE816) /*  574 */, CONST64(0x5F3B05B773645ABB) /*  575 */,
+    CONST64(0x2501A2BE5575F2F6) /*  576 */, CONST64(0x1B2F74004E7E8BA9) /*  577 */,
+    CONST64(0x1CD7580371E8D953) /*  578 */, CONST64(0x7F6ED89562764E30) /*  579 */,
+    CONST64(0xB15926FF596F003D) /*  580 */, CONST64(0x9F65293DA8C5D6B9) /*  581 */,
+    CONST64(0x6ECEF04DD690F84C) /*  582 */, CONST64(0x4782275FFF33AF88) /*  583 */,
+    CONST64(0xE41433083F820801) /*  584 */, CONST64(0xFD0DFE409A1AF9B5) /*  585 */,
+    CONST64(0x4325A3342CDB396B) /*  586 */, CONST64(0x8AE77E62B301B252) /*  587 */,
+    CONST64(0xC36F9E9F6655615A) /*  588 */, CONST64(0x85455A2D92D32C09) /*  589 */,
+    CONST64(0xF2C7DEA949477485) /*  590 */, CONST64(0x63CFB4C133A39EBA) /*  591 */,
+    CONST64(0x83B040CC6EBC5462) /*  592 */, CONST64(0x3B9454C8FDB326B0) /*  593 */,
+    CONST64(0x56F56A9E87FFD78C) /*  594 */, CONST64(0x2DC2940D99F42BC6) /*  595 */,
+    CONST64(0x98F7DF096B096E2D) /*  596 */, CONST64(0x19A6E01E3AD852BF) /*  597 */,
+    CONST64(0x42A99CCBDBD4B40B) /*  598 */, CONST64(0xA59998AF45E9C559) /*  599 */,
+    CONST64(0x366295E807D93186) /*  600 */, CONST64(0x6B48181BFAA1F773) /*  601 */,
+    CONST64(0x1FEC57E2157A0A1D) /*  602 */, CONST64(0x4667446AF6201AD5) /*  603 */,
+    CONST64(0xE615EBCACFB0F075) /*  604 */, CONST64(0xB8F31F4F68290778) /*  605 */,
+    CONST64(0x22713ED6CE22D11E) /*  606 */, CONST64(0x3057C1A72EC3C93B) /*  607 */,
+    CONST64(0xCB46ACC37C3F1F2F) /*  608 */, CONST64(0xDBB893FD02AAF50E) /*  609 */,
+    CONST64(0x331FD92E600B9FCF) /*  610 */, CONST64(0xA498F96148EA3AD6) /*  611 */,
+    CONST64(0xA8D8426E8B6A83EA) /*  612 */, CONST64(0xA089B274B7735CDC) /*  613 */,
+    CONST64(0x87F6B3731E524A11) /*  614 */, CONST64(0x118808E5CBC96749) /*  615 */,
+    CONST64(0x9906E4C7B19BD394) /*  616 */, CONST64(0xAFED7F7E9B24A20C) /*  617 */,
+    CONST64(0x6509EADEEB3644A7) /*  618 */, CONST64(0x6C1EF1D3E8EF0EDE) /*  619 */,
+    CONST64(0xB9C97D43E9798FB4) /*  620 */, CONST64(0xA2F2D784740C28A3) /*  621 */,
+    CONST64(0x7B8496476197566F) /*  622 */, CONST64(0x7A5BE3E6B65F069D) /*  623 */,
+    CONST64(0xF96330ED78BE6F10) /*  624 */, CONST64(0xEEE60DE77A076A15) /*  625 */,
+    CONST64(0x2B4BEE4AA08B9BD0) /*  626 */, CONST64(0x6A56A63EC7B8894E) /*  627 */,
+    CONST64(0x02121359BA34FEF4) /*  628 */, CONST64(0x4CBF99F8283703FC) /*  629 */,
+    CONST64(0x398071350CAF30C8) /*  630 */, CONST64(0xD0A77A89F017687A) /*  631 */,
+    CONST64(0xF1C1A9EB9E423569) /*  632 */, CONST64(0x8C7976282DEE8199) /*  633 */,
+    CONST64(0x5D1737A5DD1F7ABD) /*  634 */, CONST64(0x4F53433C09A9FA80) /*  635 */,
+    CONST64(0xFA8B0C53DF7CA1D9) /*  636 */, CONST64(0x3FD9DCBC886CCB77) /*  637 */,
+    CONST64(0xC040917CA91B4720) /*  638 */, CONST64(0x7DD00142F9D1DCDF) /*  639 */,
+    CONST64(0x8476FC1D4F387B58) /*  640 */, CONST64(0x23F8E7C5F3316503) /*  641 */,
+    CONST64(0x032A2244E7E37339) /*  642 */, CONST64(0x5C87A5D750F5A74B) /*  643 */,
+    CONST64(0x082B4CC43698992E) /*  644 */, CONST64(0xDF917BECB858F63C) /*  645 */,
+    CONST64(0x3270B8FC5BF86DDA) /*  646 */, CONST64(0x10AE72BB29B5DD76) /*  647 */,
+    CONST64(0x576AC94E7700362B) /*  648 */, CONST64(0x1AD112DAC61EFB8F) /*  649 */,
+    CONST64(0x691BC30EC5FAA427) /*  650 */, CONST64(0xFF246311CC327143) /*  651 */,
+    CONST64(0x3142368E30E53206) /*  652 */, CONST64(0x71380E31E02CA396) /*  653 */,
+    CONST64(0x958D5C960AAD76F1) /*  654 */, CONST64(0xF8D6F430C16DA536) /*  655 */,
+    CONST64(0xC8FFD13F1BE7E1D2) /*  656 */, CONST64(0x7578AE66004DDBE1) /*  657 */,
+    CONST64(0x05833F01067BE646) /*  658 */, CONST64(0xBB34B5AD3BFE586D) /*  659 */,
+    CONST64(0x095F34C9A12B97F0) /*  660 */, CONST64(0x247AB64525D60CA8) /*  661 */,
+    CONST64(0xDCDBC6F3017477D1) /*  662 */, CONST64(0x4A2E14D4DECAD24D) /*  663 */,
+    CONST64(0xBDB5E6D9BE0A1EEB) /*  664 */, CONST64(0x2A7E70F7794301AB) /*  665 */,
+    CONST64(0xDEF42D8A270540FD) /*  666 */, CONST64(0x01078EC0A34C22C1) /*  667 */,
+    CONST64(0xE5DE511AF4C16387) /*  668 */, CONST64(0x7EBB3A52BD9A330A) /*  669 */,
+    CONST64(0x77697857AA7D6435) /*  670 */, CONST64(0x004E831603AE4C32) /*  671 */,
+    CONST64(0xE7A21020AD78E312) /*  672 */, CONST64(0x9D41A70C6AB420F2) /*  673 */,
+    CONST64(0x28E06C18EA1141E6) /*  674 */, CONST64(0xD2B28CBD984F6B28) /*  675 */,
+    CONST64(0x26B75F6C446E9D83) /*  676 */, CONST64(0xBA47568C4D418D7F) /*  677 */,
+    CONST64(0xD80BADBFE6183D8E) /*  678 */, CONST64(0x0E206D7F5F166044) /*  679 */,
+    CONST64(0xE258A43911CBCA3E) /*  680 */, CONST64(0x723A1746B21DC0BC) /*  681 */,
+    CONST64(0xC7CAA854F5D7CDD3) /*  682 */, CONST64(0x7CAC32883D261D9C) /*  683 */,
+    CONST64(0x7690C26423BA942C) /*  684 */, CONST64(0x17E55524478042B8) /*  685 */,
+    CONST64(0xE0BE477656A2389F) /*  686 */, CONST64(0x4D289B5E67AB2DA0) /*  687 */,
+    CONST64(0x44862B9C8FBBFD31) /*  688 */, CONST64(0xB47CC8049D141365) /*  689 */,
+    CONST64(0x822C1B362B91C793) /*  690 */, CONST64(0x4EB14655FB13DFD8) /*  691 */,
+    CONST64(0x1ECBBA0714E2A97B) /*  692 */, CONST64(0x6143459D5CDE5F14) /*  693 */,
+    CONST64(0x53A8FBF1D5F0AC89) /*  694 */, CONST64(0x97EA04D81C5E5B00) /*  695 */,
+    CONST64(0x622181A8D4FDB3F3) /*  696 */, CONST64(0xE9BCD341572A1208) /*  697 */,
+    CONST64(0x1411258643CCE58A) /*  698 */, CONST64(0x9144C5FEA4C6E0A4) /*  699 */,
+    CONST64(0x0D33D06565CF620F) /*  700 */, CONST64(0x54A48D489F219CA1) /*  701 */,
+    CONST64(0xC43E5EAC6D63C821) /*  702 */, CONST64(0xA9728B3A72770DAF) /*  703 */,
+    CONST64(0xD7934E7B20DF87EF) /*  704 */, CONST64(0xE35503B61A3E86E5) /*  705 */,
+    CONST64(0xCAE321FBC819D504) /*  706 */, CONST64(0x129A50B3AC60BFA6) /*  707 */,
+    CONST64(0xCD5E68EA7E9FB6C3) /*  708 */, CONST64(0xB01C90199483B1C7) /*  709 */,
+    CONST64(0x3DE93CD5C295376C) /*  710 */, CONST64(0xAED52EDF2AB9AD13) /*  711 */,
+    CONST64(0x2E60F512C0A07884) /*  712 */, CONST64(0xBC3D86A3E36210C9) /*  713 */,
+    CONST64(0x35269D9B163951CE) /*  714 */, CONST64(0x0C7D6E2AD0CDB5FA) /*  715 */,
+    CONST64(0x59E86297D87F5733) /*  716 */, CONST64(0x298EF221898DB0E7) /*  717 */,
+    CONST64(0x55000029D1A5AA7E) /*  718 */, CONST64(0x8BC08AE1B5061B45) /*  719 */,
+    CONST64(0xC2C31C2B6C92703A) /*  720 */, CONST64(0x94CC596BAF25EF42) /*  721 */,
+    CONST64(0x0A1D73DB22540456) /*  722 */, CONST64(0x04B6A0F9D9C4179A) /*  723 */,
+    CONST64(0xEFFDAFA2AE3D3C60) /*  724 */, CONST64(0xF7C8075BB49496C4) /*  725 */,
+    CONST64(0x9CC5C7141D1CD4E3) /*  726 */, CONST64(0x78BD1638218E5534) /*  727 */,
+    CONST64(0xB2F11568F850246A) /*  728 */, CONST64(0xEDFABCFA9502BC29) /*  729 */,
+    CONST64(0x796CE5F2DA23051B) /*  730 */, CONST64(0xAAE128B0DC93537C) /*  731 */,
+    CONST64(0x3A493DA0EE4B29AE) /*  732 */, CONST64(0xB5DF6B2C416895D7) /*  733 */,
+    CONST64(0xFCABBD25122D7F37) /*  734 */, CONST64(0x70810B58105DC4B1) /*  735 */,
+    CONST64(0xE10FDD37F7882A90) /*  736 */, CONST64(0x524DCAB5518A3F5C) /*  737 */,
+    CONST64(0x3C9E85878451255B) /*  738 */, CONST64(0x4029828119BD34E2) /*  739 */,
+    CONST64(0x74A05B6F5D3CECCB) /*  740 */, CONST64(0xB610021542E13ECA) /*  741 */,
+    CONST64(0x0FF979D12F59E2AC) /*  742 */, CONST64(0x6037DA27E4F9CC50) /*  743 */,
+    CONST64(0x5E92975A0DF1847D) /*  744 */, CONST64(0xD66DE190D3E623FE) /*  745 */,
+    CONST64(0x5032D6B87B568048) /*  746 */, CONST64(0x9A36B7CE8235216E) /*  747 */,
+    CONST64(0x80272A7A24F64B4A) /*  748 */, CONST64(0x93EFED8B8C6916F7) /*  749 */,
+    CONST64(0x37DDBFF44CCE1555) /*  750 */, CONST64(0x4B95DB5D4B99BD25) /*  751 */,
+    CONST64(0x92D3FDA169812FC0) /*  752 */, CONST64(0xFB1A4A9A90660BB6) /*  753 */,
+    CONST64(0x730C196946A4B9B2) /*  754 */, CONST64(0x81E289AA7F49DA68) /*  755 */,
+    CONST64(0x64669A0F83B1A05F) /*  756 */, CONST64(0x27B3FF7D9644F48B) /*  757 */,
+    CONST64(0xCC6B615C8DB675B3) /*  758 */, CONST64(0x674F20B9BCEBBE95) /*  759 */,
+    CONST64(0x6F31238275655982) /*  760 */, CONST64(0x5AE488713E45CF05) /*  761 */,
+    CONST64(0xBF619F9954C21157) /*  762 */, CONST64(0xEABAC46040A8EAE9) /*  763 */,
+    CONST64(0x454C6FE9F2C0C1CD) /*  764 */, CONST64(0x419CF6496412691C) /*  765 */,
+    CONST64(0xD3DC3BEF265B0F70) /*  766 */, CONST64(0x6D0E60F5C3578A9E) /*  767 */,
+    CONST64(0x5B0E608526323C55) /*  768 */, CONST64(0x1A46C1A9FA1B59F5) /*  769 */,
+    CONST64(0xA9E245A17C4C8FFA) /*  770 */, CONST64(0x65CA5159DB2955D7) /*  771 */,
+    CONST64(0x05DB0A76CE35AFC2) /*  772 */, CONST64(0x81EAC77EA9113D45) /*  773 */,
+    CONST64(0x528EF88AB6AC0A0D) /*  774 */, CONST64(0xA09EA253597BE3FF) /*  775 */,
+    CONST64(0x430DDFB3AC48CD56) /*  776 */, CONST64(0xC4B3A67AF45CE46F) /*  777 */,
+    CONST64(0x4ECECFD8FBE2D05E) /*  778 */, CONST64(0x3EF56F10B39935F0) /*  779 */,
+    CONST64(0x0B22D6829CD619C6) /*  780 */, CONST64(0x17FD460A74DF2069) /*  781 */,
+    CONST64(0x6CF8CC8E8510ED40) /*  782 */, CONST64(0xD6C824BF3A6ECAA7) /*  783 */,
+    CONST64(0x61243D581A817049) /*  784 */, CONST64(0x048BACB6BBC163A2) /*  785 */,
+    CONST64(0xD9A38AC27D44CC32) /*  786 */, CONST64(0x7FDDFF5BAAF410AB) /*  787 */,
+    CONST64(0xAD6D495AA804824B) /*  788 */, CONST64(0xE1A6A74F2D8C9F94) /*  789 */,
+    CONST64(0xD4F7851235DEE8E3) /*  790 */, CONST64(0xFD4B7F886540D893) /*  791 */,
+    CONST64(0x247C20042AA4BFDA) /*  792 */, CONST64(0x096EA1C517D1327C) /*  793 */,
+    CONST64(0xD56966B4361A6685) /*  794 */, CONST64(0x277DA5C31221057D) /*  795 */,
+    CONST64(0x94D59893A43ACFF7) /*  796 */, CONST64(0x64F0C51CCDC02281) /*  797 */,
+    CONST64(0x3D33BCC4FF6189DB) /*  798 */, CONST64(0xE005CB184CE66AF1) /*  799 */,
+    CONST64(0xFF5CCD1D1DB99BEA) /*  800 */, CONST64(0xB0B854A7FE42980F) /*  801 */,
+    CONST64(0x7BD46A6A718D4B9F) /*  802 */, CONST64(0xD10FA8CC22A5FD8C) /*  803 */,
+    CONST64(0xD31484952BE4BD31) /*  804 */, CONST64(0xC7FA975FCB243847) /*  805 */,
+    CONST64(0x4886ED1E5846C407) /*  806 */, CONST64(0x28CDDB791EB70B04) /*  807 */,
+    CONST64(0xC2B00BE2F573417F) /*  808 */, CONST64(0x5C9590452180F877) /*  809 */,
+    CONST64(0x7A6BDDFFF370EB00) /*  810 */, CONST64(0xCE509E38D6D9D6A4) /*  811 */,
+    CONST64(0xEBEB0F00647FA702) /*  812 */, CONST64(0x1DCC06CF76606F06) /*  813 */,
+    CONST64(0xE4D9F28BA286FF0A) /*  814 */, CONST64(0xD85A305DC918C262) /*  815 */,
+    CONST64(0x475B1D8732225F54) /*  816 */, CONST64(0x2D4FB51668CCB5FE) /*  817 */,
+    CONST64(0xA679B9D9D72BBA20) /*  818 */, CONST64(0x53841C0D912D43A5) /*  819 */,
+    CONST64(0x3B7EAA48BF12A4E8) /*  820 */, CONST64(0x781E0E47F22F1DDF) /*  821 */,
+    CONST64(0xEFF20CE60AB50973) /*  822 */, CONST64(0x20D261D19DFFB742) /*  823 */,
+    CONST64(0x16A12B03062A2E39) /*  824 */, CONST64(0x1960EB2239650495) /*  825 */,
+    CONST64(0x251C16FED50EB8B8) /*  826 */, CONST64(0x9AC0C330F826016E) /*  827 */,
+    CONST64(0xED152665953E7671) /*  828 */, CONST64(0x02D63194A6369570) /*  829 */,
+    CONST64(0x5074F08394B1C987) /*  830 */, CONST64(0x70BA598C90B25CE1) /*  831 */,
+    CONST64(0x794A15810B9742F6) /*  832 */, CONST64(0x0D5925E9FCAF8C6C) /*  833 */,
+    CONST64(0x3067716CD868744E) /*  834 */, CONST64(0x910AB077E8D7731B) /*  835 */,
+    CONST64(0x6A61BBDB5AC42F61) /*  836 */, CONST64(0x93513EFBF0851567) /*  837 */,
+    CONST64(0xF494724B9E83E9D5) /*  838 */, CONST64(0xE887E1985C09648D) /*  839 */,
+    CONST64(0x34B1D3C675370CFD) /*  840 */, CONST64(0xDC35E433BC0D255D) /*  841 */,
+    CONST64(0xD0AAB84234131BE0) /*  842 */, CONST64(0x08042A50B48B7EAF) /*  843 */,
+    CONST64(0x9997C4EE44A3AB35) /*  844 */, CONST64(0x829A7B49201799D0) /*  845 */,
+    CONST64(0x263B8307B7C54441) /*  846 */, CONST64(0x752F95F4FD6A6CA6) /*  847 */,
+    CONST64(0x927217402C08C6E5) /*  848 */, CONST64(0x2A8AB754A795D9EE) /*  849 */,
+    CONST64(0xA442F7552F72943D) /*  850 */, CONST64(0x2C31334E19781208) /*  851 */,
+    CONST64(0x4FA98D7CEAEE6291) /*  852 */, CONST64(0x55C3862F665DB309) /*  853 */,
+    CONST64(0xBD0610175D53B1F3) /*  854 */, CONST64(0x46FE6CB840413F27) /*  855 */,
+    CONST64(0x3FE03792DF0CFA59) /*  856 */, CONST64(0xCFE700372EB85E8F) /*  857 */,
+    CONST64(0xA7BE29E7ADBCE118) /*  858 */, CONST64(0xE544EE5CDE8431DD) /*  859 */,
+    CONST64(0x8A781B1B41F1873E) /*  860 */, CONST64(0xA5C94C78A0D2F0E7) /*  861 */,
+    CONST64(0x39412E2877B60728) /*  862 */, CONST64(0xA1265EF3AFC9A62C) /*  863 */,
+    CONST64(0xBCC2770C6A2506C5) /*  864 */, CONST64(0x3AB66DD5DCE1CE12) /*  865 */,
+    CONST64(0xE65499D04A675B37) /*  866 */, CONST64(0x7D8F523481BFD216) /*  867 */,
+    CONST64(0x0F6F64FCEC15F389) /*  868 */, CONST64(0x74EFBE618B5B13C8) /*  869 */,
+    CONST64(0xACDC82B714273E1D) /*  870 */, CONST64(0xDD40BFE003199D17) /*  871 */,
+    CONST64(0x37E99257E7E061F8) /*  872 */, CONST64(0xFA52626904775AAA) /*  873 */,
+    CONST64(0x8BBBF63A463D56F9) /*  874 */, CONST64(0xF0013F1543A26E64) /*  875 */,
+    CONST64(0xA8307E9F879EC898) /*  876 */, CONST64(0xCC4C27A4150177CC) /*  877 */,
+    CONST64(0x1B432F2CCA1D3348) /*  878 */, CONST64(0xDE1D1F8F9F6FA013) /*  879 */,
+    CONST64(0x606602A047A7DDD6) /*  880 */, CONST64(0xD237AB64CC1CB2C7) /*  881 */,
+    CONST64(0x9B938E7225FCD1D3) /*  882 */, CONST64(0xEC4E03708E0FF476) /*  883 */,
+    CONST64(0xFEB2FBDA3D03C12D) /*  884 */, CONST64(0xAE0BCED2EE43889A) /*  885 */,
+    CONST64(0x22CB8923EBFB4F43) /*  886 */, CONST64(0x69360D013CF7396D) /*  887 */,
+    CONST64(0x855E3602D2D4E022) /*  888 */, CONST64(0x073805BAD01F784C) /*  889 */,
+    CONST64(0x33E17A133852F546) /*  890 */, CONST64(0xDF4874058AC7B638) /*  891 */,
+    CONST64(0xBA92B29C678AA14A) /*  892 */, CONST64(0x0CE89FC76CFAADCD) /*  893 */,
+    CONST64(0x5F9D4E0908339E34) /*  894 */, CONST64(0xF1AFE9291F5923B9) /*  895 */,
+    CONST64(0x6E3480F60F4A265F) /*  896 */, CONST64(0xEEBF3A2AB29B841C) /*  897 */,
+    CONST64(0xE21938A88F91B4AD) /*  898 */, CONST64(0x57DFEFF845C6D3C3) /*  899 */,
+    CONST64(0x2F006B0BF62CAAF2) /*  900 */, CONST64(0x62F479EF6F75EE78) /*  901 */,
+    CONST64(0x11A55AD41C8916A9) /*  902 */, CONST64(0xF229D29084FED453) /*  903 */,
+    CONST64(0x42F1C27B16B000E6) /*  904 */, CONST64(0x2B1F76749823C074) /*  905 */,
+    CONST64(0x4B76ECA3C2745360) /*  906 */, CONST64(0x8C98F463B91691BD) /*  907 */,
+    CONST64(0x14BCC93CF1ADE66A) /*  908 */, CONST64(0x8885213E6D458397) /*  909 */,
+    CONST64(0x8E177DF0274D4711) /*  910 */, CONST64(0xB49B73B5503F2951) /*  911 */,
+    CONST64(0x10168168C3F96B6B) /*  912 */, CONST64(0x0E3D963B63CAB0AE) /*  913 */,
+    CONST64(0x8DFC4B5655A1DB14) /*  914 */, CONST64(0xF789F1356E14DE5C) /*  915 */,
+    CONST64(0x683E68AF4E51DAC1) /*  916 */, CONST64(0xC9A84F9D8D4B0FD9) /*  917 */,
+    CONST64(0x3691E03F52A0F9D1) /*  918 */, CONST64(0x5ED86E46E1878E80) /*  919 */,
+    CONST64(0x3C711A0E99D07150) /*  920 */, CONST64(0x5A0865B20C4E9310) /*  921 */,
+    CONST64(0x56FBFC1FE4F0682E) /*  922 */, CONST64(0xEA8D5DE3105EDF9B) /*  923 */,
+    CONST64(0x71ABFDB12379187A) /*  924 */, CONST64(0x2EB99DE1BEE77B9C) /*  925 */,
+    CONST64(0x21ECC0EA33CF4523) /*  926 */, CONST64(0x59A4D7521805C7A1) /*  927 */,
+    CONST64(0x3896F5EB56AE7C72) /*  928 */, CONST64(0xAA638F3DB18F75DC) /*  929 */,
+    CONST64(0x9F39358DABE9808E) /*  930 */, CONST64(0xB7DEFA91C00B72AC) /*  931 */,
+    CONST64(0x6B5541FD62492D92) /*  932 */, CONST64(0x6DC6DEE8F92E4D5B) /*  933 */,
+    CONST64(0x353F57ABC4BEEA7E) /*  934 */, CONST64(0x735769D6DA5690CE) /*  935 */,
+    CONST64(0x0A234AA642391484) /*  936 */, CONST64(0xF6F9508028F80D9D) /*  937 */,
+    CONST64(0xB8E319A27AB3F215) /*  938 */, CONST64(0x31AD9C1151341A4D) /*  939 */,
+    CONST64(0x773C22A57BEF5805) /*  940 */, CONST64(0x45C7561A07968633) /*  941 */,
+    CONST64(0xF913DA9E249DBE36) /*  942 */, CONST64(0xDA652D9B78A64C68) /*  943 */,
+    CONST64(0x4C27A97F3BC334EF) /*  944 */, CONST64(0x76621220E66B17F4) /*  945 */,
+    CONST64(0x967743899ACD7D0B) /*  946 */, CONST64(0xF3EE5BCAE0ED6782) /*  947 */,
+    CONST64(0x409F753600C879FC) /*  948 */, CONST64(0x06D09A39B5926DB6) /*  949 */,
+    CONST64(0x6F83AEB0317AC588) /*  950 */, CONST64(0x01E6CA4A86381F21) /*  951 */,
+    CONST64(0x66FF3462D19F3025) /*  952 */, CONST64(0x72207C24DDFD3BFB) /*  953 */,
+    CONST64(0x4AF6B6D3E2ECE2EB) /*  954 */, CONST64(0x9C994DBEC7EA08DE) /*  955 */,
+    CONST64(0x49ACE597B09A8BC4) /*  956 */, CONST64(0xB38C4766CF0797BA) /*  957 */,
+    CONST64(0x131B9373C57C2A75) /*  958 */, CONST64(0xB1822CCE61931E58) /*  959 */,
+    CONST64(0x9D7555B909BA1C0C) /*  960 */, CONST64(0x127FAFDD937D11D2) /*  961 */,
+    CONST64(0x29DA3BADC66D92E4) /*  962 */, CONST64(0xA2C1D57154C2ECBC) /*  963 */,
+    CONST64(0x58C5134D82F6FE24) /*  964 */, CONST64(0x1C3AE3515B62274F) /*  965 */,
+    CONST64(0xE907C82E01CB8126) /*  966 */, CONST64(0xF8ED091913E37FCB) /*  967 */,
+    CONST64(0x3249D8F9C80046C9) /*  968 */, CONST64(0x80CF9BEDE388FB63) /*  969 */,
+    CONST64(0x1881539A116CF19E) /*  970 */, CONST64(0x5103F3F76BD52457) /*  971 */,
+    CONST64(0x15B7E6F5AE47F7A8) /*  972 */, CONST64(0xDBD7C6DED47E9CCF) /*  973 */,
+    CONST64(0x44E55C410228BB1A) /*  974 */, CONST64(0xB647D4255EDB4E99) /*  975 */,
+    CONST64(0x5D11882BB8AAFC30) /*  976 */, CONST64(0xF5098BBB29D3212A) /*  977 */,
+    CONST64(0x8FB5EA14E90296B3) /*  978 */, CONST64(0x677B942157DD025A) /*  979 */,
+    CONST64(0xFB58E7C0A390ACB5) /*  980 */, CONST64(0x89D3674C83BD4A01) /*  981 */,
+    CONST64(0x9E2DA4DF4BF3B93B) /*  982 */, CONST64(0xFCC41E328CAB4829) /*  983 */,
+    CONST64(0x03F38C96BA582C52) /*  984 */, CONST64(0xCAD1BDBD7FD85DB2) /*  985 */,
+    CONST64(0xBBB442C16082AE83) /*  986 */, CONST64(0xB95FE86BA5DA9AB0) /*  987 */,
+    CONST64(0xB22E04673771A93F) /*  988 */, CONST64(0x845358C9493152D8) /*  989 */,
+    CONST64(0xBE2A488697B4541E) /*  990 */, CONST64(0x95A2DC2DD38E6966) /*  991 */,
+    CONST64(0xC02C11AC923C852B) /*  992 */, CONST64(0x2388B1990DF2A87B) /*  993 */,
+    CONST64(0x7C8008FA1B4F37BE) /*  994 */, CONST64(0x1F70D0C84D54E503) /*  995 */,
+    CONST64(0x5490ADEC7ECE57D4) /*  996 */, CONST64(0x002B3C27D9063A3A) /*  997 */,
+    CONST64(0x7EAEA3848030A2BF) /*  998 */, CONST64(0xC602326DED2003C0) /*  999 */,
+    CONST64(0x83A7287D69A94086) /* 1000 */, CONST64(0xC57A5FCB30F57A8A) /* 1001 */,
+    CONST64(0xB56844E479EBE779) /* 1002 */, CONST64(0xA373B40F05DCBCE9) /* 1003 */,
+    CONST64(0xD71A786E88570EE2) /* 1004 */, CONST64(0x879CBACDBDE8F6A0) /* 1005 */,
+    CONST64(0x976AD1BCC164A32F) /* 1006 */, CONST64(0xAB21E25E9666D78B) /* 1007 */,
+    CONST64(0x901063AAE5E5C33C) /* 1008 */, CONST64(0x9818B34448698D90) /* 1009 */,
+    CONST64(0xE36487AE3E1E8ABB) /* 1010 */, CONST64(0xAFBDF931893BDCB4) /* 1011 */,
+    CONST64(0x6345A0DC5FBBD519) /* 1012 */, CONST64(0x8628FE269B9465CA) /* 1013 */,
+    CONST64(0x1E5D01603F9C51EC) /* 1014 */, CONST64(0x4DE44006A15049B7) /* 1015 */,
+    CONST64(0xBF6C70E5F776CBB1) /* 1016 */, CONST64(0x411218F2EF552BED) /* 1017 */,
+    CONST64(0xCB0C0708705A36A3) /* 1018 */, CONST64(0xE74D14754F986044) /* 1019 */,
+    CONST64(0xCD56D9430EA8280E) /* 1020 */, CONST64(0xC12591D7535F5065) /* 1021 */,
+    CONST64(0xC83223F1720AEF96) /* 1022 */, CONST64(0xC3A0396F7363A51F) /* 1023 */};
+
+/* one round of the hash function */
+static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, ulong64 mul)
+{
+    *c ^= x;                                                                            
+    *a -= t1[(*c)&255] ^ t2[((*c)>>16)&255] ^ t3[((*c)>>32)&255] ^ t4[((*c)>>48)&255];      
+    *b += t4[((*c)>>8)&255] ^ t3[((*c)>>24)&255] ^ t2[((*c)>>40)&255] ^ t1[((*c)>>56)&255]; 
+    *b *= mul;
+}
+
+/* one complete pass */
+static void pass(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 *x, ulong64 mul)
+{
+   round(a,b,c,x[0],mul); 
+   round(b,c,a,x[1],mul); 
+   round(c,a,b,x[2],mul); 
+   round(a,b,c,x[3],mul); 
+   round(b,c,a,x[4],mul); 
+   round(c,a,b,x[5],mul); 
+   round(a,b,c,x[6],mul); 
+   round(b,c,a,x[7],mul);          
+}   
+
+/* The key mixing schedule */
+static void key_schedule(ulong64 *x) {
+    x[0] -= x[7] ^ CONST64(0xA5A5A5A5A5A5A5A5); 
+    x[1] ^= x[0];                               
+    x[2] += x[1];                               
+    x[3] -= x[2] ^ ((~x[1])<<19);               
+    x[4] ^= x[3];                               
+    x[5] += x[4];                               
+    x[6] -= x[5] ^ ((~x[4])>>23);               
+    x[7] ^= x[6];                               
+    x[0] += x[7];                               
+    x[1] -= x[0] ^ ((~x[7])<<19);               
+    x[2] ^= x[1];                               
+    x[3] += x[2];                               
+    x[4] -= x[3] ^ ((~x[2])>>23);               
+    x[5] ^= x[4];                               
+    x[6] += x[5];                               
+    x[7] -= x[6] ^ CONST64(0x0123456789ABCDEF);
+}    
+
+#ifdef CLEAN_STACK
+static void _tiger_compress(hash_state *md)
+#else
+static void tiger_compress(hash_state *md)
+#endif
+{
+    ulong64 a, b, c, x[8];
+    unsigned long i;
+
+    _ARGCHK(md != NULL);
+
+    /* load words */
+    for (i = 0; i < 8; i++) {
+        LOAD64L(x[i],&md->tiger.buf[8*i]);
+    }
+    a = md->tiger.state[0];
+    b = md->tiger.state[1];
+    c = md->tiger.state[2];
+
+    pass(&a,&b,&c,x,5);
+    key_schedule(x);
+    pass(&c,&a,&b,x,7);
+    key_schedule(x);
+    pass(&b,&c,&a,x,9);
+
+    /* store state */
+    md->tiger.state[0] = a ^ md->tiger.state[0];
+    md->tiger.state[1] = b - md->tiger.state[1];
+    md->tiger.state[2] = c + md->tiger.state[2];
+}
+
+#ifdef CLEAN_STACK
+static void tiger_compress(hash_state *md)
+{
+   _tiger_compress(md);
+   burn_stack(sizeof(ulong64) * 11 + sizeof(unsigned long));
+}
+#endif
+
+void tiger_init(hash_state *md)
+{
+    _ARGCHK(md != NULL);
+    md->tiger.state[0] = CONST64(0x0123456789ABCDEF);
+    md->tiger.state[1] = CONST64(0xFEDCBA9876543210);
+    md->tiger.state[2] = CONST64(0xF096A5B4C3B2E187);
+    md->tiger.curlen = 0;
+    md->tiger.length = 0;
+}
+
+void tiger_process(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+    unsigned long n;
+    _ARGCHK(md != NULL);
+    _ARGCHK(buf != NULL);
+    while (len) {
+        n = MIN(len, (64 - md->tiger.curlen));
+        memcpy(md->tiger.buf + md->tiger.curlen, buf, n);
+        md->tiger.curlen += n;
+        buf            += n;
+        len            -= n;
+
+        /* is 64 bytes full? */
+        if (md->tiger.curlen == 64) {
+            tiger_compress(md);
+            md->tiger.length += 512;    /* add the number of bits not bytes */
+            md->tiger.curlen = 0;
+        }
+    }
+}
+
+void tiger_done(hash_state * md, unsigned char *hash)
+{
+    _ARGCHK(md != NULL);
+    _ARGCHK(hash != NULL);
+
+    /* increase the length of the message */
+    md->tiger.length += md->tiger.curlen * 8;
+
+    /* append the '1' bit */
+    md->tiger.buf[md->tiger.curlen++] = 0x01;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal. */
+    if (md->tiger.curlen > 56) {
+        while (md->tiger.curlen < 64) {
+            md->tiger.buf[md->tiger.curlen++] = 0;
+        }
+        tiger_compress(md);
+        md->tiger.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->tiger.curlen < 56) {
+        md->tiger.buf[md->tiger.curlen++] = 0; 
+    }
+
+    /* store length */
+    STORE64L(md->tiger.length, md->tiger.buf+56);
+    tiger_compress(md);
+
+    /* copy output */
+    STORE64L(md->tiger.state[0], &hash[0]);
+    STORE64L(md->tiger.state[1], &hash[8]);
+    STORE64L(md->tiger.state[2], &hash[16]);
+#ifdef CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+}
+
+int  tiger_test(void)
+{
+  static const struct {
+      unsigned char *msg;
+      unsigned char hash[24];
+  } tests[] = {
+    { "",
+     { 0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24,
+       0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16,
+       0x7a, 0x4e, 0x58, 0x49, 0x2d, 0xde, 0x73, 0xf3 }
+    },
+    { "abc",
+     { 0x2a, 0xab, 0x14, 0x84, 0xe8, 0xc1, 0x58, 0xf2,
+       0xbf, 0xb8, 0xc5, 0xff, 0x41, 0xb5, 0x7a, 0x52,
+       0x51, 0x29, 0x13, 0x1c, 0x95, 0x7b, 0x5f, 0x93 }
+    },
+    { "Tiger",
+     { 0xdd, 0x00, 0x23, 0x07, 0x99, 0xf5, 0x00, 0x9f,
+       0xec, 0x6d, 0xeb, 0xc8, 0x38, 0xbb, 0x6a, 0x27,
+       0xdf, 0x2b, 0x9d, 0x6f, 0x11, 0x0c, 0x79, 0x37 }
+    },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+     { 0xf7, 0x1c, 0x85, 0x83, 0x90, 0x2a, 0xfb, 0x87,
+       0x9e, 0xdf, 0xe6, 0x10, 0xf8, 0x2c, 0x0d, 0x47,
+       0x86, 0xa3, 0xa5, 0x34, 0x50, 0x44, 0x86, 0xb5 }
+    },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+     { 0xc5, 0x40, 0x34, 0xe5, 0xb4, 0x3e, 0xb8, 0x00,
+       0x58, 0x48, 0xa7, 0xe0, 0xae, 0x6a, 0xac, 0x76,
+       0xe4, 0xff, 0x59, 0x0a, 0xe7, 0x15, 0xfd, 0x25 }
+    },
+    { NULL, { 0 }}
+  };
+
+  int failed, i;
+  unsigned char tmp[24];
+  hash_state md;
+
+  for (failed = i = 0; tests[i].msg != NULL; i++) {
+      tiger_init(&md);
+      tiger_process(&md, tests[i].msg, strlen(tests[i].msg));
+      tiger_done(&md, tmp);
+      if (memcmp(tmp, tests[i].hash, 24)) {
+#if 0
+         int j;
+         printf("\nTIGER-192 Test %d failed\nGot (as a result): ", i);
+         for (j = 0; j < 24; j++) {
+             printf("%02x ", tmp[j]);
+         }
+         printf("\n");
+#endif
+         failed = 1;
+      }
+  }
+  if (failed == 1) {
+     return CRYPT_FAIL_TESTVECTOR;
+  } else {
+     return CRYPT_OK;
+  }
+}
+
+#endif
+
+/*
+Hash of "":
+        24F0130C63AC9332 16166E76B1BB925F F373DE2D49584E7A
+Hash of "abc":
+        F258C1E88414AB2A 527AB541FFC5B8BF 935F7B951C132951
+Hash of "Tiger":
+        9F00F599072300DD 276ABB38C8EB6DEC 37790C116F9D2BDF
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-":
+        87FB2A9083851CF7 470D2CF810E6DF9E B586445034A5A386
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789":
+        467DB80863EBCE48 8DF1CD1261655DE9 57896565975F9197
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham":
+        0C410A042968868A 1671DA5A3FD29A72 5EC1E457D3CDB303
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.":
+        EBF591D5AFA655CE 7F22894FF87F54AC 89C811B6B0DA3193
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.":
+        3D9AEB03D1BD1A63 57B2774DFD6D5B24 DD68151D503974FC
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-":
+        00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4
+*/
+
+
+

+ 727 - 0
twofish.c

@@ -0,0 +1,727 @@
+/* Implementation of Twofish by Tom St Denis */
+#include "mycrypt.h"
+
+#ifdef TWOFISH
+
+const struct _cipher_descriptor twofish_desc =
+{
+    "twofish",
+    7,
+    16, 32, 16, 16,
+    &twofish_setup,
+    &twofish_ecb_encrypt,
+    &twofish_ecb_decrypt,
+    &twofish_test,
+    &twofish_keysize
+};
+
+/* the two polynomials */
+#define MDS_POLY          0x169
+#define RS_POLY           0x14D
+
+/* The 4x4 MDS Linear Transform */
+static const unsigned char MDS[4][4] = {
+    { 0x01, 0xEF, 0x5B, 0x5B },
+    { 0x5B, 0xEF, 0xEF, 0x01 },
+    { 0xEF, 0x5B, 0x01, 0xEF },
+    { 0xEF, 0x01, 0xEF, 0x5B }
+};
+
+/* The 4x8 RS Linear Transform */
+static const unsigned char RS[4][8] = {
+    { 0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E },
+    { 0xA4, 0x56, 0x82, 0xF3, 0X1E, 0XC6, 0X68, 0XE5 },
+    { 0X02, 0XA1, 0XFC, 0XC1, 0X47, 0XAE, 0X3D, 0X19 },
+    { 0XA4, 0X55, 0X87, 0X5A, 0X58, 0XDB, 0X9E, 0X03 }
+};
+
+/* sbox usage orderings */
+static const unsigned char qord[4][5] = {
+   { 1, 1, 0, 0, 1 },
+   { 0, 1, 1, 0, 0 },
+   { 0, 0, 0, 1, 1 },
+   { 1, 0, 1, 1, 0 }
+};
+
+#ifdef TWOFISH_TABLES
+static const unsigned char SBOX[2][256] = {
+{
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 
+ 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, 0x0d, 0xc6, 0x35, 0x98, 
+ 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 
+ 0x94, 0x48, 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 
+ 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, 0x63, 0x01, 
+ 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 
+ 0x16, 0x0c, 0xe3, 0x61, 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 
+ 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1, 
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95,
+ 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, 0xfb, 0xc3, 0x8e, 0xb5, 
+ 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 
+ 0x62, 0x71, 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 
+ 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, 0xa1, 0x1d, 
+ 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 
+ 0x31, 0xc2, 0x27, 0x90, 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 
+ 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef, 
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 
+ 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, 0x2a, 0xce, 0xcb, 0x2f, 
+ 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 
+ 0xa7, 0x5a, 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 
+ 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, 0x57, 0xc7, 
+ 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 
+ 0x58, 0x07, 0x99, 0x34, 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 
+ 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4, 
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 
+ 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0},
+{
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 
+ 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, 0xd6, 0x32, 0xd8, 0xfd, 
+ 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 
+ 0x06, 0x3f, 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 
+ 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, 0xa0, 0x84, 
+ 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 
+ 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c, 
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 
+ 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, 0xa6, 0x83, 0x20, 0xff,
+ 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 
+ 0x2b, 0xe2, 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 
+ 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, 0x66, 0x94, 
+ 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 
+ 0xef, 0xd1, 0x53, 0x3e, 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 
+ 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9, 
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 
+ 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, 0x4f, 0xf2, 0x65, 0x8e, 
+ 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 
+ 0x05, 0x64, 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 
+ 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, 0x29, 0x2e, 
+ 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 
+ 0x35, 0x6a, 0xcf, 0xdc, 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 
+ 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9, 
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 
+ 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91}
+};
+
+static const unsigned char GF_EF[256] = {
+ 0x00, 0xef, 0xb7, 0x58, 0x07, 0xe8, 0xb0, 0x5f, 0x0e, 0xe1, 
+ 0xb9, 0x56, 0x09, 0xe6, 0xbe, 0x51, 0x1c, 0xf3, 0xab, 0x44, 
+ 0x1b, 0xf4, 0xac, 0x43, 0x12, 0xfd, 0xa5, 0x4a, 0x15, 0xfa, 
+ 0xa2, 0x4d, 0x38, 0xd7, 0x8f, 0x60, 0x3f, 0xd0, 0x88, 0x67, 
+ 0x36, 0xd9, 0x81, 0x6e, 0x31, 0xde, 0x86, 0x69, 0x24, 0xcb, 
+ 0x93, 0x7c, 0x23, 0xcc, 0x94, 0x7b, 0x2a, 0xc5, 0x9d, 0x72, 
+ 0x2d, 0xc2, 0x9a, 0x75, 0x70, 0x9f, 0xc7, 0x28, 0x77, 0x98, 
+ 0xc0, 0x2f, 0x7e, 0x91, 0xc9, 0x26, 0x79, 0x96, 0xce, 0x21,
+ 0x6c, 0x83, 0xdb, 0x34, 0x6b, 0x84, 0xdc, 0x33, 0x62, 0x8d, 
+ 0xd5, 0x3a, 0x65, 0x8a, 0xd2, 0x3d, 0x48, 0xa7, 0xff, 0x10, 
+ 0x4f, 0xa0, 0xf8, 0x17, 0x46, 0xa9, 0xf1, 0x1e, 0x41, 0xae, 
+ 0xf6, 0x19, 0x54, 0xbb, 0xe3, 0x0c, 0x53, 0xbc, 0xe4, 0x0b, 
+ 0x5a, 0xb5, 0xed, 0x02, 0x5d, 0xb2, 0xea, 0x05, 0xe0, 0x0f, 
+ 0x57, 0xb8, 0xe7, 0x08, 0x50, 0xbf, 0xee, 0x01, 0x59, 0xb6, 
+ 0xe9, 0x06, 0x5e, 0xb1, 0xfc, 0x13, 0x4b, 0xa4, 0xfb, 0x14, 
+ 0x4c, 0xa3, 0xf2, 0x1d, 0x45, 0xaa, 0xf5, 0x1a, 0x42, 0xad, 
+ 0xd8, 0x37, 0x6f, 0x80, 0xdf, 0x30, 0x68, 0x87, 0xd6, 0x39, 
+ 0x61, 0x8e, 0xd1, 0x3e, 0x66, 0x89, 0xc4, 0x2b, 0x73, 0x9c, 
+ 0xc3, 0x2c, 0x74, 0x9b, 0xca, 0x25, 0x7d, 0x92, 0xcd, 0x22, 
+ 0x7a, 0x95, 0x90, 0x7f, 0x27, 0xc8, 0x97, 0x78, 0x20, 0xcf, 
+ 0x9e, 0x71, 0x29, 0xc6, 0x99, 0x76, 0x2e, 0xc1, 0x8c, 0x63, 
+ 0x3b, 0xd4, 0x8b, 0x64, 0x3c, 0xd3, 0x82, 0x6d, 0x35, 0xda, 
+ 0x85, 0x6a, 0x32, 0xdd, 0xa8, 0x47, 0x1f, 0xf0, 0xaf, 0x40, 
+ 0x18, 0xf7, 0xa6, 0x49, 0x11, 0xfe, 0xa1, 0x4e, 0x16, 0xf9, 
+ 0xb4, 0x5b, 0x03, 0xec, 0xb3, 0x5c, 0x04, 0xeb, 0xba, 0x55, 
+ 0x0d, 0xe2, 0xbd, 0x52, 0x0a, 0xe5};
+
+static const unsigned char GF_5B[256] = {
+ 0x00, 0x5b, 0xb6, 0xed, 0x05, 0x5e, 0xb3, 0xe8, 0x0a, 0x51, 
+ 0xbc, 0xe7, 0x0f, 0x54, 0xb9, 0xe2, 0x14, 0x4f, 0xa2, 0xf9, 
+ 0x11, 0x4a, 0xa7, 0xfc, 0x1e, 0x45, 0xa8, 0xf3, 0x1b, 0x40, 
+ 0xad, 0xf6, 0x28, 0x73, 0x9e, 0xc5, 0x2d, 0x76, 0x9b, 0xc0, 
+ 0x22, 0x79, 0x94, 0xcf, 0x27, 0x7c, 0x91, 0xca, 0x3c, 0x67, 
+ 0x8a, 0xd1, 0x39, 0x62, 0x8f, 0xd4, 0x36, 0x6d, 0x80, 0xdb, 
+ 0x33, 0x68, 0x85, 0xde, 0x50, 0x0b, 0xe6, 0xbd, 0x55, 0x0e, 
+ 0xe3, 0xb8, 0x5a, 0x01, 0xec, 0xb7, 0x5f, 0x04, 0xe9, 0xb2,
+ 0x44, 0x1f, 0xf2, 0xa9, 0x41, 0x1a, 0xf7, 0xac, 0x4e, 0x15, 
+ 0xf8, 0xa3, 0x4b, 0x10, 0xfd, 0xa6, 0x78, 0x23, 0xce, 0x95, 
+ 0x7d, 0x26, 0xcb, 0x90, 0x72, 0x29, 0xc4, 0x9f, 0x77, 0x2c, 
+ 0xc1, 0x9a, 0x6c, 0x37, 0xda, 0x81, 0x69, 0x32, 0xdf, 0x84, 
+ 0x66, 0x3d, 0xd0, 0x8b, 0x63, 0x38, 0xd5, 0x8e, 0xa0, 0xfb, 
+ 0x16, 0x4d, 0xa5, 0xfe, 0x13, 0x48, 0xaa, 0xf1, 0x1c, 0x47, 
+ 0xaf, 0xf4, 0x19, 0x42, 0xb4, 0xef, 0x02, 0x59, 0xb1, 0xea, 
+ 0x07, 0x5c, 0xbe, 0xe5, 0x08, 0x53, 0xbb, 0xe0, 0x0d, 0x56, 
+ 0x88, 0xd3, 0x3e, 0x65, 0x8d, 0xd6, 0x3b, 0x60, 0x82, 0xd9, 
+ 0x34, 0x6f, 0x87, 0xdc, 0x31, 0x6a, 0x9c, 0xc7, 0x2a, 0x71, 
+ 0x99, 0xc2, 0x2f, 0x74, 0x96, 0xcd, 0x20, 0x7b, 0x93, 0xc8, 
+ 0x25, 0x7e, 0xf0, 0xab, 0x46, 0x1d, 0xf5, 0xae, 0x43, 0x18, 
+ 0xfa, 0xa1, 0x4c, 0x17, 0xff, 0xa4, 0x49, 0x12, 0xe4, 0xbf, 
+ 0x52, 0x09, 0xe1, 0xba, 0x57, 0x0c, 0xee, 0xb5, 0x58, 0x03, 
+ 0xeb, 0xb0, 0x5d, 0x06, 0xd8, 0x83, 0x6e, 0x35, 0xdd, 0x86, 
+ 0x6b, 0x30, 0xd2, 0x89, 0x64, 0x3f, 0xd7, 0x8c, 0x61, 0x3a, 
+ 0xcc, 0x97, 0x7a, 0x21, 0xc9, 0x92, 0x7f, 0x24, 0xc6, 0x9d, 
+ 0x70, 0x2b, 0xc3, 0x98, 0x75, 0x2e};
+
+#define sbox(i, x) ((unsigned long)SBOX[i][(x)&255])
+
+#else
+
+/* The Q-box tables */
+static const unsigned char qbox[2][4][16] = { 
+{
+   { 0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4 },
+   { 0xE, 0XC, 0XB, 0X8, 0X1, 0X2, 0X3, 0X5, 0XF, 0X4, 0XA, 0X6, 0X7, 0X0, 0X9, 0XD },
+   { 0XB, 0XA, 0X5, 0XE, 0X6, 0XD, 0X9, 0X0, 0XC, 0X8, 0XF, 0X3, 0X2, 0X4, 0X7, 0X1 },
+   { 0XD, 0X7, 0XF, 0X4, 0X1, 0X2, 0X6, 0XE, 0X9, 0XB, 0X3, 0X0, 0X8, 0X5, 0XC, 0XA }
+}, 
+{
+   { 0X2, 0X8, 0XB, 0XD, 0XF, 0X7, 0X6, 0XE, 0X3, 0X1, 0X9, 0X4, 0X0, 0XA, 0XC, 0X5 },
+   { 0X1, 0XE, 0X2, 0XB, 0X4, 0XC, 0X3, 0X7, 0X6, 0XD, 0XA, 0X5, 0XF, 0X9, 0X0, 0X8 },
+   { 0X4, 0XC, 0X7, 0X5, 0X1, 0X6, 0X9, 0XA, 0X0, 0XE, 0XD, 0X8, 0X2, 0XB, 0X3, 0XF },
+   { 0xB, 0X9, 0X5, 0X1, 0XC, 0X3, 0XD, 0XE, 0X6, 0X4, 0X7, 0XF, 0X2, 0X0, 0X8, 0XA }
+}
+};
+
+/* computes S_i[x] */
+#ifdef CLEAN_STACK
+static unsigned long _sbox(int i, unsigned long x)
+#else
+unsigned long sbox(int i, unsigned long x)
+#endif
+{
+   unsigned char a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,y;
+
+   /* a0,b0 = [x/16], x mod 16 */
+   a0 = (x>>4)&15;
+   b0 = (x)&15;
+
+   /* a1 = a0 ^ b0 */
+   a1 = a0 ^ b0;
+
+   /* b1 = a0 ^ ROR(b0, 1) ^ 8a0 */
+   b1 = (a0 ^ ((b0<<3)|(b0>>1)) ^ (a0<<3)) & 15;
+
+   /* a2,b2 = t0[a1], t1[b1] */
+   a2 = qbox[i][0][a1];
+   b2 = qbox[i][1][b1];
+
+   /* a3 = a2 ^ b2 */
+   a3 = a2 ^ b2;
+
+   /* b3 = a2 ^ ROR(b2, 1) ^ 8a2 */
+   b3 = (a2 ^ ((b2<<3)|(b2>>1)) ^ (a2<<3)) & 15;
+
+   /* a4,b4 = t2[a3], t3[b3] */
+   a4 = qbox[i][2][a3];
+   b4 = qbox[i][3][b3];
+
+   /* y = 16b4 + a4 */
+   y = (b4 << 4) + a4;
+
+   /* return result */
+   return (unsigned long)y;
+}
+
+#ifdef CLEAN_STACK
+static unsigned long sbox(int i, unsigned long x)
+{
+   unsigned long y;
+   y = _sbox(i, x);
+   burn_stack(sizeof(unsigned char) * 11);
+   return y;
+}
+#endif
+
+#endif
+
+/* computes ab mod p */
+static unsigned long gf_mult(unsigned long a, unsigned long b, unsigned long p)
+{
+   unsigned long result = 0;
+   while (a) {
+      if (a&1)
+         result ^= b;
+      a >>= 1;
+      b <<= 1;
+      if (b & 0x100)
+         b ^= p;
+   }
+   return result & 255;
+}
+
+
+/* Computes [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3] */
+static void mds_mult(const unsigned char *in, unsigned char *out)
+{
+  int x, y;
+  unsigned char tmp[4];
+
+  for (x = 0; x < 4; x++) {
+      tmp[x] = 0;
+      for (y = 0; y < 4; y++)
+          tmp[x] ^= gf_mult(in[y], MDS[x][y], MDS_POLY);
+  }
+  for (x = 0; x < 4; x++)
+      out[x] = tmp[x];
+  zeromem(tmp, 4);
+}
+
+/* computes [y0 y1 y2 y3] = RS . [x0 x1 x2 x3 x4 x5 x6 x7] */
+static void rs_mult(const unsigned char *in, unsigned char *out)
+{
+  int x, y;
+  unsigned char tmp[4];
+
+  for (x = 0; x < 4; x++) {
+      tmp[x] = 0;
+      for (y = 0; y < 8; y++)
+          tmp[x] ^= gf_mult(in[y], RS[x][y], RS_POLY);
+  }
+  for (x = 0; x < 4; x++)
+      out[x] = tmp[x];
+  zeromem(tmp, 4);
+}
+
+/* computes [y0 y1 y2 y3] = MDS . [x0] */
+#ifndef TWOFISH_TABLES
+static unsigned long mds_column_mult(unsigned char in, int col)
+{
+   return
+       (gf_mult(in, MDS[0][col], MDS_POLY) << 0) |
+       (gf_mult(in, MDS[1][col], MDS_POLY) << 8) |
+       (gf_mult(in, MDS[2][col], MDS_POLY) << 16) |
+       (gf_mult(in, MDS[3][col], MDS_POLY) << 24);
+}
+#else
+static unsigned long mds_column_mult(unsigned char in, int col)
+{
+   unsigned long x01, x5B, xEF;
+
+   x01 = in;
+   x5B = GF_5B[in];
+   xEF = GF_EF[in];
+
+   switch (col) {
+       case 0:
+          return (x01 << 0 ) |
+                 (x5B << 8 ) |
+                 (xEF << 16) |
+                 (xEF << 24);
+       case 1:
+          return (xEF << 0 ) |
+                 (xEF << 8 ) |
+                 (x5B << 16) |
+                 (x01 << 24);
+       case 2:
+          return (x5B << 0 ) |
+                 (xEF << 8 ) |
+                 (x01 << 16) |
+                 (xEF << 24);
+       case 3:
+          return (x5B << 0 ) |
+                 (x01 << 8 ) |
+                 (xEF << 16) |
+                 (x5B << 24);
+   }
+   /* avoid warnings, we'd never get here normally but just to calm compiler warnings... */
+   return 0;
+}
+#endif
+
+/* computes h(x) */
+static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M, int k, int offset)
+{
+  int x;
+  unsigned char y[4];
+
+  for (x = 0; x < 4; x++)
+      y[x] = in[x];
+
+  switch (k) {
+     case 4:
+            y[0] = sbox(1, y[0]) ^ M[4 * (6 + offset) + 0];
+            y[1] = sbox(0, y[1]) ^ M[4 * (6 + offset) + 1];
+            y[2] = sbox(0, y[2]) ^ M[4 * (6 + offset) + 2];
+            y[3] = sbox(1, y[3]) ^ M[4 * (6 + offset) + 3];
+     case 3:
+            y[0] = sbox(1, y[0]) ^ M[4 * (4 + offset) + 0];
+            y[1] = sbox(1, y[1]) ^ M[4 * (4 + offset) + 1];
+            y[2] = sbox(0, y[2]) ^ M[4 * (4 + offset) + 2];
+            y[3] = sbox(0, y[3]) ^ M[4 * (4 + offset) + 3];
+     case 2:
+            y[0] = sbox(1, sbox(0, sbox(0, y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0]);
+            y[1] = sbox(0, sbox(0, sbox(1, y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1]);
+            y[2] = sbox(1, sbox(1, sbox(0, y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2]);
+            y[3] = sbox(0, sbox(1, sbox(1, y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3]);
+  }
+  mds_mult(y, out);
+}
+
+#ifndef TWOFISH_SMALL
+
+static unsigned long g_func(unsigned long x, symmetric_key *key)
+{
+   return
+       key->twofish.S[0][(x>>0)&255] ^
+       key->twofish.S[1][(x>>8)&255] ^
+       key->twofish.S[2][(x>>16)&255] ^
+       key->twofish.S[3][(x>>24)&255];
+}
+
+#else
+
+#ifdef CLEAN_STACK
+static unsigned long _g_func(unsigned long x, symmetric_key *key)
+#else
+unsigned long g_func(unsigned long x, symmetric_key *key)
+#endif
+{
+   unsigned char g, i, y, z;
+   unsigned long res;
+
+   res = 0;
+   for (y = 0; y < 4; y++) {
+       z = key->twofish.start;
+
+       /* do unkeyed substitution */
+       g = sbox(qord[y][z++], (x >> (8*y)) & 255);
+
+       /* first subkey */
+       i = 0;
+
+       /* do key mixing+sbox until z==5 */
+       while (z != 5) {
+          g = g ^ key->twofish.S[4*i++ + y];
+          g = sbox(qord[y][z++], g);
+       }
+
+       /* multiply g by a column of the MDS */
+       res ^= mds_column_mult(g, y);
+   }
+   return res;
+}
+
+#ifdef CLEAN_STACK
+static unsigned long g_func(unsigned long x, symmetric_key *key)
+{
+    unsigned long y;
+    y = _g_func(x, key);
+    burn_stack(sizeof(unsigned char) * 4 + sizeof(unsigned long));
+    return y;
+}
+#endif
+
+#endif
+
+#ifdef CLEAN_STACK
+static int _twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+#ifndef TWOFISH_SMALL
+   int g, 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;
+
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* invalid arguments? */
+   if (num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16 && keylen != 24 && keylen != 32) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* k = keysize/64 [but since our keysize is in bytes...] */
+   k = keylen / 8;
+
+   /* copy the key into M */
+   for (x = 0; x < keylen; x++)
+       M[x] = key[x];
+
+   /* create the S[..] words */
+#ifndef TWOFISH_SMALL
+   for (x = 0; x < k; x++)
+       rs_mult(M+(x*8), S+(x*4));
+#else
+   for (x = 0; x < k; x++)
+       rs_mult(M+(x*8), skey->twofish.S+(x*4));
+#endif
+
+   /* make subkeys */
+   for (x = 0; x < 20; x++) {
+       /* A = h(p * 2x, Me) */
+       for (y = 0; y < 4; y++)
+           tmp[y] = x+x;
+       h_func(tmp, tmp2, M, k, 0);
+       LOAD32L(A, tmp2);
+
+       /* B = ROL(h(p * (2x + 1), Mo), 8) */
+       for (y = 0; y < 4; y++)
+           tmp[y] = x+x+1;
+       h_func(tmp, tmp2, M, k, 1);
+       LOAD32L(B, tmp2);
+       B = ROL(B, 8);
+
+       /* K[2i]   = A + B */
+       skey->twofish.K[x+x] = (A + B) & 0xFFFFFFFFUL;
+
+       /* K[2i+1] = (A + 2B) <<< 9 */
+       skey->twofish.K[x+x+1] = ROL(B + B + A, 9);
+   }
+
+   /* where to start in the sbox layers */
+   switch (k) {
+         case 4 : start = 0; break;
+         case 3 : start = 1; break; 
+         default: start = 2; break;
+   }
+
+#ifndef TWOFISH_SMALL
+   /* make the sboxes (large ram variant) */
+   for (y = 0; y < 4; y++) {
+       for (x = 0; x < 256; x++) {
+           z = start;
+
+           /* do unkeyed substitution */
+           g = sbox(qord[y][z++], x);
+
+           /* first subkey */
+           i = 0;
+
+           /* do key mixing+sbox until z==5 */
+           while (z != 5) {
+               g = g ^ S[4*i++ + y];
+               g = sbox(qord[y][z++], g);
+           }
+           
+           /* multiply g by a column of the MDS */
+           skey->twofish.S[y][x] = mds_column_mult(g, y);
+       }
+   }
+#else
+   /* small ram variant */
+   skey->twofish.start = start;
+#endif
+   return CRYPT_OK;
+}
+
+#ifdef CLEAN_STACK
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _twofish_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(int) * 7 + sizeof(unsigned char) * 56 + sizeof(unsigned long) * 2);
+   return x;
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+#else
+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;
+    int r;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+
+    LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]);
+    LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]);
+    a ^= key->twofish.K[0];
+    b ^= key->twofish.K[1];
+    c ^= key->twofish.K[2];
+    d ^= key->twofish.K[3];
+
+    for (r = 0; r < 16; r += 2) {
+        t1 = g_func(a, key);
+        t2 = g_func(ROL(b, 8), key);
+        t2 += (t1 += t2);
+        t1 += key->twofish.K[r+r+8];
+        t2 += key->twofish.K[r+r+9];
+        c  ^= t1; c = ROR(c, 1);
+        d  = ROL(d, 1) ^ t2;
+
+        t1 = g_func(c, key);
+        t2 = g_func(ROL(d, 8), key);
+        t2 += (t1 += t2);
+        t1 += key->twofish.K[r+r+10];
+        t2 += key->twofish.K[r+r+11];
+        a ^= t1; a = ROR(a, 1);
+        b  = ROL(b, 1) ^ t2;
+    }
+
+    /* output with "undo last swap" */
+    ta = c ^ key->twofish.K[4];
+    tb = d ^ key->twofish.K[5];
+    tc = a ^ key->twofish.K[6];
+    td = b ^ key->twofish.K[7];
+
+    /* store output */
+    STORE32L(ta,&ct[0]); STORE32L(tb,&ct[4]);
+    STORE32L(tc,&ct[8]); STORE32L(td,&ct[12]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+#ifdef CLEAN_STACK
+static void _twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+#else
+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;
+    int r;
+
+    _ARGCHK(pt != NULL);
+    _ARGCHK(ct != NULL);
+    _ARGCHK(key != NULL);
+
+    /* load input */
+    LOAD32L(ta,&ct[0]); LOAD32L(tb,&ct[4]);
+    LOAD32L(tc,&ct[8]); LOAD32L(td,&ct[12]);
+
+    /* undo undo final swap */
+    a = tc ^ key->twofish.K[6];
+    b = td ^ key->twofish.K[7];
+    c = ta ^ key->twofish.K[4];
+    d = tb ^ key->twofish.K[5];
+
+    for (r = 14; r >= 0; r -= 2) {
+        t1 = g_func(c, key);
+        t2 = g_func(ROL(d, 8), key);
+        t2 += (t1 += t2);
+        t1 += key->twofish.K[r+r+10];
+        t2 += key->twofish.K[r+r+11];
+        a  = ROL(a, 1) ^ t1;
+        b  = b ^ t2; b = ROR(b, 1);
+
+        t1 = g_func(a, key);
+        t2 = g_func(ROL(b, 8), key);
+        t2 += (t1 += t2);
+        t1 += key->twofish.K[r+r+8];
+        t2 += key->twofish.K[r+r+9];
+        c  = ROL(c, 1) ^ t1;
+        d  = d ^ t2; d = ROR(d, 1);
+    }
+
+    /* pre-white */
+    a ^= key->twofish.K[0];
+    b ^= key->twofish.K[1];
+    c ^= key->twofish.K[2];
+    d ^= key->twofish.K[3];
+    
+    /* store */
+    STORE32L(a, &pt[0]); STORE32L(b, &pt[4]);
+    STORE32L(c, &pt[8]); STORE32L(d, &pt[12]);
+}
+
+#ifdef CLEAN_STACK
+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));
+}
+#endif
+
+int twofish_test(void)
+{
+ static const unsigned char key128[16] = {
+     0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32,
+     0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A };
+ static const unsigned char pt128[16] = {
+     0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E,
+     0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 };
+ static const unsigned char ct128[16] = {
+     0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85,
+     0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 };
+
+ static const unsigned char key192[24] = {
+     0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36,
+     0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
+     0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44 };
+ static const unsigned char pt192[16] = {
+     0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5,
+     0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 };
+ static const unsigned char ct192[16] = {
+     0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45,
+     0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 };
+
+ static const unsigned char key256[32] = {
+     0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
+     0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
+     0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B,
+     0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F };
+ static const unsigned char pt256[16] = {
+     0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F,
+     0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 };
+ static const unsigned char ct256[16] = {
+     0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97,
+     0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA };
+
+ symmetric_key key;
+ unsigned char tmp[2][16];
+ int errno;
+
+ if ((errno = twofish_setup(key128, 16, 0, &key)) != CRYPT_OK) {
+    return errno;
+ }
+ twofish_ecb_encrypt(pt128, tmp[0], &key);
+ twofish_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct128, 16) || memcmp(tmp[1], pt128, 16)) {
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+ 
+ if ((errno = twofish_setup(key192, 24, 0, &key)) != CRYPT_OK) {
+    return errno;
+ }
+ twofish_ecb_encrypt(pt192, tmp[0], &key);
+ twofish_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct192, 16) || memcmp(tmp[1], pt192, 16)) {
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ if ((errno = twofish_setup(key256, 32, 0, &key)) != CRYPT_OK)  {
+    return errno;
+ }
+ twofish_ecb_encrypt(pt256, tmp[0], &key);
+ twofish_ecb_decrypt(tmp[0], tmp[1], &key);
+ if (memcmp(tmp[0], ct256, 16) || memcmp(tmp[1], pt256, 16)) {
+    return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ return CRYPT_OK;
+}
+
+int twofish_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize);
+   if (*desired_keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*desired_keysize < 24) {
+      *desired_keysize = 16;
+      return CRYPT_OK;
+   } else if (*desired_keysize < 32) {
+      *desired_keysize = 24;
+      return CRYPT_OK;
+   } else {
+      *desired_keysize = 32;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+
+
+

+ 121 - 0
xtea.c

@@ -0,0 +1,121 @@
+#include "mycrypt.h"
+
+#ifdef XTEA
+
+const struct _cipher_descriptor xtea_desc =
+{
+    "xtea",
+    1,
+    16, 16, 8, 32,
+    &xtea_setup,
+    &xtea_ecb_encrypt,
+    &xtea_ecb_decrypt,
+    &xtea_test,
+    &xtea_keysize
+};
+
+int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   _ARGCHK(key != NULL);
+   _ARGCHK(skey != NULL);
+
+   /* check arguments */
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (num_rounds != 0 && num_rounds != 32) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* load key */
+   LOAD32L(skey->xtea.K[0], key+0);
+   LOAD32L(skey->xtea.K[1], key+4);
+   LOAD32L(skey->xtea.K[2], key+8);
+   LOAD32L(skey->xtea.K[3], key+12);
+   return CRYPT_OK;
+}
+
+void xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key)
+{
+   unsigned long y, z, sum;
+   int r;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   LOAD32L(y, &pt[0]);
+   LOAD32L(z, &pt[4]);
+   sum = 0;
+   for (r = 0; r < 32; r++) {
+       y = (y + ((((z<<4)^(z>>5)) + z) ^ (sum + key->xtea.K[sum&3]))) & 0xFFFFFFFFUL;
+       sum = (sum + 0x9E3779B9UL) & 0xFFFFFFFFUL;
+       z = (z + ((((y<<4)^(y>>5)) + y) ^ (sum + key->xtea.K[(sum>>11)&3]))) & 0xFFFFFFFFUL;
+   }
+   STORE32L(y, &ct[0]);
+   STORE32L(z, &ct[4]);
+}
+
+void xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key)
+{
+   unsigned long y, z, sum;
+   int r;
+
+   _ARGCHK(pt != NULL);
+   _ARGCHK(ct != NULL);
+   _ARGCHK(key != NULL);
+
+   LOAD32L(y, &ct[0]);
+   LOAD32L(z, &ct[4]);
+   sum = (32UL*0x9E3779B9UL)&0xFFFFFFFFUL;
+   for (r = 0; r < 32; r++) {
+       z = (z - ((((y<<4)^(y>>5)) + y) ^ (sum + key->xtea.K[(sum>>11)&3]))) & 0xFFFFFFFFUL;
+       sum = (sum - 0x9E3779B9UL) & 0xFFFFFFFFUL;
+       y = (y - ((((z<<4)^(z>>5)) + z) ^ (sum + key->xtea.K[sum&3]))) & 0xFFFFFFFFUL;
+   }
+   STORE32L(y, &pt[0]);
+   STORE32L(z, &pt[4]);
+}
+
+int xtea_test(void)
+{
+   static const unsigned char key[16] = 
+      { 0x78, 0x56, 0x34, 0x12, 0xf0, 0xcd, 0xcb, 0x9a,
+        0x48, 0x37, 0x26, 0x15, 0xc0, 0xbf, 0xae, 0x9d };
+   static const unsigned char pt[8] = 
+      { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+   static const unsigned char ct[8] = 
+      { 0x75, 0xd7, 0xc5, 0xbf, 0xcf, 0x58, 0xc9, 0x3f };
+   unsigned char tmp[2][8];
+   symmetric_key skey;
+   int errno;
+
+   if ((errno = xtea_setup(key, 16, 0, &skey)) != CRYPT_OK)  {
+      return errno;
+   }
+   xtea_ecb_encrypt(pt, tmp[0], &skey);
+   xtea_ecb_decrypt(tmp[0], tmp[1], &skey);
+
+   if (memcmp(tmp[0], ct, 8) || memcmp(tmp[1], pt, 8)) { 
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+}
+
+int xtea_keysize(int *desired_keysize)
+{
+   _ARGCHK(desired_keysize);
+   if (*desired_keysize < 16) {
+      return CRYPT_INVALID_KEYSIZE; 
+   }
+   *desired_keysize = 16;
+   return CRYPT_OK;
+}
+
+
+#endif
+
+
+

+ 144 - 0
yarrow.c

@@ -0,0 +1,144 @@
+#include "mycrypt.h"
+
+#ifdef YARROW
+
+const struct _prng_descriptor yarrow_desc =
+{
+    "yarrow",
+    &yarrow_start,
+    &yarrow_add_entropy,
+    &yarrow_ready,
+    &yarrow_read
+};
+
+int yarrow_start(prng_state *prng)
+{
+   int errno;
+   
+   _ARGCHK(prng != NULL);
+
+   /* these are the default hash/cipher combo used */
+#ifdef RIJNDAEL
+   prng->yarrow.cipher = register_cipher(&rijndael_desc);
+#elif defined(BLOWFISH)
+   prng->yarrow.cipher = register_cipher(&blowfish_desc);
+#elif defined(TWOFISH)
+   prng->yarrow.cipher = register_cipher(&twofish_desc);
+#elif defined(CAST5)
+   prng->yarrow.cipher = register_cipher(&cast5_desc);
+#elif defined(SERPENT)
+   prng->yarrow.cipher = register_cipher(&serpent_desc);
+#elif defined(SAFER)
+   prng->yarrow.cipher = register_cipher(&saferp_desc);
+#elif defined(RC5)
+   prng->yarrow.cipher = register_cipher(&rc5_desc);
+#elif defined(RC6)
+   prng->yarrow.cipher = register_cipher(&rc6_desc);
+#elif defined(XTEA)
+   prng->yarrow.cipher = register_cipher(&xtea_desc);
+#elif defined(RC2)
+   prng->yarrow.cipher = register_cipher(&rc2_desc);
+#elif defined(DES)
+   prng->yarrow.cipher = register_cipher(&des3_desc);
+#elif
+   #error YARROW needs at least one CIPHER
+#endif
+   if ((errno = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+#ifdef SHA256
+   prng->yarrow.hash   = register_hash(&sha256_desc);
+#elif defined(SHA512)
+   prng->yarrow.hash   = register_hash(&sha512_desc);
+#elif defined(SHA384)
+   prng->yarrow.hash   = register_hash(&sha384_desc);
+#elif defined(SHA1)
+   prng->yarrow.hash   = register_hash(&sha1_desc);
+#elif defined(TIGER)
+   prng->yarrow.hash   = register_hash(&tiger_desc);
+#elif defined(MD5)
+   prng->yarrow.hash   = register_hash(&md5_desc);
+#elif defined(MD4)
+   prng->yarrow.hash   = register_hash(&md4_desc);
+#elif defined(MD2)
+   prng->yarrow.hash   = register_hash(&md2_desc);
+#else
+   #error YARROW needs at least one HASH
+#endif
+   if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* zero the memory used */
+   zeromem(prng->yarrow.pool, sizeof(prng->yarrow.pool));
+
+   return CRYPT_OK;
+}
+
+int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
+{
+   hash_state md;
+   int errno;
+
+   _ARGCHK(buf != NULL);
+   _ARGCHK(prng != NULL);
+
+   if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* start the hash */
+   hash_descriptor[prng->yarrow.hash].init(&md);
+
+   /* hash the current pool */
+   hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool, hash_descriptor[prng->yarrow.hash].hashsize);
+
+   /* add the new entropy */
+   hash_descriptor[prng->yarrow.hash].process(&md, buf, len);
+
+   /* store result */
+   hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool);
+
+   return CRYPT_OK;
+}
+
+int yarrow_ready(prng_state *prng)
+{
+   int ks, errno;
+
+   _ARGCHK(prng != NULL);
+
+   if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      return errno;
+   }
+   
+   if ((errno = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
+      return errno;
+   }
+
+   /* setup CTR mode using the "pool" as the key */
+   ks = hash_descriptor[prng->yarrow.hash].hashsize;
+   if ((errno = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) {
+      return errno;
+   }
+
+   if ((errno = ctr_start(prng->yarrow.cipher, prng->yarrow.pool, prng->yarrow.pool, ks, 0, &prng->yarrow.ctr)) != CRYPT_OK) {
+      return errno;
+   }
+   return CRYPT_OK;
+}
+
+unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng)
+{
+   _ARGCHK(buf != NULL);
+   _ARGCHK(prng != NULL);
+
+   if (ctr_encrypt(buf, buf, len, &prng->yarrow.ctr) != CRYPT_OK) {
+      return 0;
+   }
+   return len;
+}
+
+#endif
+