/* ****

*/

#include <time.h>
#include "mycrypt.h"
#include "sks.h"
/*#include "ec_mpcrypt.h"*/


#ifdef LANG_ES
#include "sks_msg_es.h"
#else
#include "sks_msg_en.h"
#endif

#define eccRandom(A)	get_entropy(A, GF_SIZE)

int ec_cryptCheck(int test_count)
{
	int i, crypt_fail = 0, sign_fail = 0;
	clock_t elapsed_crypt = 0L, elapsed_sign = 0L, elapsed_key = 0L;
	PubKey 		pub;
	PrivKey 	priv;
	vlPoint 	sec1, sec2, msg;
	sgPair		sig;
	ecPoint	cod;
	
	eccInit();
	
	srand ((unsigned)(time(NULL) % 65521U));
		
	fprintf(stderr, "  Encryption based on Elliptic Curve Group. GF(2^%d)\n", GF_M);
	fprintf(stderr, "  Bits per digit: %d\n", DIGIT_BIT);
	fprintf(stderr, "  Checking %d times...\n", test_count);
	
	for(i = 0; i < test_count; ++i){
		
		/** Make key **/
		eccRandom(priv);
		elapsed_key -= clock();
		eccMakePublicKey(pub, priv);
		elapsed_key += clock();
		
		/** crypt/decrypt **/
		eccRandom(sec1);
		elapsed_crypt -= clock();
		eccEncode(&pub, &cod, sec1, 1);
		eccDecode(priv, cod, sec2);
		elapsed_crypt += clock();
		
		if(memcmp(sec1, sec2, GF_SIZE)){
			crypt_fail++;
			#ifdef DEBUG
			eccPrint("sec1", sec1);
			eccPrint("sec2", sec2);
			#endif
		}
		
		/** sign/verify **/
		eccRandom(msg);
		int ver;
		do{
			eccRandom(sec1);
			elapsed_sign -= clock();
			ver = eccSign(priv, sec1, msg, &sig);
			elapsed_sign += clock();
		} while(ver);
		
		elapsed_sign -= clock();
		ver = eccVerify(pub, msg, &sig);
		elapsed_sign += clock();
		if(!ver) sign_fail++;
		
	}
	
	printf ("  Done.\n  Encrypt-Decrypt time: %.3f s/cicle.\n",
		(float)elapsed_crypt/CLOCKS_PER_SEC/(test_count));
	printf ("  Sign/Verify time: %.3f s/cicle.\n",
		(float)elapsed_sign/CLOCKS_PER_SEC/(test_count));
	printf ("  Key generation time: %.3f s/key.\n",
		(float)elapsed_key/CLOCKS_PER_SEC/(test_count));
	if (crypt_fail) printf ("  ---> %d fails in encryption/decryption <---\n", crypt_fail);
	if (sign_fail) printf ("  ---> %d fails in signing /verifying <---\n", sign_fail);
	
	
	eccQuit();
	return crypt_fail | sign_fail;
}



int myaes_test(void)
{
    
 int err;
 static const struct {
     int keylen;
     unsigned char key[32], pt[16], ct[16];
 } tests[] = {
    { 16,
      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, 
      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
      { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 
        0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }
    }, { 
      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 },
      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
      { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 
        0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }
    }, {
      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 },
      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
      { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 
        0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }
    }
 };
 
 symmetric_key key;
 unsigned char tmp[2][16];
 int i, y;
 
 for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
    zeromem(&key, sizeof(key));
    if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { 
       return err;
    }
  
    rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key);
    rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
    if (memcmp(tmp[0], tests[i].ct, 16) || memcmp(tmp[1], tests[i].pt, 16)) { 

        return CRYPT_FAIL_TESTVECTOR;
    }

      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
      for (y = 0; y < 16; y++) tmp[0][y] = 0;
      for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
      for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
      for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
 }       
 return CRYPT_OK;
 
}

int  mytiger_test(void)
{
    
  static const struct {
      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 }
    },
  };

  int i;
  unsigned char tmp[24];
  hash_state md;

  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
      tiger_init(&md);
      tiger_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
      tiger_done(&md, tmp);
      if (memcmp(tmp, tests[i].hash, 24) != 0) {
          return CRYPT_FAIL_TESTVECTOR;
      }
  }
  return CRYPT_OK;
  
}

int entropy_test()
{
	int n = 256, chunk = 16;
	unsigned char buf[16];
	while(n){
		int i = chunk;
		if(!get_entropy(buf, chunk)) return 1;
		fputs("\t", stdout);
		while(i--) printf("%02x", buf[i]);
		puts("");
		n -= chunk;
	}
	return 0;
}

int main()
{
		
	int exit_code = 0;
	
	puts("PRNG Test starts...");
	if (entropy_test()){
		printf("PRNG Test fails.\n");
		exit_code |= 8;
	}
	else {
		printf("PRNG Test good.\n");
	}
	puts("ECC Test starts...");
	if (ec_cryptCheck(5)){
		printf("ECC Test fails.\n");
		exit_code |= 4;
	}
	else {
		printf("ECC Test good.\n");
	}
	if (myaes_test() != CRYPT_OK){
		printf("AES Test fails.\n");
		exit_code |= 1;
	}
	else {
		printf("AES Test good.\n");
	}
	
	if (mytiger_test() != CRYPT_OK){
		printf("TIGER Test fails.\n");
		exit_code |= 2;
	}
	else {
		printf("TIGER Test good.\n");
	}
	
	
	exit(exit_code);
}	
