/*
 decrypt.c - PSEC-2 decryption function

 Copyright NTT MCL, 2000.

 Duncan S Wong   
 Security Group, NTT MCL
 July 2000
*/

#include <stdio.h>
#include <string.h>
#include <gmp.h>
#include "ec_arith.h"
#include "psec2.h"
#include "hash.h"
#include "utils.h"

void BulkDecrypt(BYTE *message, CIPHER_INFO *cipherInfo, BYTE *K, WORD KLen,
	              PSEC2_CIPHERTEXT *ciphertext);

/*
 PSEC-2 Decryption

 Return: TRUE if succeed; otherwise FALSE
*/
BYTE PSEC2_Decryption (
   PSEC2_CIPHERTEXT *ciphertext,
   CIPHER_INFO      *cipherInfo,
   PSEC2_PUB_KEY    *publicKey,
   PSEC2_PRIV_KEY   *privateKey,
   BYTE             *message,
   EC_PARAM         *E
)
{
mpz_t r, t;
EC_POINT D, Q;
BYTE *r_raw, *K_raw, *m_raw, *m_n_r_raw, *tmp_ptr, *t_raw, *r_raw_ptr;
BYTE compare_result;
long i;

	/*
	printf("PSEC2_Decryption: C1 =\n");
	printf("%s\n%s\n%d\n\n", mpz_get_str(NULL, 16, (ciphertext->C1).x),
	       mpz_get_str(NULL, 16, (ciphertext->C1).y),
	       (ciphertext->C1).inf_id);
	printf("PSEC2_Decryption: c2 =\n%s\n\n",
	       mpz_get_str(NULL, 16, ciphertext->c2));
	printf("PSEC2_Decryption: c3 =\n");
	for(i=0; i<publicKey->mLen/8; i++)
		printf("%02x ", ciphertext->c3[i]);
	printf("\n\n");
	*/

	mpz_init(r);
	mpz_init(t);
	m_raw = (BYTE *) malloc (publicKey->mLen/8);
	r_raw = (BYTE *) malloc (E->qLen/8);
	K_raw = (BYTE *) malloc (publicKey->mLen/8);
	m_n_r_raw = (BYTE *) malloc ((publicKey->mLen + publicKey->rLen)/8);
	t_raw = (BYTE *) malloc (publicKey->hLen/8);

	memset(m_raw, 0, publicKey->mLen/8);
	memset(r_raw, 0, E->qLen/8);

	/* compute D = sk * C1 */
	EC_initPoint(&D);
	EC_Mult(&D, privateKey->sk, &(ciphertext->C1), E);

	/* compute r = c2 \xor x_D */
	mpz_xor(r, ciphertext->c2, D.x);
	/* printf("PSEC2_Decryption: r = %s\n\n", mpz_get_str(NULL, 16, r)); */

	/* compute K_raw := G(r_raw) */
	r_raw_ptr = r_raw + (E->qLen - publicKey->rLen)/8;
	WORD2BYTE(r_raw_ptr+(publicKey->rLen/8-ABS(r->_mp_size)*4), r->_mp_d,
	          ABS(r->_mp_size));
	indexedSHA( K_raw, publicKey->gLen/8, r_raw_ptr, publicKey->rLen/8);

	/*
	printf("PSEC2_Decryption: K_raw =\n");
	for(i=0; i< publicKey->gLen/8; i++)
		printf("%02x ", K_raw[i]);
	printf("\n\n");
	*/

	/* compute (BYTE *) m_raw */
	BulkDecrypt(m_raw, cipherInfo, K_raw, publicKey->mLen, ciphertext);

	/*
	printf("PSEC2_Decryption: m_raw =\n");
	for(i=0; i< publicKey->mLen/8; i++)
		printf("%02x ", m_raw[i]);
	printf("\n\n");
	*/

	/* check C1 */
	assignBYTE(m_n_r_raw, m_raw, publicKey->mLen/8);
	tmp_ptr = m_n_r_raw + publicKey->mLen/8;
	assignBYTE(tmp_ptr, r_raw_ptr, publicKey->rLen/8);
	/*
	printf("PSEC2_Decryption: m_n_r_raw =\n");
	for(i=0; i<(publicKey->mLen + publicKey->rLen)/8; i++)
		printf("%02x ", m_n_r_raw[i]);
	printf("\n\n");
	*/

	indexedSHA(t_raw, publicKey->hLen/8, m_n_r_raw,
	           (publicKey->mLen + publicKey->rLen)/8);
	/*
	printf("PSEC2_Decryption: t_raw =\n");
	for(i=0; i<publicKey->hLen/8; i++)
		printf("%02x ", t_raw[i]);
	printf("\n\n");
	*/

	BYTE2WORD(t, t_raw, publicKey->hLen/8);
	/*
	printf("PSEC2_Decryption: t =\n");
	printf("%s\n\n", mpz_get_str(NULL, 16, t));
	*/

	EC_initPoint(&Q);
	EC_Mult(&Q, t, &(E->P), E);

	/* compare Q with C1 */
	compare_result = 0;
   compare_result += ABS(mpz_cmp((ciphertext->C1).x, Q.x));
   compare_result += ABS(mpz_cmp((ciphertext->C1).y, Q.y));
   if((ciphertext->C1).inf_id != Q.inf_id)
      compare_result++;

   if(compare_result) {
      printf("Checking failed.\n");
      sprintf(message,"");
   } else {
      sprintf(message,"0x");
      tmp_ptr = message+2;
      i = 0;
      while(m_raw[i] == 0 && i != (publicKey->mLen/8-1)) i++;
      while (i<publicKey->mLen/8) {           
         sprintf(tmp_ptr,"%02x",m_raw[i]);
         tmp_ptr += 2; 
         i++;
      }  
   }
   /* printf("PSEC2_Decryption: message =\n%s\n\n", message); */


	/* clean up */
	mpz_clear(r);
	mpz_clear(t);
	EC_clearPoint(&D);
	EC_clearPoint(&Q);

	memset(m_raw, 0, publicKey->mLen/8);
	memset(r_raw, 0, E->qLen/8);
	memset(K_raw, 0, publicKey->mLen/8);
	memset(m_n_r_raw, 0, (publicKey->mLen + publicKey->rLen)/8);
	memset(t_raw, 0, publicKey->hLen/8);
	free(m_raw);
	free(r_raw);
	free(K_raw);
	free(m_n_r_raw);
	free(t_raw);

	i = 0;

	return TRUE;
}


void BulkDecrypt(BYTE *message, CIPHER_INFO *cipherInfo, BYTE *K, WORD KLen,
	              PSEC2_CIPHERTEXT *ciphertext)
{
   if(cipherInfo->algorithmID == ENCRYPT_ALG_XOR) {
      Vernam(K, KLen, ciphertext->c3, message);
   }
}
