/* --------------------------------------------------------------------

 hermes Algorithm   (c) 2005  Dr. Ulrich Kaiser, (Texas Instruments) Germany

 UK20050317 initial version, copy from sc.c
 UK20050318 added visible stream and binary stream
 UK20050320 added initialization of RandReg
 UK20050328 added SBOX application to key byte afer init, after 11 rounds
            added plaintext length
	    added Hermes_encrypt
 UK20050403 added loop to Hermes_encrypt; added Hermes_decrypt
 UK20050408 added encrypt/decrypt loopback check;
            added chisquare test to Hermes_encrypt.
 UK20050410 added FIPS 140-2 test to Hermes_encrypt
 UK20050415 added SetKey(); added sensitivity test for SAC checking.
 UK20050424 added MY_IV_LENGTH to SetLength for algo dependence.
            added SetPlaintext pattern.
 UK20050517 started changes in order to close the backdoor:
            made p1, p2, accu dependent on key;
	    extended state to 23 resp. 37 bytes;
	    defined variables OUTPUTBYTES, OUTPUTBITS;
	    updated SetLength acordingly.
 UK20050602 corrected setIVlength, 37 max.
            corrected makesequence()
 
  

TODO
- 


----------------------------------------------------------------------- */


#define credits "HERMES   Advanced Stream Cipher  Ulrich Kaiser (c) 2005 "

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


/* statistical tool suite definitions */

#define CHISQ_95 0.00393214
#define CHISQ_90 0.0157908
#define CHISQ_10 2.70554
#define CHISQ_05 3.84146

/* CUSTOMIZE HERE */
#define LOPC 10
#define HIPC 90
#define EXPERIMENTS 100
#define EXPERIMENTSIZE 50

 int TestRounds;
 float CHISQ_LO, CHISQ_HI;




#define K_LENGTH  32
#define S_LENGTH  37
#define S_LENGTH1 23
#define S_LENGTH2 37
#define P_LENGTH   8

#include "ecrypt-sync.h" 

/* working space for other routines: crunch, init, stream */
 u8  k[K_LENGTH];        /* key space    */
 u8  state[S_LENGTH];    /* cipher state */
u32  parm[P_LENGTH];     /* parameters   */

 u8  kh[K_LENGTH];        /* key helper    */

#define X_LENGTH 37
#define Y_LENGTH 32

 unsigned char x[X_LENGTH];
 unsigned char y[Y_LENGTH];



  /* global definition of number of rounds for initialisation ! */
 int MY_INIT_ROUNDS = 10;    


  /* global definition of number of rounds for stream cipher operation ! */
 int MY_SC_ROUNDS = 100;    



  /* global definition of number of IV bytes ! */
 int MY_IV_LENGTH = S_LENGTH;    




  /* global definition of number of plaintext resp. ciphertext bytes ! */
 int MY_PT_LENGTH = 25600; 
 
#define PTSIZE  320000
 u8 my_plaintext[PTSIZE];
 u8 my_ciphertext[PTSIZE];
  
 int MY_PT_PATTERN = 0; 
 
     


/* now dependent on algorithm ...,  is set by SetLength */

 int KEYBYTES = -1;
 int KEYBITS  = -1;

 int STATEBYTES = -1;
 int STATEBITS  = -1;
 
 int OUTPUTBYTES = -1;
 int OUTPUTBITS  = -1;
 
 

 int algo = -1; /* selects algorithm */
#define ALGO_NOT_VALID  "AlgorithmNumber not valid !\n"

#define  choice  "[ Hermes8-80 = 1,  Hermes8-128 = 2 ]"


/* fail cunters */

 int totalfail_runs_test=0;
 int totalfail_long_runs=0;
 int totalfail_poker=0;
 int total_fail_monobit=0;


/* ----- random number generator ----- */
 unsigned char RandReg[8];



/* output file handle */
FILE *op;




/* ---------  S-BOXes for SC algorithm -------------- */


/* ---------- AES code definitions ---------- */

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




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



 unsigned char sboxAF[256] =
 {0xAF, 0x1B, 0xDD, 0xBC, 0x30, 0xEB, 0xF0, 0x56,
  0xC1, 0x08, 0x93, 0x36, 0x03, 0xCB, 0x81, 0x80,
  0x43, 0x2F, 0xDF, 0x2D, 0x26, 0x05, 0x0A, 0xF8,
  0x7D, 0x21, 0xE0, 0xC4, 0x06, 0xD5, 0xA6, 0xE8,
  0x8E, 0x70, 0xDC, 0xA4, 0x6D, 0x23, 0xAC, 0x18,
  0x40, 0x00, 0x64, 0x0E, 0xF6, 0x79, 0xB5, 0x1F,
  0x5D, 0x9A, 0x3B, 0xFA, 0x48, 0x5F, 0x74, 0xA1,
  0x8D, 0xD3, 0x5C, 0x4E, 0x9E, 0x14, 0x25, 0xEF,
  0xD6, 0xC9, 0x3F, 0xC5, 0xA0, 0x10, 0x50, 0xFB,
  0x31, 0xF4, 0x17, 0x88, 0xAB, 0x32, 0x76, 0x3E,
  0x15, 0x2A, 0x3D, 0xA9, 0x52, 0x20, 0xC3, 0xFC,
  0x7B, 0x49, 0x3A, 0x6E, 0xB7, 0x1D, 0xAD, 0xAA,
  0x5A, 0x0D, 0x35, 0x38, 0xC8, 0xF5, 0xF3, 0xB3,
  0x8F, 0xE6, 0x13, 0x55, 0x33, 0x8A, 0xC0, 0x67,
  0x2E, 0xE7, 0x82, 0x8C, 0x09, 0xCF, 0x1E, 0x97,
  0x28, 0x07, 0xBA, 0x4D, 0x42, 0x04, 0x73, 0x41,
  0x5B, 0xB1, 0xF9, 0xE5, 0xF7, 0x6C, 0xD8, 0x12,
  0x8B, 0x84, 0xCC, 0xB0, 0x69, 0x37, 0xAE, 0x6F,
  0xE2, 0xDB, 0x0C, 0x86, 0x29, 0x78, 0x34, 0x7C,
  0x1A, 0x85, 0x27, 0xA3, 0x9B, 0x92, 0xE3, 0xBD,
  0x59, 0x63, 0x66, 0x19, 0xCA, 0x5E, 0xFF, 0x75,
  0x72, 0x24, 0x4F, 0x47, 0x61, 0x11, 0x0B, 0xBE,
  0xA7, 0x16, 0x3C, 0xB2, 0xFD, 0x7F, 0x44, 0x99,
  0x6B, 0x98, 0x22, 0x46, 0x4A, 0x1C, 0x02, 0x6A,
  0x51, 0x39, 0x60, 0x4B, 0x57, 0x01, 0x2C, 0xE1,
  0xEE, 0x83, 0x89, 0xDA, 0x58, 0x0F, 0xBB, 0x2B,
  0xD2, 0xD4, 0x62, 0x9F, 0x90, 0x7E, 0xDE, 0xB8,
  0x4C, 0xCD, 0x68, 0xA8, 0xF2, 0x54, 0xE9, 0xE4,
  0xF1, 0xEA, 0xD7, 0x77, 0x9D, 0x96, 0xEC, 0xFE,
  0xB9, 0x91, 0xBF, 0xD1, 0xD9, 0xA2, 0x95, 0xED,
  0xA5, 0xC2, 0x7A, 0xC6, 0xC7, 0x45, 0x94, 0xB6,
  0x65, 0xD0, 0xCE, 0x9C, 0x71, 0x87, 0xB4, 0x53
 };/* ddt: 19763 4917 854 106 9 2 0 */




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







/************ This is the 8-bit  algorithm under test ***************/
/************ This is the 8-bit  algorithm under test ***************/
/************ This is the 8-bit  algorithm under test ***************/
/*
* DESCRIPTION OF ALGORITHM
*
* accu is one byte
* s-box is a table with 256 bytes, i.e. 8 bit input and 8 bit output
*
* A state byte and a key byte and the previous result (accu)
* are EXORed. Then the s-box function is applied. The output is
* fed into accu and into the oldest state byte.
* Number of initial rounds:    >= 4
* Number of sub-rounds    : 20 (Hermes8-80)  or  32 (Hermes8-128)
*
* Confusion by:   S-Box, non-linear boolean function
* Diffusion by:   Accu overwriting state byte
*
*
* Notation
*
* Hermes8-80
* State register x consists of 20 bytes x[19]..x[0].
* Key register k consists of 10 bytes k[9]..k[0].
* or
* Hermes8-128
* State register x consists of 32 bytes x[31]..x[0].
* Key register k consists of 16 bytes k[15]..k[0].
*
*/

/* ALGO1  ALGO2  */


void dump_state_key( int nx, int nk )
{
   int j;
   fprintf(op, "State: 0x \n");
   for( j=0; j<nx; j++ ){ fprintf(op, " %2x", state[j] );}
   fprintf(op, "\n");
   fprintf(op, "Key:\n 0x ");
   for( j=0; j<nk; j++ ){ fprintf(op, " %2x", k[j] );}
   fprintf(op, "\n");
}/* dump_state_key ------------------------------------ */


void dump_key_hex( int nk )
{
   int j;
   fprintf(op, "Key: 0x \n");
   for( j=0; j<nk; j++ ){ fprintf(op, " %2x", k[j] );}
   fprintf(op, "\n");
   printf( "Key: 0x \n");
   for( j=0; j<nk; j++ ){ printf( " %2x", k[j] );}
   printf( "\n");
}/* dump_key_hex ------------------------------------ */


/*
The routine crunch_Hermes8 is needed to evaluate the quality of the
initialization, i.e. find the number of initial rounds that are
needed to get a proper avalanche effect for the state vector.
*/
void crunch_Hermes8( unsigned char xin[], unsigned char y[], 
                 unsigned char k[],   int algo )
{
  int	  j;       /* inner counter */
  int     nx;      /* number of state bytes */
  int     nk;      /* number of key bytes */

  int	  round;   /* round counter */
  int     src;     /* sub-round counter */
  int     p1;      /* pointer to actual state byte */
  int     p2;      /* pointer to actual key byte */
  unsigned char accu;
  unsigned char state[S_LENGTH];

  int     nrounds; /* number of rounds to run */
  u16     p3, p4;  /* scratch */
  u8      tmp;     /* scratch */


  /* copy needed in order to destroy k in menu ! */
  for( j=0; j<K_LENGTH; j++ ){  kh[j] = k[j]; }
  
 
  /* local copy needed in order to avoid overwriting xin ! */
  for( j=0; j<S_LENGTH1; j++ ){  state[j] = xin[j]; }
  nx = S_LENGTH1;
  nk = 10;
  if( algo == 2 )
  { 
     for( j=20; j<S_LENGTH2; j++ ){  state[j] = xin[j]; }
     nx = S_LENGTH2; 
     nk = 16; 
  }
  for( j=MY_IV_LENGTH; j<S_LENGTH2; j++ ){  state[j] = 0; }


  nrounds = MY_INIT_ROUNDS;  /* number of rounds, i.e. outer loop count !! */

  p1   = ( k[0] ^ k[1] ^ k[2] )  % nx ;
  p2   = ( k[3] ^ k[4] ^ k[5] )  % nk ;
  accu =   k[6] ^ k[7] ^ k[8]  ;
#define KEY_STEP3  7
  src  = ( k[9] ^ k[0] ^ k[3] )  %  KEY_STEP3;


  for( round=1;  round <= nrounds; round++ )
  { 
	   
#include "hermes_core2.h"
	    
  }/* for round */



  /* copy result to output */
  for( j=0; j<S_LENGTH1; j++ ){ y[j] = state[j]; }
  if( algo == 2 )
  {
     for( j=20; j<S_LENGTH2; j++ ){ y[j] = state[j]; }
  }

  /* dump_key_hex( nk ); */
/*   
   dump_state_key( nx, nk );
   
   fprintf(op, "State: 0x \n");
   for( j=0; j<nx; j++ ){ fprintf(op, " %2x", state[j] );}
   fprintf(op, "\n");  
   
 */   
  /* restore key array (for crunch only!) */
  for( j=0; j<K_LENGTH; j++ ){  k[j] = kh[j]; }
  

} /* crunch_Hermes8 ------------------------------------------------ */



/*
Does not generate stream bytes, but uses the initialization vector to feed the
state register and to run some rounds in order to obtain initial avalanche
effect. Do not use the state bytes !!!
*/
void Hermes8_init( unsigned char iv[], unsigned char k[], unsigned char state[], 
               u32 parameters[],   int nx,   int nk,  int n_init )
{
  u16	  round;   /* round counter */
  int     src;     /* sub-round counter */
  u16     p1;      /* pointer to actual state byte */
  u16     p2;      /* pointer to actual key byte */
  u8      accu;

  u16     p3, p4;  /* scratch */
  int     nrounds; /* number of rounds to run */
  int     j;
  u8      tmp;     /* scratch */



  /* feed state[] with Initialization Vector */
  for( j=0; j<nx; j++ ){  state[j] = iv[j]; }
  for( j=MY_IV_LENGTH; j<S_LENGTH; j++ ){  state[j] = 0; }


  for( j=0; j<nk; j++){ printf(" %2d  0x%2x \n", j, k[j] ); }
  printf(" key setup done. \n");
  for( j=0; j<nk; j++){ fprintf(op, " %2d  0x%2x \n", j, k[j] ); }
  fprintf(op, " key setup done. \n");



  for( j=0; j<nx; j++){ printf(" %2d  0x%2x \n", j, state[j] ); }
  printf(" IV setup done. \n");
  for( j=0; j<nx; j++){ fprintf(op, " %2d  0x%2x \n", j, state[j] ); }
  fprintf(op, " IV setup done. \n");



  /* ----------------- start of algorithm ----------------- */

  fprintf(op, "Hermes8_init  started...\n");
  
  nrounds =  n_init; /* number of rounds, i.e. outer loop count !! */

  p1   = ( k[0] ^ k[1] ^ k[2] )  % nx ;
  p2   = ( k[3] ^ k[4] ^ k[5] )  % nk ;
  accu =   k[6] ^ k[7] ^ k[8]  ;
#define KEY_STEP3  7
  src  = ( k[9] ^ k[0] ^ k[3] )  %  KEY_STEP3;

  for( round=1;  round <= nrounds; round++ )
  {

#include "hermes_core2.h"

     fprintf(op,"CORE-K   k[%2d]= 0x%2x \n", p3, k[p3] );

  }/* for round */

  parameters[0] = accu;
  parameters[1] = p1;
  parameters[2] = p2;
  parameters[3] = src;
  parameters[4] = n_init;


  printf("INIT   accu=0x%2x p1=%d p2=%d src=%d  round=%d   done.\n",
  parameters[0],parameters[1],parameters[2],parameters[3],parameters[4] );
  fprintf(op, "INIT   accu=0x%2x p1=%d p2=%d src=%d  round=%d   done.\n",
  parameters[0],parameters[1],parameters[2],parameters[3],parameters[4]);
  
  for( j=0; j<MY_IV_LENGTH; j++){ printf(" %2d  0x%2x \n", j, state[j] ); }
  printf(" Initialization done. \n\n");
  for( j=0; j<MY_IV_LENGTH; j++){ fprintf(op, " %2d  0x%2x \n", j, state[j] ); }
  fprintf(op, " Initialization done. \n\n");

  
}/* Hermes8_init ---------------------------------------------------------*/



/*
generates stream bytes for one round only, i.e. as many bytes
as state has available.
*/
int  Hermes8_stream( unsigned char k[], unsigned char state[], 
                 u32 parameters[],   int nx,   int nk       )
{
  u16     p1;      /* pointer to actual state byte */
  u16     p2;      /* pointer to actual key byte */
  u8     accu;
  u16    round;
  int     src;     /* sub-round counter */

  u16     p3, p4;  /* scratch */
  u8      tmp;     /* scratch */
  u16     j, m;


  fprintf(op, "Hermes8_stream started...\n"); 
	
  /* ----------------- start of algorithm ----------------- */
  accu  = parameters[0] & 0x00FF;
  p1	= parameters[1];
  p2	= parameters[2];
  src	= parameters[3];
  round = parameters[4];

  fprintf(op,"STREAM accu= 0x%2x p1=%d p2=%d src=%d round=%d \n", accu, p1, p2, src, round );

#define STREAM_ROUNDS  3

  for( m=1; m<=STREAM_ROUNDS; m++)
  {
     round++; 
#include "hermes_core2.h"
  }
  
  parameters[0] = accu;
  parameters[1] = p1;
  parameters[2] = p2;
  parameters[3] = src;
  parameters[4] = round;

  /* printf(" accu=%d p1=%d p2=%d src=%d  round=%d \n", accu, p1, p2, src, round ); */
  
  return( p1 );
}/* Hermes8_stream ---------------------------------------------------------*/




/*
 The routine stream_Hermes8 is needed to evaluate the quality of the
 long key stream. After initialization very many bits are produced
 and can be tested w.r.t. randomness.
 Uses:  state[], k[], parameters[]
*/
#define YES 1
#define NO  0

void stream_Hermes8( unsigned char xin[], unsigned char y[], 
                 int algo, int init_q )
{
  int	  j;      /* inner counter */
  int     nx;     /* number of state bytes */
  int     nk;     /* number of key bytes */
  int     po;     /* pointer to state[] */

  nx = S_LENGTH1;
  nk = 10;
  if( algo == 2 )
  { 
     nx = S_LENGTH2; 
     nk = 16; 
  }


  
  if( init_q == YES )
  {
     for( j=MY_IV_LENGTH; j<S_LENGTH2; j++ ) /* reset undefined bytes */
       {  xin[j] = 0; }
    /* ********************** */
     Hermes8_init( xin, k, state, parm, nx, nk, MY_INIT_ROUNDS );
    /* ********************** */
  }
  else
  {
    /* ********************** */
     po = Hermes8_stream( k, state, parm, nx, nk ); 
    /* ********************** */
  
     /* copy result to output */
     for( j=0; j<OUTPUTBYTES; j++ )
     { 
         y[j] = state[po];
	 po = po + 2; 
	 if( po >= nx ) po = po - nx;
     }
  }


  /* dump_key_hex( nk ); */
  

} /* stream_Hermes8 ------------------------------------------------ */





/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------  support for ECRYPT  APIs  --------------------- */
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

void print_ciphertext_hex( u32 length )
{
   u32 j;
   
   fprintf(op, "\n");
   fprintf(op, " printing ciphertext now .... \n" );
   for(j=0; j<length; j++ )
   {
      fprintf(op, " %2x", my_ciphertext[j] );
      if( j % 16 == 15 ) fprintf(op, "\n");
   }
   fprintf(op, "\n %d bytes of ciphertext printed. \n", length );
}


void print_ciphertext( u32 length )
{
   u32 j;
   
   fprintf(op, "\n");
   fprintf(op, " printing ciphertext now .... \n" );
   for(j=0; j<length; j++ )
   {
      fprintf(op, " %3d", my_ciphertext[j] );
      if( j % 16 == 15 ) fprintf(op, "\n");
   }
   fprintf(op, "\n %d bytes of ciphertext printed. \n", length );
}



/**
 Run over the full ciphertext and count the occurence of the values as histogram.
 Print the histogram resulta as matrix 16 x 16.
 Calculate the chi-square test.
*/
void ciphertext_histogram( u32 length )
{
   int hist[256];
   int j;
   u32  n, count, index;
   float chisqu;

   for(j=0; j<256; j++ ){ hist[j] = 0; }
   

   for(n=0; n<length; n++ ) /* build histogram */
   {
      hist[ my_ciphertext[n] ]++;
   }

   printf("\nHistogram: \n");  /* print histogram */  
   fprintf(op, "\nHistogram: \n");  /* print histogram */  
   for(j=0; j<256; j++ )
   { 
      printf(" %4d" , hist[j] );
      if( j % 16 == 15 ) printf("\n");
      fprintf(op, " %4d" , hist[j] );
      if( j % 16 == 15 ) fprintf(op, "\n");
   }
   
   
   /* Chi Square Test */
    n = length / 256;
    printf("===> expected value %d \n", n );
    fprintf(op, "===> expected value %d \n", n );
    chisqu = 0.0;
    for( index=0; index<256; index++ ) /* calculate Chi^2 */
    {
	count = hist[index];
	chisqu = chisqu + (count-n)*(count-n)/n ;
    }
    /* v=255, alpha=10%  ==>  x=284.366 */
    printf("===> chisqu = %9.2f   <?   284.336 \n", chisqu );
    fprintf(op, "===> chisqu = %9.2f   <?   284.336 \n", chisqu );
    if( chisqu > 284.336 )
    {
       printf("====> ERROR: chisqu = %6.2f > 284.336   \n", chisqu );
       fprintf(op, "====> ERROR: chisqu = %6.2f > 284.336   \n", chisqu );
    }
    
}/* ciphertext_histogram -------------------------------- */                           



void print_plaintext( u32 length )
{
   u32 j;
   
   fprintf(op, "\n");
   fprintf(op, " printing plaintext now .... \n" );
   for(j=0; j<length; j++ )
   {
      fprintf(op, " %3d", my_plaintext[j] );
      if( j % 16 == 15 ) fprintf(op, "\n");
   }
   fprintf(op, "\n %d bytes of plaintext printed. \n", length );
}

void print_plaintext_hex( u32 length )
{
   u32 j;
   
   fprintf(op, "\n");
   fprintf(op, " printing plaintext now .... \n" );
   for(j=0; j<length; j++ )
   {
      fprintf(op, " %2x", my_plaintext[j] );
      if( j % 16 == 15 ) fprintf(op, "\n");
   }
   fprintf(op, "\n %d bytes of plaintext printed. \n", length );
}




void ECRYPT_dump_state_key( ECRYPT_ctx* ctxx, int nx, int nk )
{
   int j;
   fprintf(op, "State: 0x \n");
   for( j=0; j<nx; j++ ){ fprintf(op," %2x", ctxx->state[j] );}
   fprintf(op,"\n");
   fprintf(op, "Key:0x \n");
   for( j=0; j<nk; j++ ){ fprintf(op," %2x", ctxx->k[j] );}
   fprintf(op,"\n");
}/* ECRYPT_dump_state_key ------------------------------------ */




void ECRYPT_dump_state_hex( ECRYPT_ctx* ctxx, int nx )
{
   int j;
   fprintf(op, "State: 0x \n");
   for( j=0; j<nx; j++ ){ fprintf(op, " %2x", ctxx->state[j] );}
   fprintf(op, "\n");
}/* ECRYPT_dump_state_hex ------------------------------------ */


void ECRYPT_dump_key_hex( ECRYPT_ctx* ctxx, int nk )
{
   int j;
   fprintf(op, "Key:0x \n");
   for( j=0; j<nk; j++ ){ fprintf(op, " %2x", ctxx->k[j] );}
   fprintf(op, "\n");
}/* ECRYPT_dump_key_hex ------------------------------------ */


void dump_IV( u8* x, int nx )
{
   int j;
   fprintf(op, "IV: 0x \n");
   for( j=0; j<nx; j++ ){ fprintf(op, " %2x", x[j] );}
   fprintf(op, "\n");
}/* dump_IV ------------------------------------ */


/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------  ECRYPT  APIs  --------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

/**
 loads key[] into k[] of the ctx record
 stores key size value in record
 stores iv size value in record
 @param  ctx   ptr to record
 @param  key   ptr to array with crypto key
 @param  keysize  in bits
 @param  ivsize   in bits
*/
void ECRYPT_keysetup(
  ECRYPT_ctx* ctx,
  const u8* key,
  u32 keysize,               /* Key size in bits. */
  u32 ivsize )               /* IV size in bits. */ 
{
   u16  j, kb;
   
   kb = keysize / 8;
   for( j=0; j<kb; j++ ){ ctx->k[j] = key[j]; }
   ctx->parm[5] = kb;
   ctx->parm[6] = ivsize / 8;
   
   
   for( j=0; j<kb; j++){ printf(" %2d  0x%2x \n", j, ctx->k[j] ); }
   printf(" ECRYPT_keysetup done. \n");
   for( j=0; j<kb; j++){ fprintf(op, " %2d  0x%2x \n", j, ctx->k[j] ); }
   fprintf(op, " ECRYPT_keysetup done. \n"); 

}/* ECRYPT_keysetup ------------------------------------------ */


/**
 loads iv[] into state[],
 runs initial rounds in order to hide IV and KEY from
  first key stream output.
 @param  ctx   ptr to record
 @param  iv    ptr to array with initial value IV
*/
void ECRYPT_ivsetup(
  ECRYPT_ctx* ctx,
  const u8* iv )
{
   u16     ivb;      /* IV size in bytes. */ 
   u16	   round;    /* round counter */
   u16     nk;       /* number of key bytes */
   u16     nx;       /* number of state bytes */
   u16     p1;       /* pointer to actual state byte */
   u16     p2;       /* pointer to actual key byte */
   u8      accu;
   u16     src;      /* sub-round counter */

   u16     nrounds;  /* number of rounds to run */
   u16     j;        /* little helpers */
   u16     p3, p4;   /* scratch */
   u8      tmp;      /* scratch */
   
   /* fill IV into state[] */
   ivb = ctx->parm[6];
   for( j=0; j<ivb; j++ ){ ctx->state[j] = iv[j]; }

   for( j=0; j<ivb; j++){ printf(" %2d  %2x \n", j, ctx->state[j] ); }
   printf(" ECRYPT_ivsetup done. \n");
   for( j=0; j<ivb; j++){ fprintf(op, " %2d  %2x \n", j, ctx->state[j] ); }
   fprintf(op, " ECRYPT_ivsetup done. \n"); 

   /* ----------------- start of algorithm ----------------- */

   /* fprintf(op, "Hermes8_init  started...\n"); */
  
   nrounds =  MY_INIT_ROUNDS; /* number of rounds, i.e. outer loop count !! */
   nk   = ctx->parm[5]; /* kb */
   nx   = STATEBYTES;   /* state size in bytes */

   p1   = ( k[0] ^ k[1] ^ k[2] )  % nx ;
   p2   = ( k[3] ^ k[4] ^ k[5] )  % nk ;
   accu =   k[6] ^ k[7] ^ k[8]  ;
#define KEY_STEP3  7
   src  = ( k[9] ^ k[0] ^ k[3] )  %  KEY_STEP3;

   for( round=1;  round <= nrounds; round++ )
   {

      #include "hermes_core.h"

   }/* for round */

   ctx->parm[0] = accu;
   ctx->parm[1] = p1;
   ctx->parm[2] = p2;
   ctx->parm[3] = src;
   ctx->parm[4] = MY_INIT_ROUNDS;

  
   printf( "INIT   accu=0x%2x p1=%d p2=%d src=%d  round=%d   done.\n",
   ctx->parm[0],ctx->parm[1],ctx->parm[2],ctx->parm[3],ctx->parm[4] );
   /* fprintf(op, "INIT   accu=%d p1=%d p2=%d src=%d  round=%d   done.\n",
   ctx->parm[0],ctx->parm[1],ctx->parm[2],ctx->parm[3],ctx->parm[4] ); */


   for( j=0; j<ivb; j++){ printf(" %2d 0x%2x \n", j, ctx->state[j] ); }
   printf(" ECRYPT_initialization done. \n\n");
   for( j=0; j<ivb; j++){ fprintf(op, " %2d  0x%2x \n", j, ctx->state[j] ); }
   fprintf(op, " ECRYPT_initialization done. \n\n"); 

}/* ECRYPT_ivsetup ------------------------------------------ */




/**
 Encrypts a certain number of bytes of the plaintext.
 @param  in  ctx          ptr to record
 @param  in  plaintext    ptr to array with plaintext
 @param  out ciphertext   ptr to array with ciphertext
 @param  in  msglen       number of bytes to process
*/
void ECRYPT_encrypt_bytes(
  ECRYPT_ctx* ctx, 
  const u8* plaintext, 
  u8* ciphertext, 
  u32 msglen)         /* Message length in bytes. */ 
{
   u32     round;
   u16     nx;       /* number of state bytes */
   u16     nk;       /* number of key bytes */
   u16     p1;       /* pointer to actual state byte */
   u16     p2;       /* pointer to actual key byte */
   u16     src;      /* sub-round counter */
   u8      accu;
   u16     po;       /* output pointer */

   u16     p3, p4;   /* scratch */
   u8      tmp;      /* scratch */
   u32     m, n, pc; /* little helpers */
   u16     j;        /* little helpers */
   u32     maxloops; /* loops needed to process msglen bytes */
 	
   /* ----------------- start of algorithm ----------------- */
   accu  = ctx->parm[0] & 0x00FF;
   p1    = ctx->parm[1];
   p2	 = ctx->parm[2];
   src   = ctx->parm[3];
   round = ctx->parm[4];
   nk    = ctx->parm[5];
   nx    = ctx->parm[6];

   fprintf(op,"STREAM start  accu=0x%2x  p1=%d p2=%d scr=%d  round=%d \n", accu, p1, p2, src, round );
   printf("STREAM start  accu=0x%2x  p1=%d p2=%d scr=%d  round=%d \n", accu, p1, p2, src, round );

   maxloops = (u32)( msglen / OUTPUTBYTES  + 1.0 );
   pc = 0;

   for( n=0; n<maxloops; n++ )
   {

#define STREAM_ROUNDS  3

      for( m=1; m<=STREAM_ROUNDS; m++)
      {
         round++; 
#include "hermes_core.h"
      }
      
      po = p1;
      for( j=0; j<OUTPUTBYTES; j++ )
      { 
          ciphertext[pc+j] = plaintext[pc+j]^ctx->state[po];
	  po = po + 2;
	  if( po >= nx ) po = po - nx;
      }
      pc = pc + OUTPUTBYTES;

   }/* for n */


   /* printf(" accu=%d p1=%d p2=%d src=%d  round=%d \n", accu, p1, p2, src, round ); */
 
   /* avoid further usage of this routine !!! */
   ctx->parm[1] = 9999;
   ctx->parm[2] = 9999;
   
   /* show resulting state in GUI */
   for(j=0; j<=STATEBYTES; j++){ y[j] = ctx->state[j]; }

}/* ECRYPT_encrypt_bytes ------------------------------------------ */





/**
 Decrypts a certain number of bytes of the plaintext.
 @param  in  ctx          ptr to record
 @param  in  ciphertext   ptr to array with ciphertext
 @param  out plaintext    ptr to array with plaintext
 @param  in  msglen       number of bytes to process
*/
void ECRYPT_decrypt_bytes(
  ECRYPT_ctx* ctx, 
  const u8* ciphertext, 
  u8* plaintext, 
  u32 msglen)         /* Message length in bytes. */ 
{
   u32     round;
   u16     nx;       /* number of state bytes */
   u16     nk;       /* number of key bytes */
   u16     p1;       /* pointer to actual state byte */
   u16     p2;       /* pointer to actual key byte */
   u16     src;      /* sub-round counter */
   u8      accu;
   u16     po;       /* output pointer */

   u16     p3, p4;   /* scratch */
   u8      tmp;      /* scratch */
   u32     n, pc;    /* little helpers */
   u16     j, m;     /* little helpers */
   u32     maxloops; /* loops needed to process msglen bytes */
   
   /* fprintf(op, "Hermes8_stream started...\n"); */
 	
   /* ----------------- start of algorithm ----------------- */
   accu  = ctx->parm[0] & 0x00FF;
   p1    = ctx->parm[1];
   p2	 = ctx->parm[2];
   src   = ctx->parm[3];
   round = ctx->parm[4];
   nk    = ctx->parm[5];
   nx    = ctx->parm[6];
   fprintf(op,"STREAM start  accu=%2x hex  p1=%d p2=%d  round=%d \n", accu, p1, p2, round );
   printf("STREAM start  accu=%2x hex  p1=%d p2=%d  round=%d \n", accu, p1, p2, round );
   
   maxloops = (u32)( msglen / OUTPUTBYTES  + 0.5 );
   pc = 0;

   for( n=0; n<maxloops; n++ )
   {
      for( m=1; m<=STREAM_ROUNDS; m++)
      {
         round++; 
#include "hermes_core.h"
      }
 
      po = p1;
      for( j=0; j<OUTPUTBYTES; j++ )
      { 
          plaintext[pc+j] = ciphertext[pc+j]^ctx->state[po];
	  po = po + 2;
	  if( po >= nx ) po = po - nx;
      }
      pc = pc + OUTPUTBYTES;

   }/* for n */

   /* printf(" accu=%d p1=%d p2=%d src=%d  round=%d \n", accu, p1, p2, src, round ); */
 
   /* avoid further usage of this routine !!! */
   ctx->parm[1] = 9999;
   ctx->parm[2] = 9999;
   
   /* show resulting state in GUI */
   for(j=0; j<=STATEBYTES; j++){ y[j] = ctx->state[j]; }
   
} /* ECRYPT_decrypt_bytes ------------------------------------------ */




/**
 Generates key stream....
 @param  in  ctx          ptr to record
 @param  out keystream    ptr to array with key stream
 @param  in  length       number of bytes to process
*/
void ECRYPT_keystream_bytes(  /* based on ECRYPT_encrypt_bytes */
  ECRYPT_ctx* ctx,
  u8* keystream,
  u32 length)              /* Length of keystream in bytes. */
{
   u32     round;
   u16     nx;       /* number of state bytes */
   u16     nk;       /* number of key bytes */
   u16     p1;       /* pointer to actual state byte */
   u16     p2;       /* pointer to actual key byte */
   u16     src;      /* sub-round counter */
   u8      accu;

   u16     p3, p4;   /* scratch */
   u8      tmp;      /* scratch */
   u32     n, pc;    /* little helpers */
   u16     j, m;     /* little helpers */
   u32     maxloops; /* loops needed to process msglen bytes */

   /* ----------------- start of algorithm ----------------- */
   accu  = ctx->parm[0] & 0x00FF;
   p1    = ctx->parm[1];
   p2	 = ctx->parm[2];
   src   = ctx->parm[3];
   round = ctx->parm[4];
   nk    = ctx->parm[5];
   nx    = ctx->parm[6];
   
   fprintf(op,"STREAM accu=%3d p1=%d p2=%d src=%d  round=%d \n", accu, p1, p2, src, round );
   printf("STREAM accu=%3d p1=%d p2=%d src=%d  round=%d \n", accu, p1, p2, src, round );

   maxloops = (u32)( length / OUTPUTBYTES  + 0.5 );
   pc = 0;

   for( n=0; n<maxloops; n++ )
   {
      for( m=1; m<=STREAM_ROUNDS; m++)
      {
         round++; 
#include "hermes_core.h"
      }
      
      /* for( j=0; j<nx; j++ ){ ciphertext[pc+j] = ctx->state[j]; } */
      for( j=0; j<OUTPUTBYTES; j++ ){ keystream[pc+j] = ctx->state[j]; }
      pc = pc + OUTPUTBYTES;
   }/* for n */

} /* ECRYPT_keystream_bytes ------------------------------------------ */





/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/* ---------------- wrappers for ECRYPT  APIs  ------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */


/**
 Encryption of plaintext of length pt_length
 Uses:
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);
   ECRYPT_ivsetup( &ctx, x );
   ECRYPT_encrypt_bytes( &ctx, plaintext, ciphertext, msg_length );
 -
 @input  x  
 @input  k  
 @input  algo  
 @input  plaintext
 @input  pt_length
 -
 @global  ciphertext
*/
void Hermes_encrypt( u8 x[], u8 k[], int algo, const u8* plaintext, u8* ciphertext, u32 pt_length )
{
   u32 key_length;
   u32 iv_length;
   u32 msg_length;
   ECRYPT_ctx  ctx; /* create  data structure */


   msg_length = pt_length;
   key_length = 10;
   iv_length = S_LENGTH1;
   if( algo == 2 ){ key_length = 16; iv_length = S_LENGTH2;}
   
   printf("\n");
   printf("Test of ECRYPT_* procedures \n");
   printf(" key length = %5d \n", key_length );
   printf(" iv  length = %5d \n", iv_length );
   printf(" pt  length = %5d \n", pt_length );
   
   
   /* Call the ECRYPT API subroutine */
      
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);


   
   /* Call the ECRYPT API subroutine */
      
   ECRYPT_ivsetup( &ctx, x );


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);


   /* Call the ECRYPT API subroutine */
      
   ECRYPT_encrypt_bytes( &ctx, plaintext, ciphertext, msg_length );


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);



   /* print_ciphertext( msg_length ); */
   ciphertext_histogram( msg_length );

   
   ECRYPT_dump_state_key( &ctx, iv_length,  key_length );
   ECRYPT_dump_key_hex( &ctx, key_length );
   
   printf("\n");

}/* Hermes_encrypt ----------------------------------------------------------- */




/**
 Decryption of ciphertext of length pt_length
 Uses:
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);
   ECRYPT_ivsetup( &ctx, x );
   ECRYPT_decrypt_bytes( &ctx, ciphertext, plaintext, msg_length );
 -
 @input  x  
 @input  k  
 @input  algo  
 @input  ciphertext
 @input  pt_length
 -
 @global  plaintext
*/
void Hermes_decrypt( u8 x[], u8 k[], int algo, const u8* ciphertext, u8* plaintext, u32 pt_length )
{
   u32 key_length;
   u32 iv_length;
   u32 msg_length;
   ECRYPT_ctx  ctx; /* create  data structure */


   msg_length = pt_length;
   key_length = 10;
   iv_length = S_LENGTH1;
   if( algo == 2 ){ key_length = 16; iv_length = S_LENGTH2;}
   
   printf("\n");
   printf("Test of ECRYPT_* procedures \n");
   printf(" key length = %5d \n", key_length );
   printf(" iv  length = %5d \n", iv_length );
   printf(" pt  length = %5d \n", pt_length );
   
   
   /* Call the ECRYPT API subroutine */
      
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);


   
   /* Call the ECRYPT API subroutine */
      
   ECRYPT_ivsetup( &ctx, x );


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);


      
   /* Call the ECRYPT API subroutine */
      
   ECRYPT_decrypt_bytes( &ctx, ciphertext, plaintext, msg_length );


   printf( "==>   accu=%d p1=%d p2=%d  round=%d  kb=%d ivb=%d   done.\n",
   ctx.parm[0],ctx.parm[1],ctx.parm[2],ctx.parm[3],ctx.parm[4],ctx.parm[5]);


   print_plaintext( msg_length );

   ECRYPT_dump_state_key( &ctx, iv_length,  key_length );

   printf("\n");

}/* Hermes_decrypt ----------------------------------------------------------- */



/**
 Perform loops of encryption and decryption and
 check if the original plaintest is recovered again.
 -
 @input  x  
 @input  k  
 @input  algo  
 @input  pt_length
 -
 @global  plaintext
 @global  ciphertext
*/
void Hermes_EncryptDecrypt(  u8 x[], u8 k[], int algo, u32 pt_length ) 
{
 int j, n, loops=15;
 u8  pt[PTSIZE];
 int FAILS = 0;
 u32  my_ptlength;
 
 /* u8 key[K_LENGTH];
 for(j=0; j<K_LENGTH; j++){ key[j] = k[j];} */
 
 
 my_ptlength = 2000;
 /* my_ptlength = pt_length; */
 
 
 loops=15;
 
 
 for( n=0; n<=loops; n++ )
 {
   /* fill global plaintext and reference pt */
   for( j=0; j<pt_length; j++ ){ my_plaintext[j] = n; pt[j] = n; }
   
   Hermes_encrypt( x, k, algo, my_plaintext, my_ciphertext, my_ptlength ); /* fill ciphertext */


   print_ciphertext_hex( my_ptlength );
   fprintf( op, "\n");

   for( j=0; j<my_ptlength; j++ ){ my_plaintext[j] = 99; }/* destroy plaintext */


   
   printf("\n\n start decryption....\n");
   fprintf(op, "\n\n start decryption....\n");

   Hermes_decrypt( x, k, algo, my_ciphertext, my_plaintext, my_ptlength ); /* derive new plaintext */

   
   for( j=0; j<my_ptlength; j++ ) /* check */
   { 
      if( my_plaintext[j] != pt[j] ){ FAILS++; }
   }
 }/* for n */

 printf("E/D loop test:  FAILS = %d  \n", FAILS );
 printf("============================\n" );
 printf("\n" );

}/* Hermes_EncryptDecrypt ----------------------------------------------------------- */






/**
 Encryption of plaintext of length pt_length to produce test vector
 Uses:
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);
   ECRYPT_ivsetup( &ctx, x );
   ECRYPT_encrypt_bytes( &ctx, plaintext, ciphertext, msg_length );
 -
 @input  x  
 @input  k  
 @input  algo  
 @input  plaintext
 @input  pt_length
 -
 @global  ciphertext
*/
void Hermes_testvector( u8 x[], u8 k[], int algo, u8 plaintext[], u32 pt_length )
{
   u32 key_length;
   u32 iv_length;
   u32 msg_length;
   ECRYPT_ctx  ctx; /* create  data structure */


   msg_length = pt_length;
   key_length = 10;
   iv_length = 20;
   if( algo == 2 ){ key_length = 16; iv_length = 32;}
   
   printf("\n");
   printf("Test of ECRYPT_* procedures \n");
   printf(" key length = %5d \n", key_length );
   printf(" iv  length = %5d \n", iv_length );
   printf(" pt  length = %5d \n", pt_length );
   
   
   print_plaintext_hex( 40 );
   fprintf( op, "\n");

   /* Call the ECRYPT API subroutine */
      
   ECRYPT_keysetup( &ctx, k, key_length*8, iv_length*8);

   ECRYPT_dump_key_hex( &ctx, key_length );

   
   /* Call the ECRYPT API subroutine */
      
   fprintf( op, "Initialization ....... \n");
   ECRYPT_ivsetup( &ctx, x );
   dump_IV( x, iv_length );
   
   fprintf( op, "Initialization done. \n");
   ECRYPT_dump_state_hex( &ctx, iv_length );
   ECRYPT_dump_key_hex( &ctx, key_length );



   /* Call the ECRYPT API subroutine */
      
   ECRYPT_encrypt_bytes( &ctx, my_plaintext, my_ciphertext, msg_length );



   print_ciphertext_hex( msg_length );
   fprintf( op, "\n");
   
   fprintf( op, "final state and key: \n");
   ECRYPT_dump_state_hex( &ctx, iv_length );
   ECRYPT_dump_key_hex( &ctx, key_length );
   
   print_plaintext_hex( 40 );
   fprintf( op, "\n");
   fprintf( op, "\n");
   
   printf("\n");

}/* Hermes_testvector ----------------------------------------------------------- */









/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------- little helpers -------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */




/* FILL RandReg[] WITH A FRESH SET OF BYTES
   USING LINEAR FEEDBACK SHIFT REGISTER USING
   A SPECIFIED NUMBER OF BIT SHIFTS.
   IF YOU ONLY WANT 16 BITS OF RANDOM NUMBER IT'S NOT
   WORTH SHIFTING MORE THAN ABOUT 16 BITS
*/
void MakeRnd( int bits ){
  int j, carryin, carryout;


  while ( bits ){
	carryin = 0;
	
	for ( j=0; j<8; j++){
	  carryout = ( RandReg[j] & 0x80 );
	  RandReg[j] <<= 1;
	  if ( carryin ) RandReg[j]++;
	  carryin = carryout;
	}/*for*/
	
	/*Primitive polynomial 1 C526 F0E9 EFA3 4021   deg=64*/
	
	if ( carryout ){
	  RandReg[0]^=0x21;
	  RandReg[1]^=0x40;
	  RandReg[2]^=0xA3;
	  RandReg[3]^=0xEF;
	  RandReg[4]^=0xE9;
	  RandReg[5]^=0xF0;
	  RandReg[6]^=0x26;
	  RandReg[7]^=0xC5;
	}
	bits--;
  }/*while*/

}/* MakeRnd --------------------------------------------- */



unsigned char RandByte(){
	MakeRnd(12);
	return RandReg[0];
}/* RandByte ---------------- */





void cputs( char *s )
{
   printf( "%s", s );
}/* cputs ---------------- */



/*  get a character from keyboard, needs CR !!!  */
char getch()
{
   char test;
   
   test = getchar();
   getchar(); /* for CR */
   return test;
}/* getch ---------------------------------------------  */






void BinPrnt( unsigned char x){
  int j;
	for (j=0;j<8;j++){
		if (x & 0x80) fprintf(op,"1"); else fprintf(op,"o");
		x <<= 1;
	}
	fprintf(op," ");
}


/* write REGISTER CONTENTS to file op */
void WriteReg( char *msg, unsigned char *x, int n ){
  int j;
  
  fprintf(op, msg );
  for( j=n-1; j>=0; j-- )
   {
      fprintf(op, "%02x", x[j] );
   }
  fprintf(op, "  ");
  for( j=n-1; j>=0; j-- ) BinPrnt( x[j] );
  fprintf(op, " \n");
}







/* PRINT CHAR X IN BINARY */
void BinPrint( unsigned char x )
{
    int j;
	for (j=0;j<8;j++){
	if (x & 0x80) cputs("1"); else cputs("o");
	x <<= 1;
  }
}


/* DISPLAY REGISTER CONTENTS ON CONSOLE */
void ShowReg( char *msg, unsigned char *x, int n ){
  int j;
  
  cputs(msg);
  for (j=n-1;j>=0;j--){
	printf("%02x",x[j]);
	}
  cputs("  ");
  for (j=n-1;j>=0;j--) BinPrint(x[j]);

}




/* INTEGER CORRESPONDING TO HEX SYMBOL */
int HexVal(char ch){
  int k;
  ch=toupper(ch);
  if (ch>='A'){
	k=ch-'A'+10;
  }
  else{
	k=ch-'0';
  }
  return k;
} /* HexVal --------------------------------- */




/* SET REGISTER x (n BYTES) ACCORDING TO
STRING s REPRESENTING HEX VALUE */
void SetReg( unsigned char *x, int n, char *s )
{
	int j,k,i;

	for (j=0;j<n;j++) x[j]=0;

	k=0;i=n-1;
	while ((s[k]) && (i>=0) && (i<n)){
		i=n-1-k/2;
		if (k & 1){
			x[i] |= HexVal(s[k]);
		} else {
			j=HexVal(s[k]);
			j <<= 4;
			x[i] = j;
		}
	  k++;
	}
} /* SetReg ------------------------------------------- */





/* GET VALUE AS TYPED ON CONSOLE INTO REGISTER 	x[] */
void GetReg( char *msg, unsigned char *x, int n )
{
	int j;
	char s[100];

	cputs(msg);
	for (j=0;j<2*n;j++) cputs("-");
	
	gets(s);
	for (j=0;j<n;j++) x[j]=0;

	SetReg(x,n,s);
}/*  GetReg ----------------------------------- */






void SetLength( int algo )
{
  if( algo == 1 ) /* Hermes8-80     key 10 bytes,  state 20 bytes*/
  {
	KEYBYTES =  10;
	KEYBITS  =  80;

	STATEBYTES = 23;
	STATEBITS = 184;
	
	MY_IV_LENGTH = 23;

	OUTPUTBYTES =  8; /* 15 bytes hidden */
	OUTPUTBITS =  64;
  }
  else
  if( algo == 2 ) /* Hermes8-128     key 16 bytes,  state 32 bytes*/
  {
	KEYBYTES =  16;
	KEYBITS  = 128;

	STATEBYTES = 37;
	STATEBITS = 296;

	MY_IV_LENGTH = 37;

	OUTPUTBYTES = 16; /* 21 bytes hidden */
	OUTPUTBITS = 128;
  }

  else
  {
     printf( ALGO_NOT_VALID ); 
     exit(1);
  }

  printf("\n");
  printf("Algorithm      = %d    %s \n", algo, choice );
  printf("KEYBYTES       = %d \n", KEYBYTES );
  printf("STATEBYTES = %d \n",STATEBYTES  );
  
}/* SetLength ------------------------------------------------------------ */



void SetKey()
{
   int j;
   u8  t;

   /* initialise KEY  k[n]..k[0] =  0123456789..... */
   t=0x01;
   for( j=KEYBYTES-1; j>=0; j--) {
	k[j]=t;
	t+=0x22;
   }/* for */


}/* SetKey ------------------------------------------------------------ */




void  writeAlgorithmName()
{
	fprintf(op,"%s \n", choice );
	fprintf(op,"Algorithm = %2d  \n\n", algo );
}


void  writeAlgorithmInitRounds()
{
	fprintf(op,"Number of INIT_ROUNDS = %2d  \n\n", MY_INIT_ROUNDS );
}


void  writeAlgorithmIvLength()
{
	fprintf(op,"Number of IV bytes    = %2d  \n\n", MY_IV_LENGTH );
}








int GetAlgorithm( char *msg, char *msg2 )
{
  int alg, N=1;
  char s[2];
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  alg = (int) s[0] ;
  alg = alg - 48 ;
  printf("alg = %d \n", alg );
  
  if( alg == 1 ) N = alg;  
   else if( alg == 2 ) N = alg;  
     else printf("ERROR !!! Algorithm not defined !!! \n");

  return N;
}/*  GetAlgorithm ----------------------------------- */




int GetIvLength( char *msg, char *msg2 )
{
  int r, r1, N=-1;
  char s[2];
  
  s[0]='-';
  s[1]='-';
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  printf(" s = %s \n", s );

  r = (int) s[0] ;
  r = r - 48 ;
  
  r1 = (int) s[1] ;
  r1 = r1 - 48 ;
  if( r1 >= 0 && r1 <= 9 )
  {
     r = r * 10;
     r = r + r1;
  }
  
  printf("rounds = %d \n", r );
  
  if( r >= 4 && r <= 37 ) N = r;  
     else printf("ERROR !!! Need 4..37 !!! \n");

  return N;
}/*  GetIvLength----------------------------------- */



int GetInitRounds( char *msg, char *msg2 )
{
  int r, r1, N=-1;
  char s[2];
  
  s[0]='-';
  s[1]='-';
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  printf(" s = %s \n", s );

  r = (int) s[0] ;
  r = r - 48 ;
  
  r1 = (int) s[1] ;
  r1 = r1 - 48 ;
  if( r1 >= 0 && r1 <= 9 )
  {
     r = r * 10;
     r = r + r1;
  }
  
  printf("rounds = %d \n", r );
  
  if( r > 0 && r <= 32 ) N = r;  
     else printf("ERROR !!! Need 1..32 !!! \n");

  return N;
}/*  GetInitRounds----------------------------------- */



int GetScRounds( char *msg, char *msg2 )
{
  int j, r, r1, N=-1;
  char s[4];
  
  s[0]='-';
  s[1]='-';
  s[2]='-';
  s[3]='-';
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  printf(" s = %s \n", s );

  r = 0;
  for( j=0; j<4; j++ )
  {
    r1 = (int) s[j] ;
    r1 = r1 - 48 ;
    if( r1 >= 0 && r1 <= 9 )
    {
       r = r * 10;
       r = r + r1;
    }
  }/*for*/
  
  printf("rounds = %d \n", r );
  
  if( r > 0 && r <= 1000 ) N = r;  
     else printf("ERROR !!! Need 1..1000 !!! \n");

  return N;
}/*  GetScRounds----------------------------------- */






int GetPtLength( char *msg, char *msg2 )
{
  int j, r, r1, N=-1;
  char s[5];
  
  s[0]='-';
  s[1]='-';
  s[2]='-';
  s[3]='-';
  s[4]='-';
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  printf(" s = %s \n", s );

  r = 0;
  for( j=0; j<5; j++ )
  {
    r1 = (int) s[j] ;
    r1 = r1 - 48 ;
    if( r1 >= 0 && r1 <= 9 )
    {
       r = r * 10;
       r = r + r1;
    }
  }/*for*/
  
  printf("rounds = %d \n", r );
  
  if( r >= 256  &&  r <= 32000 ) N = r;  
     else printf("ERROR !!! Need 256..32000 !!! \n");

  return N;
}/*  GetPtLength----------------------------------- */







int GetPtPattern( char *msg, char *msg2 )
{
  int j, r, r1, N=-1;
  char s[3];
  
  s[0]='-';
  s[1]='-';
  s[2]='-';
  
  cputs( msg );
  cputs( msg2 );
  
  gets( s );
  printf(" s = %s \n", s );

  r = 0;
  for( j=0; j<3; j++ )
  {
    r1 = (int) s[j] ;
    r1 = r1 - 48 ;
    if( r1 >= 0 && r1 <= 9 )
    {
       r = r * 10;
       r = r + r1;
    }
  }/*for*/
  
  printf("pattern value (dec) = %d \n", r );
  
  if( r >= 0 && r <= 255) N = r;  
     else printf("ERROR !!! Need 0..255 !!! \n");

  return N;
}/*  GetPtPattern----------------------------------- */





















/* makes sequence of 1 million bits by concatenating
   responses to successive states each an increment
   of the previous one.
 */
void makesequence()
{
	int j;
	long count=0, bytes=0, maxbytes=1000000L;
	FILE *a;
	
	
        maxbytes =  4 * 50000025;
        maxbytes =     268500000;

	a = fopen("STREAM.DAT","wb");
	
	printf("Generating %ld bytes .... \n", maxbytes );

	stream_Hermes8( x, y, algo, YES ); /* initialization of stream generator */

	bytes = 0;
	while (bytes<maxbytes)
	{
		if( algo >=1 && algo <= 2 )  stream_Hermes8( x, y, algo, NO ); else
		 printf( ALGO_NOT_VALID ); 

		/* write to file */
		for (j=0;j<OUTPUTBYTES;j++) putc( y[j], a );

		count++;
		bytes += OUTPUTBYTES;
		
		if( bytes % 1000000 == 0 ) printf(" bytes = %ld \n", bytes );
	}

	fclose(a);

}/* makesequence ----------------------------------------------------------- */






void makevisiblesequence( int runs )
{
	int  j;
	long r;

	fprintf(op,"IV ,  initial state\n");
	fprintf(op,"     ");
	for( j=0; j<STATEBYTES;j++ ) { BinPrnt( x[j] );} /* print IV */
	fprintf(op,"\n\n");


 	stream_Hermes8( x, y, algo, YES ); /* initialize the stream cipher */

	fprintf(op,"\n");

	for ( r=0; r<runs; r++ )
	{
		if( algo >=1 && algo <= 2  ) stream_Hermes8( x, y, algo, NO ); else
		printf( ALGO_NOT_VALID ); 

		/* write to file */
		fprintf(op,"%4ld ",r);
		for (j=0; j<OUTPUTBYTES;j++) { BinPrnt( y[j] );} /* print result */
		fprintf(op,"\n");
	}/*for*/

}/* makevisiblesequence --------------------------------------------- */





/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* ==================   TEST SUITE   FIPS_140_2   =========================== */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* T_FIPS */

long  fail_FIPS_140_2( char *bit_string )      /* UK20020205 */

/* Statistical tests for randomness 
   returns 4000000  if bit_string fails monobit test, 
   30000 if it fails poker test, 
   200 if it fails runs test,
   1 if it fails the long run test,  
   0 otherwise;
   all fails -> code =4030201
*/

{
  long result = 0;
  long BIT_STRING_LENGTH = 20000L; /* fixed for FIPS 140-2 !!! */
  
  float X1, X3, sum = 0.0, mu;


  long i, index, j, k, n1 = 0;

  /* for the runs test */
  long B[6]= {0}, G[6] = {0}, n[16] = {0};
  long max_run = 0;
  long interval_lo[6] = { 2315, 1114, 527, 240, 103, 103 };
  long interval_hi[6] = { 2685, 1386, 723, 384, 209, 209 };



  printf("===>  1 \n"   );


  /* ----- monobit test ----- */

  printf("monobit test .... \n");

  for( i = 0; i < BIT_STRING_LENGTH; i++ )

    if( bit_string[i] == 1 ) n1++;

  mu = (float)( BIT_STRING_LENGTH / 2 );
  X1 = 2.0 * ( n1 - mu ) * ( n1 - mu ) / mu  ;



printf("===>  2 \n"   );

  /*  ----- poker test  m=4  ----- */

  printf("poker test m=4 .... \n");

  i = 0;

  k = BIT_STRING_LENGTH / 4;

  for (j = 0; j < k; j++)
  {
    index = 8 * bit_string[i + 3] + 4 * bit_string[i + 2]
          + 2 * bit_string[i + 1] + bit_string[i];

    n[index]++;
    i += 4;
  }

  for( i = 0; i < 16; i++ ) sum += n[i] * n[i];

  X3 = 16.0 * sum / k   - k ;


printf("===>  3 \n"   );

  /* ----- runs test ----- */

  printf("runs test  .... \n");

  i = 0;

  while (i < BIT_STRING_LENGTH) { /* search for BLOCKS */

    j = 0;

    while(i < BIT_STRING_LENGTH && bit_string[i] == 1) i++, j++;

    if(j <= 6)  B[j - 1]++;  else B[5]++;

    if(j > max_run)  max_run = j;

    while(i < BIT_STRING_LENGTH && bit_string[i] == 0) i++;

 }
 
printf("===>  4 \n"   );

  i = 0;

  while (i < BIT_STRING_LENGTH) { /* search for GAPS */

    j = 0;

    while(i < BIT_STRING_LENGTH && bit_string[i] == 0) i++, j++;

    if(j <= 6)  G[j - 1]++;  else G[5]++;

    if(j > max_run)  max_run = j;

    while(i < BIT_STRING_LENGTH && bit_string[i] == 1) i++;

  }

printf("===>  5 \n"   );



  /* print out results of the tests */

  printf("monobit statistic: n1 = %ld   X1 = %f \n", n1, X1);
  fprintf(op,"monobit statistic: n1 = %ld   X1 = %f \n", n1, X1);

  printf("poker test statistic: X3 = %f\n", X3);
  fprintf(op,"poker test statistic: X3 = %f\n", X3);

  printf("runs test:\n");
  printf("# blocks\tgaps\n");

  for (i = 0; i < 6; i++)

    printf("%ld %4ld\t\t%4ld\n", i + 1, B[i], G[i]);

  printf("long runs statistic:  maxrun = %ld\n", max_run);
  fprintf(op,"long runs statistic:  maxrun = %ld\n", max_run);


printf("===>  6 \n"   );

  /* compute return value based on statistics */

  for (i = 0; i < 6; i++) {

    if(B[i] < interval_lo[i] || B[i] > interval_hi[i]) result = result + 20;

    if(G[i] < interval_lo[i] || G[i] > interval_hi[i]) result = result + 20;

  }
  
  if( result > 0 )
  {
   printf("runs test      FAILED \n");
   fprintf(op, "runs test      FAILED \n");
   result = 200;
   totalfail_runs_test++;
  }
  
  
  if ( max_run >= 26 )
  {
   printf("long runs test FAILED \n");
   fprintf(op, "long runs test FAILED \n");
   result = result + 1;
   totalfail_long_runs++;
  }



  if (X3 <= 2.16 || X3 >= 46.17 )
  {
   printf("poker test     FAILED \n");
   fprintf(op, "poker test     FAILED \n");
   result = result + 30000;
   totalfail_poker++;
  }


  if (n1 <= 9725 || n1 >= 10275 )
  {
   printf("monobit test   FAILED \n");
   fprintf(op, "monobit test   FAILED \n");
   result = result + 4000000;
   total_fail_monobit++;
  }

  return  result;

} /* fail_FIPS_140_2 ------------------------------------------------------- */




/* C_FIPS */
void  doFIPS1402_crunch() /* UK20020205 */
{

  /*char bit_string[20032];  UK 9.Jan.2004   +32 because of 64 bit states */
  char bit_string[20224]; /* UK 20.Feb.2005   because of 256 bit states */
  
  long  result;

  unsigned char z;
  int bit;
  
  int j, i, jj, t, fail=0, ntest=100;
  
  long count, bits=0, maxbits=20000;
  
  int j_start, bits_inc;


 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "====> crunch: FIPS 140-2  Random Number Generator  Quality Test <====\n\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "Key is unchanged for every FIPS test; IV is incremented from zero start value.\n" );
 fprintf(op, "The initialization is run as often as 20000 bits are collected.\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
	
 writeAlgorithmName();
 writeAlgorithmInitRounds();
 writeAlgorithmIvLength();


 j_start  = OUTPUTBYTES - 1;
 bits_inc = OUTPUTBITS;
 
 for (j=0;j<X_LENGTH;j++) x[j]=0; /* default x = 0x0000000000 */



 for( t = 1; t <= ntest; t++ )  /* perform 100 tests ... */
 {
        count = 0;
	
	printf("Generating %ld bits .... \n", maxbits );

	bits = 0;
	while ( bits < maxbits ){

		if( algo >=1 && algo <= 2  ) crunch_Hermes8( x, y, k, algo ); else
		printf( ALGO_NOT_VALID ); 
		
		/* printf("crunch %02x %02x %02x %02x %02x \n",
		             y[4], y[3], y[2], y[1], y[0] ); */


		/* write to long bit_string */
		for ( j=j_start; j>=0; j-- )
		{
		  z = y[j];
		  
		  for ( jj=0; jj<8; jj++ )
		  {
		    if( z & 0x80 ) { bit = 1; }
		        else       { bit = 0; }
		    /* printf(" %d  %d  ", j, jj );
		    printf(" count = %ld  bit = %d \n", count, bit ); */
                    bit_string[ count ] =  bit ;
		    count++;
		    z <<= 1;
		  }/*for*/
		}/*for*/

		/*   INC x[]  for next crunch()  */
		j=0;
		do{
			x[j]++;
			i=x[j];
			j++;
		} while (!i);
		
		bits += bits_inc;
		
		if( bits % 4000 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
		if( bits % 6400 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
	}/*while*/

	printf("Test: %d \n", t );
	printf("Generated %ld bits .... \n", maxbits );
	fprintf(op,"Test: %d \n", t );
	fprintf(op,"Generated %ld bits .... \n", maxbits );


    /* check the bit string now ... */

    result = fail_FIPS_140_2( bit_string );
  
    if( result )
     { printf("----- FAILED FIPS_140_2  result = %8ld\n\n", result );
       fail++;
       fprintf(op,"----- FAILED FIPS_140_2  result = %8ld\n\n", result );
     }
    else printf("+++++ PASSED FIPS_140_2  result = %8ld\n\n", result );

 }/* for ntest */


  printf("\n   ====> total number of FAIL = %d  !!! (%d) \n", fail, ntest );
  fprintf(op,"\n   ====> FIPS_140_2: total number of FAIL = %d  !!! (%d) \n\n", fail, ntest );
  
  
  printf("\n ***  FIPS 140-2 done. ***\n" );
  
}/*  doFIPS1402_crunch ------------------------------------------------------- */






/*
 Run t=ntest FIPS140-2 tests.
 For given IV=x and Key=k we perform init_Hermes8.
 For every t we keep these IV and Key and run the stream_Hermes8
 again and again in order to produce 20000 random bits
*/
/* S_FIPS */
void  doFIPS1402_stream( int  n_tests ) 
{

  /* char bit_string[20032]; */
  char bit_string[20224]; /* UK 20.Feb.2005   because of 256 bit states */
  
  long  result;

  unsigned char z;
  int bit;
  int j, jj, t, fail=0, ntest=100;
  long count, bits=0, maxbits=20000;
  int n;
  u32  pt_length;


 ntest = n_tests; /* variable number of FIPS tests ... */

 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "====> stream: FIPS 140-2  Random Number Generator  Quality Test <====\n\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "IV is unchanged for every FIPS test.\n" );
 fprintf(op, "The stream subroutine is run as often as 20000 bits are collected.\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
	
 writeAlgorithmName();
 writeAlgorithmInitRounds();
 writeAlgorithmIvLength();


/* for (j=0;j<X_LENGTH;j++) x[j]=0;  default x = 0x0000000000 */


 stream_Hermes8( x, y, algo, YES ); /* initialize the stream cipher */
 
 printf( "Initialization of stream cipher done. \n");
 
 

 for( t = 1; t <= ntest; t++ )  /* perform e.g. 100 tests ... */
 {
        count = 0;
        pt_length = 0;
	
	printf("Generating %ld bits .... \n", maxbits );

	bits = 0;
	while ( bits < maxbits ){

		if( algo >=1 && algo <= 2  ) stream_Hermes8( x, y, algo, NO ); else
		printf( ALGO_NOT_VALID ); 
		
                for( n=0; n<OUTPUTBYTES; n++)
		{
		   my_ciphertext[pt_length]  = y[n];
		   pt_length++;
		}

		/* write to long bit_string */
		for ( j=0; j<OUTPUTBYTES; j++ )
		{
		  z = y[j];
		  
		  for ( jj=0; jj<8; jj++ )
		  {
		    if( z & 0x80 ) { bit = 1; }
		        else       { bit = 0; }
		    /* printf(" %d  %d  ", j, jj );
		    printf(" count = %ld  bit = %d \n", count, bit ); */
                    bit_string[ count ] =  bit ;
		    count++;
		    z <<= 1;
		  }/*for*/
		}/*for*/

		
		bits += OUTPUTBITS;
		
		if( bits % 4000 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
		if( bits % 6400 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
	}/*while*/

     printf("Test: %d \n", t );
     printf("Generated %ld bits .... \n", maxbits );
     fprintf(op,"Test: %d \n", t );
     fprintf(op,"Generated %ld bits .... \n", maxbits );
	
     pt_length = 2500;
     	
     printf(" pt_length = %d \n", pt_length );
     for( n=0; n<128; n++ ){ printf( " %2x", my_ciphertext[n]); } /* dump ciphertext */
     printf("\n");
     printf(" pt_length = %d \n", pt_length );
     for( n=pt_length-128; n<pt_length; n++ ){ printf( " %2x", my_ciphertext[n]); } /* dump ciphertext */
     printf("\n");
    
     fprintf(op," pt_length = %d   first 128 bytes...\n", pt_length );
     for( n=0; n<128; n++ ){ fprintf(op, " %2x", my_ciphertext[n]); } /* dump ciphertext */
     fprintf(op,"\n");
     fprintf(op," pt_length = %d   last 128 bytes...\n", pt_length );
     for( n=pt_length-128; n<pt_length; n++ ){ fprintf(op, " %2x", my_ciphertext[n]); } /* dump ciphertext */
     fprintf(op,"\n");
    
    
    /* 
     fprintf(op,"\n");
     fprintf(op,"\n");
     for( n=0; n<2500; n++ )
     { 
          fprintf(op, " %2x", my_ciphertext[n]);
          if( n % 50 == 49 ){ fprintf(op,"\n"); }
     } 
    
     exit(1);
      */
     

    /* check the bit string now ... */

    result = fail_FIPS_140_2( bit_string );
  
    if( result )
     { printf("----- FAILED FIPS_140_2  result = %8ld\n\n", result );
       fail++;
       fprintf(op,"----- FAILED FIPS_140_2  result = %8ld\n\n", result );
     }
    else printf("+++++ PASSED FIPS_140_2  result = %8ld\n\n", result );

 }/* for ntest */


  printf("\n   ====> total number of FAIL = %d  !!! (%d) \n", fail, ntest );
  fprintf(op,"\n   ====> FIPS_140_2: total number of FAIL = %d  !!! (%d) \n\n", fail, ntest );
  
}/*  doFIPS1402_stream ------------------------------------------------------- */




/*
 Run N=longtest loops in order to run  t=ntest FIPS140-2 tests.
 For every N we define a new randome set of IV and Key values
 and perform init_Hermes8.
 For every t we keep these IV and Key and run the stream_Hermes8
 again and again in order to produce 20000 random bits
*/
/* LS_FIPS */
void  doFIPS1402_longstream() /* UK20050214 */
{

  /* char bit_string[20032]; */
  char bit_string[20224]; /* UK 20.Feb.2005   because of 256 bit states */
  
  long  result;

  unsigned char z;
  int bit;
  
  int j, jj;
  int t, ntest=100, fail;
  int total_fail=0, longtest=50, N;
  
  long count, bits=0, maxbits=20000;
  


 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "====> longstream: FIPS 140-2  Random Number Generator  Quality Test <====\n\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "IV is unchanged for every FIPS test; key is changeing automatically.\n" );
 fprintf(op, "The stream subroutine is run as often as 20000 bits are collected.\n" );
	
 writeAlgorithmName();
 writeAlgorithmInitRounds();
 writeAlgorithmIvLength();


 
 totalfail_runs_test=0;
 totalfail_long_runs=0;
 totalfail_poker=0;
 total_fail_monobit=0;


for( N = 1;  N <=longtest; N++ )
{

 /* apply random IV, random Key */
 
 for (j=0;j<X_LENGTH;j++){ x[j] = RandByte(); }
 for (j=0;j<K_LENGTH;j++){ k[j] = RandByte(); }

 printf("RNG: x0= %3d   k0= %3d ", x[0], k[0] );
  
 fail = 0;
 
 stream_Hermes8( x, y, algo, YES ); /* initialize the stream cipher */
 
 printf( "Initialization of stream cipher done. \n");



 for( t = 1; t <= ntest; t++ )  /* perform e.g. 100 tests ... */
 {
        count = 0;
	
	printf("Generating %ld bits .... \n", maxbits );

	bits = 0;
	while ( bits < maxbits ){

		if( algo >=1 && algo <= 2  ) stream_Hermes8( x, y, algo, NO ); else
		printf( ALGO_NOT_VALID ); 
		
		/*  printf("crunch %02x %02x %02x %02x %02x   ntest= %d\n",
		             y[4], y[3], y[2], y[1], y[0] ,  ntest ); */ 


		/* write to long bit_string */
		for ( j=0; j<OUTPUTBYTES; j++ )
		{
		  z = y[j];
		  
		  for ( jj=0; jj<8; jj++ )
		  {
		    if( z & 0x80 ) { bit = 1; }
		        else       { bit = 0; }
		    /* printf(" %d  %d  ", j, jj );
		    printf(" count = %ld  bit = %d \n", count, bit ); */
                    bit_string[ count ] =  bit ;
		    count++;
		    z <<= 1;
		  }/*for*/
		}/*for*/

		
		bits += OUTPUTBITS;
		
		if( bits % 4000 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
		if( bits % 6400 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
	}/*while*/

	printf("Generated %ld bits .... \n", maxbits );
	fprintf(op,"Test: %d \n", t );
	fprintf(op,"Generated %ld bits .... \n", maxbits );


    /* check the bit string now ... */

    result = fail_FIPS_140_2( bit_string );
  
    if( result )
     { printf("----- FAILED FIPS_140_2  result = %8ld\n\n", result );
       fail++;
       total_fail++;
       fprintf(op,"----- FAILED FIPS_140_2  result = %8ld\n\n", result );
     }
    else printf("+++++ PASSED FIPS_140_2  result = %8ld\n\n", result );

 }/* for ntest */

  printf(" N = %d \n", N );
  fprintf(op, " N = %d \n", N );
  printf("\n   ====> number of FAILs = %d  !!! of(%d) \n", fail, ntest );
  fprintf(op,"\n   ====> FIPS_140_2: number of FAILs = %d  !!! of(%d) \n\n", fail, ntest );


}/*for N */

 printf("\n");
 printf(" Number of FAILs : %d   of  total tests %d \n", total_fail, longtest*ntest ); 
 fprintf(op,"\n");
 fprintf(op," Number of FAILs : %d   of  total test %d \n", total_fail, longtest*ntest ); 



 printf(" Number of runs test FAILs : %d  \n", totalfail_runs_test );
 printf(" Number of long runs FAILs : %d  \n", totalfail_long_runs );
 printf(" Number of poker tst FAILs : %d  \n", totalfail_poker );
 printf(" Number of mono bit  FAILs : %d  \n", total_fail_monobit );
 fprintf(op," Number of runs test FAILs : %d  \n", totalfail_runs_test );
 fprintf(op," Number of long runs FAILs : %d  \n", totalfail_long_runs );
 fprintf(op," Number of poker tst FAILs : %d  \n", totalfail_poker );
 fprintf(op," Number of mono bit  FAILs : %d  \n", total_fail_monobit );


}/*  doFIPS1402_longstream ------------------------------------------------------- */








/*
 Run t=ntest FIPS140-2 tests.
 For given IV=x and Key=k we perform ECRYPT_encryption_bytes().
 The plaintext is set to zero !
 For every t we keep the ciphertext and take 2500 bytes to form
 the 20000 bit stream.
*/
/* A_FIPS */
void  doFIPS1402_ECRYPTstream( int n_tests ) 
{

  /* char bit_string[20032]; */
  char bit_string[20224]; /* UK 20.Feb.2005   because of 256 bit states */
  
  long  result;

  unsigned char z;
  int bit;
  
  int jj, t, fail=0, ntest=100;
  
  long count, bits=0, maxbits=20000;
  
  u32  pos, n;
  u32  pt_length;

 ntest = n_tests; /* variable number of FIPS test ... */

 pt_length = 2500 * ntest;


 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "====> ECRYPT stream: FIPS 140-2  Random Number Generator  Quality Test <====\n\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "IV and key are unchanged for every FIPS test.\n" );
 fprintf(op, "Number of tests: %d \n", ntest );
 fprintf(op, "The stream subroutine is run once for %d bytes.\n", pt_length );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
	
 writeAlgorithmName();
 writeAlgorithmInitRounds();
 writeAlgorithmIvLength();




 for( n=0; n<pt_length; n++ ){ my_plaintext[n] = 0; } /* reset plaintext */

 /*for( n=0; n<pt_length; n++ ){ printf( " %d", plaintext[n]); }  dump plaintext */

   
 Hermes_encrypt( x, k, algo, my_plaintext, my_ciphertext, pt_length ); /* fill  ciphertext */



 printf( "Initialization of  ciphertext  done. \n");

 printf(" pt_length = %d \n", pt_length );
 for( n=0; n<128; n++ ){ printf( " %2x", my_ciphertext[n]); } /* dump ciphertext */
 printf("\n");
 printf(" pt_length = %d \n", pt_length );
 for( n=pt_length-128; n<pt_length; n++ ){ printf( " %2x", my_ciphertext[n]); } /* dump ciphertext */
 printf("\n");

 fprintf(op," pt_length = %d   first 128 bytes...\n", pt_length );
 for( n=0; n<128; n++ ){ fprintf(op, " %2x", my_ciphertext[n]); } /* dump ciphertext */
 fprintf(op,"\n");
 fprintf(op," pt_length = %d   last 128 bytes...\n", pt_length );
 for( n=pt_length-128; n<pt_length; n++ ){ fprintf(op, " %2x", my_ciphertext[n]); } /* dump ciphertext */
 fprintf(op,"\n");

 /* 
 fprintf(op,"\n");
 fprintf(op,"\n");
 for( n=0; n<2500; n++ )
 { 
      fprintf(op, " %2x", my_ciphertext[n]);
      if( n % 50 == 49 ){ fprintf(op,"\n"); }
 } 
 exit(0); 
 */


 
 pos = 0; /* position in ciphertext */

 for( t = 1; t <= ntest; t++ )  /* perform e.g. 100 tests ... */
 {
        count = 0;
	
	printf("Taking %ld bits .... \n", maxbits );

	bits = 0;
	while ( bits < maxbits )
	{
     	    z = my_ciphertext[pos];

     	    for ( jj=0; jj<8; jj++ )
     	    {
     	      if( z & 0x80 ) { bit = 1; }
     		  else       { bit = 0; }
     	      /* printf(" %d  %d  ", j, jj );
     	      printf(" count = %ld  bit = %d \n", count, bit ); */
	      bit_string[ count ] =  bit ;
     	      count++;
     	      z <<= 1;
     	    }/*for*/
	    pos++;	     
	    bits += 8;
		
	    if( bits % 4000 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
	}/*while*/

	printf("Test: %d     position: %d\n", t, pos );
	printf("Generated %ld bits .... \n", maxbits );
	fprintf(op,"Test: %d \n", t );
	fprintf(op,"Generated %ld bits .... \n", maxbits );


    /* check the bit string now ... */

    result = fail_FIPS_140_2( bit_string );
  
    if( result )
     { printf("----- FAILED FIPS_140_2  result = %8ld\n\n", result );
       fail++;
       fprintf(op,"----- FAILED FIPS_140_2  result = %8ld\n\n", result );
     }
    else printf("+++++ PASSED FIPS_140_2  result = %8ld\n\n", result );

 }/* for ntest */


  printf("\n   ====> total number of FAIL = %d  !!! (%d) \n", fail, ntest );
  fprintf(op,"\n   ====> FIPS_140_2: total number of FAIL = %d  !!! (%d) \n\n", fail, ntest );
  
}/*  doFIPS1402_ECRYPTstream ------------------------------------------------------- */









/*
 Run t=ntest FIPS140-2 tests.
 For given IV=x and Key=k we perform ECRYPT_encryption_bytes().
 The plaintext is set to zero !
 For every t we keep the ciphertext and take 2500 bytes to form
 the 20000 bit stream.
*/
/* B_FIPS */
void  doFIPS1402_ECRYPTlongstream() /* UK20050410 */
{

  char bit_string[20224];
  
  long  result;

  unsigned char z;
  int bit;
  
  int j, jj, t, fail=0, ntest=100;
  
  long count, bits=0, maxbits=20000;
  
  u32  pos, n;
  u32  pt_length;

  int total_fail=0, longtest=50, N;



 pt_length = 2500 * ntest;


 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "====> ECRYPT longstream: FIPS 140-2  Random Number Generator  Quality Test <====\n\n" );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
 fprintf(op, "IV and key are random, but unchanged for every 100 FIPS tests.\n" );
 fprintf(op, "Number of tests: %d \n", ntest );
 fprintf(op, "The stream subroutine is run once for %d bytes.\n", pt_length );
 fprintf(op, "\n" );
 fprintf(op, "\n" );
	
 writeAlgorithmName();
 writeAlgorithmInitRounds();
 writeAlgorithmIvLength();


 totalfail_runs_test=0;
 totalfail_long_runs=0;
 totalfail_poker=0;
 total_fail_monobit=0;



for( N = 1;  N <=longtest; N++ )
{

 /* apply random IV, random Key */
 
 for (j=0;j<X_LENGTH;j++){ x[j] = RandByte(); }
 for (j=0;j<K_LENGTH;j++){ k[j] = RandByte(); }

 printf("RNG: x0= %3d   k0= %3d ", x[0], k[0] );
  
 fail = 0;
 


 for( n=0; n<pt_length; n++ ){ my_plaintext[n] = 0; } /* reset plaintext */

 /*for( n=0; n<pt_length; n++ ){ printf( " %d", plaintext[n]); }  dump plaintext */

   
 Hermes_encrypt( x, k, algo, my_plaintext, my_ciphertext, pt_length ); /* fill ciphertext */

 printf( "Initialization of  ciphertext  done. \n");

 /* printf(" pt_length = %d \n", pt_length );
 for( n=0; n<128; n++ ){ printf( " %d", ciphertext[n]); }  */  /* dump ciphertext */
 /* printf(" pt_length = %d \n", pt_length );
 for( n=pt_length-128; n<pt_length; n++ ){ printf( " %d", ciphertext[n]); } */  /* dump ciphertext */

/*  exit(0); */
 
 pos = 0; /* position in ciphertext */

 for( t = 1; t <= ntest; t++ )  /* perform e.g. 100 tests ... */
 {
        count = 0;
	
	printf("Taking %ld bits .... \n", maxbits );

	bits = 0;
	while ( bits < maxbits )
	{
     	    z = my_ciphertext[pos];

     	    for ( jj=0; jj<8; jj++ )
     	    {
     	      if( z & 0x80 ) { bit = 1; }
     		  else       { bit = 0; }
     	      /* printf(" %d  %d  ", j, jj );
     	      printf(" count = %ld  bit = %d \n", count, bit ); */
	      bit_string[ count ] =  bit ;
     	      count++;
     	      z <<= 1;
     	    }/*for*/
	    pos++;	     
	    bits += 8;
		
	    if( bits % 4000 == 0 ) printf(" bits = %ld   %ld \n", bits, count );
	}/*while*/

	printf("Test: %d     position: %d\n", t, pos );
	printf("Generated %ld bits .... \n", maxbits );
	fprintf(op,"Test: %d \n", t );
	fprintf(op,"Generated %ld bits .... \n", maxbits );


    /* check the bit string now ... */

    result = fail_FIPS_140_2( bit_string );
  
    if( result )
     { printf("----- FAILED FIPS_140_2  result = %8ld\n\n", result );
       fail++;
       total_fail++;
       fprintf(op,"----- FAILED FIPS_140_2  result = %8ld\n\n", result );
     }
    else printf("+++++ PASSED FIPS_140_2  result = %8ld\n\n", result );

 }/* for ntest */


  printf(" N = %d \n", N );
  fprintf(op, " N = %d \n", N );
  printf("\n   ====> number of FAIL = %d  !!! (%d) \n", fail, ntest );
  fprintf(op,"\n   ====> FIPS_140_2: number of FAIL = %d  !!! (%d) \n\n", fail, ntest );

}/*for N */


 printf("\n");
 printf(" Number of FAILs : %d   of  total tests %d \n", total_fail, longtest*ntest ); 
 fprintf(op,"\n");
 fprintf(op," Number of FAILs : %d   of  total test %d \n", total_fail, longtest*ntest ); 



 printf(" Number of runs test FAILs : %d  \n", totalfail_runs_test );
 printf(" Number of long runs FAILs : %d  \n", totalfail_long_runs );
 printf(" Number of poker tst FAILs : %d  \n", totalfail_poker );
 printf(" Number of mono bit  FAILs : %d  \n", total_fail_monobit );
 fprintf(op," Number of runs test FAILs : %d  \n", totalfail_runs_test );
 fprintf(op," Number of long runs FAILs : %d  \n", totalfail_long_runs );
 fprintf(op," Number of poker tst FAILs : %d  \n", totalfail_poker );
 fprintf(op," Number of mono bit  FAILs : %d  \n", total_fail_monobit );


}/*  doFIPS1402_ECRYPTslongtream ------------------------------------------------------- */







void showparams( char *msg ){
	printf("%s\n\n",msg);
	printf("runs/experiment    = %4d\n",EXPERIMENTSIZE);
	printf("experiments        = %4d\n",EXPERIMENTS);
	printf("significance level = %4d%%\n",LOPC);
}/* showparams -------------------------------------  */




/* writes to file */
void writeparams(char *msg){
	fprintf(op,"\n\n\n====>  %s  <====\n\n",msg);
	fprintf(op,"runs/experiment    = %4d\n",EXPERIMENTSIZE);
	fprintf(op,"experiments        = %4d\n",EXPERIMENTS);
	fprintf(op,"significance level = %4d%%\n\n",LOPC);
}



/* -------------------------------------------------------- */
/* ----------test sensitivity to challenge or key --------- */
/* -------------------------------------------------------- */
/* T_SENS */
/*
  Csens  = 0  =>  do  Challenge-Sensitivity Test
  Csens  = 1  =>  do     k[] Key-Sensitivity Test

  Toggle the bits of x one at a time
  and note which bits of y change.
------------------------------------------*/

void TestSensitivities( int Csens ){

#define MAX_I  296
#define MAX_J  256

	int h[MAX_I][MAX_J], highs[MAX_I][MAX_J], lows[MAX_I][MAX_J];
	long runs = 0;
	int wrd,i,j,bits;
	int blocks=0;
	int BlockSize = EXPERIMENTSIZE;
	int inblock=0;
	int maxblocks = EXPERIMENTS; 
	float chisq;
	unsigned char msk, yy[Y_LENGTH];
		
	int index;
	int histogram[26];
	
	long count = 0;
	long mincount, maxcount;
	long avgcount = 0;
	

	if (Csens==0){
		bits = STATEBITS;
		showparams("State-Sensitivity Test");
	}
	if (Csens==1){
		bits = KEYBITS;
		showparams("k[] Key-Sensitivity Test");
	}

        /* first index i   for stepping over key bits or state bits, vertical */
	/* second index j for stepping over output bits            , horizontal */

        /* reset all arrays */
	for (i=0;i<MAX_I;i++)			/*UK20040502*/
		for (j=0;j<MAX_J;j++)
			h[i][j]= highs[i][j]= lows[i][j]= 0;


	
	mincount = 9999999L;
	maxcount = -1;
	
	do{
		runs++;

                if( runs % EXPERIMENTSIZE == 0 )
		      printf(" runs = %ld \n", runs );
		      
		/* setup  random  state  */
		for( j=0; j<STATEBYTES; j++) x[j] = RandByte();

		/* setup  random  key */
		for( j=0; j<KEYBYTES; j++ )      k[j] = RandByte();


		/* find yy[] as a reference */
		if( algo >=1 && algo <= 2  ) crunch_Hermes8( x, yy, k, algo ); else
		printf( ALGO_NOT_VALID ); 




		/* toggle the bits of x (resp. k) one at a time
		   and note which bits of y change   */
		for( i=0; i<bits; i++){
			wrd=i/8;

			msk=1 << (i & 7);

			if (Csens==0){
				/* toggle bit j */
				x[wrd] ^= msk;

				/* crunch into y[] for comparison with yy[] */
				if( algo >=1 && algo <= 2  ) crunch_Hermes8( x, y, k, algo ); else
				printf( ALGO_NOT_VALID ); 

				/* restore x[] */
				x[wrd] ^= msk;
		              } 
			if (Csens==1){
				/* toggle bit j in k[] */
				k[wrd] ^= msk;

				/* crunch into y[] for comparison with yy[] */
				if( algo >=1 && algo <= 2  ) crunch_Hermes8( x, y, k, algo ); else
				printf( ALGO_NOT_VALID ); 

				/* restore k[] */
				k[wrd] ^= msk;
		              }


			wrd=0;
			msk=1;
			j=0;
			while( j<OUTPUTBITS ){
				if( (y[wrd] ^ yy[wrd]) & msk  ){ h[i][j]++; count++; }
				/* fprintf(op,"%d %d %d \n", i, j, h[i][j] ); */				
				msk <<= 1;
				if( !msk ){
					msk=1;
					wrd++;
				}
				j++;
			}/*while j */

		}/* for i */



		inblock++;

		if( inblock==BlockSize ){
			blocks++;
			inblock=0;
			
			/* fprintf(op,"count = %d \n", count ); */
			avgcount += count;
			if( count > maxcount ) maxcount = count;
			if( count < mincount ) mincount = count;
			count = 0;

			/* showprogress( blocks, maxblocks ); */

			for( i=0; i<bits; i++ )
				for( j=0; j<OUTPUTBITS; j++ ){
					chisq = ( 2*h[i][j] - BlockSize );
					chisq = chisq*chisq/BlockSize;
					
					/* fprintf(op,"%d %d %d \n", i, j, h[i][j] ); */

					if( chisq > CHISQ_HI ) highs[i][j]++;
					if( chisq < CHISQ_LO )  lows[i][j]++;
					h[i][j]=0;
			}/*for*/
		}/*if*/
	} while( blocks < maxblocks );


    /* print results */

    if (Csens==0) writeparams("State-Sensitivity Test");
    if (Csens==1) writeparams("k[] Key-Sensitivity Test");

    writeAlgorithmName();
    writeAlgorithmInitRounds();
    writeAlgorithmIvLength();



    fprintf(op,"mincount = %ld \n", mincount );
    fprintf(op,"maxcount = %ld \n", maxcount );
    fprintf(op,"avgcount = %ld \n", avgcount/EXPERIMENTS );
    fprintf(op,"expected = %d \n", OUTPUTBITS*bits*EXPERIMENTSIZE/2 );
    fprintf(op,"experiments = %d \n", EXPERIMENTS );
    fprintf(op,"\n\n" );


    fprintf(op,"percent highs\n\n   ");
    for (j=0;j<OUTPUTBITS;j++) fprintf(op,"%3d",j);
    for (i=0;i<bits;i++){
    	    fprintf(op,"\n%3d",i);
    	    if (blocks) for (j=0;j<OUTPUTBITS;j++) fprintf(op,"%3.0f",100.0*highs[i][j]/blocks);
    }
    fprintf(op,"\n\npercent lows\n\n   ");
    for (j=0;j<OUTPUTBITS;j++) fprintf(op,"%3d",j);
    for (i=0;i<bits;i++){
    	    fprintf(op,"\n%3d",i);
    	    if (blocks) for (j=0;j<OUTPUTBITS;j++) fprintf(op,"%3.0f",100.0*lows[i][j]/blocks);
    }



 /* make histogram on highs */
 
  fprintf(op,"\n\nHistogram for percent highs\n\n");

  for( index=0; index<26; index++ ){ histogram[index] = 0; }

  for( j=0; j<OUTPUTBITS; j++ )
   for( i=0; i<bits; i++ )
   {
     index = highs[i][j];
     if( index >25 ){ index = 25;  }
     histogram[index]++;
   }

  for( index=0; index<26; index++ )
  {
    fprintf(op, "%2d %4d ", index, histogram[index] );
    for( j=0; j<(int)(0.5+histogram[index]/10.0); j++ ){ fprintf(op, "*" ); }
    fprintf(op, "\n" );
  }
  if( histogram[25] > 0 )
       fprintf(op, "====>   HIGH-25 : %d\n", histogram[25] );



 /* make histogram on lows */
 
  fprintf(op,"\n\nHistogram for percent lows\n\n");

  for( index=0; index<26; index++ ){ histogram[index] = 0; }

  for( j=0; j<OUTPUTBITS; j++ )
   for( i=0; i<bits; i++ )
   {
     index = lows[i][j];
     if( index >25 ){ index = 25;  }
     histogram[index]++;
   }

  for( index=0; index<26; index++ )
  {
    fprintf(op, "%2d %4d ", index, histogram[index] );
    for( j=0; j<(int)(0.5+histogram[index]/10.0); j++ ){ fprintf(op, "*" ); }
    fprintf(op, "\n" );
  }
  if( histogram[0] > 0 )
       fprintf(op, "====>   LOW-0 : %d\n", histogram[0] );

}/* TestSensitivities --------------------------------------------- */






/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/* ---------------------   M A I N ------------------------------------- */
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */


/* ------------------------ MAIN  with crude menu -------------------------*/

int  main()
{
  unsigned char test, done=0;
  int j, escseq;
  u32  n;


  j = LOPC;  /* either 5%  or  10%  possible !!! */

  if (j>6){
  	  CHISQ_LO=CHISQ_90;
  	  CHISQ_HI=CHISQ_10;
  } else {
  	  CHISQ_LO=CHISQ_95;
  	  CHISQ_HI=CHISQ_05;
  }


  algo = 1;
  SetLength( algo );
  SetKey();



  /* initialize the pseudo random generator */
  for( j=0; j<8; j++ ) RandReg[j] = 0;
  RandReg[0]=1;



  /* initialize plaintext */
  for( n=0; n<PTSIZE; n++ ) my_plaintext[n] = 0;

  /* initialize ciphertext */
  for( n=0; n<PTSIZE; n++ ) my_ciphertext[n] = 99;



  op=fopen("RESULTS.TXT","wb");




  /* PRESENT SIMPLE MENU TO USER */

  while( !done )
  {
	 cputs(credits);
	 cputs("\n\n");

	 /* SHOW STATE OF KEY[] AND REG[] */
         printf( "        alg = %d   %s\n", algo, choice );
	 ShowReg("        k[] = ", k, KEYBYTES);cputs("\n");
	 ShowReg("        x[] = ", x, STATEBYTES);cputs("\n");
	 ShowReg("        y[] = ", y, OUTPUTBYTES);cputs("\n");
	 
	 printf( "        PT_LENGTH   = %4d \n", MY_PT_LENGTH );
	 printf( "        IV_LENGTH   = %4d \n", MY_IV_LENGTH );
	 printf( "        INIT_ROUNDS = %4d \n", MY_INIT_ROUNDS );
	 printf( "        SC_ROUNDS   = %4d \n", MY_SC_ROUNDS );

	 /* SHOW MENU OPTIONS */
	 cputs("=== choose ===\n");
	 cputs("   Z       choose algorithm \n");
	 cputs("   K|X     choose k[] | x[] \n");
	 cputs("   E|D     Perform ECRYPT Stream Cipher En|Decryption   \n"); 
	 cputs("   L       Perform ECRYPT Stream Cipher LoopCheck  \n"); 
	 cputs("   A       Perform ECRYPT FIPS 140-2 stream test with 100 * 20,000 bits \n");
	 cputs("   B       Perform ECRYPT FIPS 140-2 stream test with 50 * (100 * 20,000 bits) \n");
	 cputs("   1       Set MY_PT_LENGTH             3       Set MY_IV_LENGTH\n"); 
	 cputs("   6       Set MY_INIT_ROUNDS           7       Set MY_SC_ROUNDS\n");
	 cputs("   H       State-Sensitivities test     I       Key-Sensitivities test\n");
	 cputs("   T       Test Vectors with ECRYPT Stream Cipher Encryption   \n"); 
	 cputs("   4       Set Plaintext pattern\n"); 

	 if( algo == 1 ) cputs("   C       Crunch_Hermes8( x, y, k, 1 )\n");
	 if( algo == 2 ) cputs("   C       Crunch_Hermes8( x, y, k, 2 )\n");
	 cputs("   Q       Perform FIPS 140-2 crunch test with 100 * 20,000 bits \n"); 
	 cputs("   S       Perform FIPS 140-2 stream test with 100 * 20,000 bits \n");
	 cputs("   R       Perform FIPS 140-2 stream test with 50 * (100 * 20,000 bits) \n");
	 cputs("   M       Make binary STREAM.DAT for external testing (n=12e6)\n");
	 cputs("   N       Make visible stream\n");
         ShowReg(" RandReg = ", RandReg, 8 );printf("\n");
	 cputs("   5       Set RandomGenerator\n"); 
	 cputs("   8       Perform FIPS 140-2 stream test with 1 * 20,000 bits \n");
	 cputs("   9       Perform ECRYPT FIPS 140-2 stream test with 1 * 20,000 bits \n");
	 cputs("   Esc|.   Exit\n");
	 cputs("\n");
	 cputs("   Choice =[ ]");

	 /* GET USER'S CHOICE */
	 do {
		 escseq = 0;
		 test = getch();
		 if ( !test ) { escseq=1; getch();}
	 } while ( escseq );

         fprintf(op, "Command chosen: %c \n", test );
	 test = toupper(test);

	 /* printf("MAXINT = %d  \n", MAX_INT ); */

	 /* EXECUTE USER'S CHOICE */
	 switch (test){
		case 'Z': algo = GetAlgorithm( "Algorithm =  ? ", choice );
		          SetLength( algo );
			  SetKey();
			  break;
		case 'K': GetReg("k = ", k, KEYBYTES); break;
		case 'X': GetReg("x = ",x,STATEBYTES); break;
		
		case 'C': if( algo==1) { crunch_Hermes8( x, y, k, 1 );  } else
			  if( algo==2) { crunch_Hermes8( x, y, k, 2 );  } else
			  if( algo==99) { crunch_Hermes8( x, y, k, 99 );  };
			  break;
		case 'E': Hermes_encrypt( x, k, algo, my_plaintext, my_ciphertext, MY_PT_LENGTH );
		          break;
		case 'D': Hermes_decrypt( x, k, algo, my_ciphertext, my_plaintext, MY_PT_LENGTH );
			  break;
		case 'L': Hermes_EncryptDecrypt( x, k, algo, MY_PT_LENGTH );
			  break;
		case 'A': doFIPS1402_ECRYPTstream( 100 );
		          printf(" doFIPS1402_ECRYPTstream  done. \n");
		          break; /* UK20050408 */
		case 'B': doFIPS1402_ECRYPTlongstream();
		          printf(" doFIPS1402_ECRYPTlongstream  done. \n");
		          break; /* UK20050410 */
		case 'H': TestSensitivities(0); break;
		case 'I': TestSensitivities(1); break;
		case 'T': Hermes_testvector( x, k, algo, my_plaintext,  MY_PT_LENGTH );
		          break;
		case 'M': makesequence();break;
		case 'N': makevisiblesequence( MY_SC_ROUNDS );break;
		case 'Q': doFIPS1402_crunch();
		          printf(" doFIPS1402_crunch  done. \n");
		          break; /* UK20020205 */
		case 'S': doFIPS1402_stream( 100 );
		          printf(" doFIPS1402_stream  done. \n");
		          break; /* UK20050213 */
		case 'R': doFIPS1402_longstream();
		          printf(" doFIPS1402_longstream  done. \n");
		          break; /* UK20050214 */
		case '1': MY_PT_LENGTH = GetPtLength( "PT_LENGTH =  ? ", "[256..32000]" );
			  break;
		case '3': MY_IV_LENGTH = GetIvLength( "IV_LENGTH =  ? ", "[4..37]" );
			  break;
		case '4': MY_PT_PATTERN = GetPtPattern( "PT_PATTERN =  ? ", "[0..255]" );
		           /* initialize plaintext */
                          for( n=0; n<PTSIZE; n++ ) my_plaintext[n] = (u8)MY_PT_PATTERN;
			  break;
		case '6': MY_INIT_ROUNDS = GetInitRounds( "InitRounds =  ? ", "[1..32]" );
			  break;
		case '7': MY_SC_ROUNDS = GetScRounds( "StreamCipherRounds =  ? ", "[1..1000]" );
			  break;
		case '8': doFIPS1402_stream( 1 );
		          printf(" doFIPS1402_stream  done. \n");
		          break; /* UK20050527 */
		case '9': doFIPS1402_ECRYPTstream( 1 );
		          printf(" doFIPS1402_ECRYPTstream  done. \n");
		          break; /* UK20050527 */
		case '5': GetReg("r = ", RandReg, 8);break;
		case  27: done=1;break;
		case '.': done=1;break;
	 }/*switch*/
	 
	 /* fclose( op );
         op=fopen("RESULTS.TXT","wa"); */
	 
  }/*while*/

  return 0;
  
}/* main */

/* ----------------------------------- end ------------------------------- */
