/*
 decrypt.c - PSEC-1 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 "psec1.h"
#include "hash.h"
#include "utils.h"


/*
 PSEC-1 decryption

 Return: TRUE if succeed; otherwise FALSE
*/
BYTE PSEC1_Decryption (
   PSEC1_CIPHERTEXT *ciphertext,
   PSEC1_PUB_KEY    *publicKey,
   PSEC1_PRIV_KEY   *privateKey,
   BYTE             *message,
   EC_PARAM         *E
)
{
mpz_t u, t, m;
EC_POINT D, Q;
BYTE *u_raw,*t_raw, *tmp_ptr, *u_raw_ptr;
WORD uLen;
BYTE compare_result;
long i;

	/*
	printf("PSEC1_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("PSEC1_Decryption: c2 =\n%s\n\n",
	       mpz_get_str(NULL, 16, ciphertext->c2));
	*/

	mpz_init(u);
	mpz_init(t);
	mpz_init(m);
	t_raw = (BYTE *) malloc (publicKey->hLen/8);

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

	/*
	printf("PSEC1_Decryption: D =\n");
	printf("%s\n%s\n%d\n\n", mpz_get_str(NULL, 16, D.x),
	       mpz_get_str(NULL, 16, D.y), D.inf_id);
	*/

	/* compute u = c2 \xor x_D */
	mpz_xor(u, ciphertext->c2, D.x);
	uLen = (publicKey->mLen + publicKey->rLen)/8;

	/* checkif C1 == t * P where t := H(u) */
	u_raw = (BYTE *) malloc (E->qLen/8);
	u_raw = memset(u_raw, 0, E->qLen/8);
	u_raw_ptr = u_raw + E->qLen/8 - uLen;
	WORD2BYTE(u_raw_ptr+(uLen-ABS(u->_mp_size)*4), u->_mp_d, ABS(u->_mp_size));

	/*
	printf("PSEC1_Decryption: u =\n%s\n\n", mpz_get_str(NULL, 16, u));
	printf("PSEC1_Decryption: uLen =\n%lu\n\n", uLen);
	printf("PSEC1_Decryption: u_raw =\n");
	for(i=0; i< E->qLen/8; i++)
		printf("%02x ", u_raw[i]);
	printf("\n\n");
	*/

	indexedSHA(t_raw, publicKey->hLen/8, u_raw_ptr, uLen);

	BYTE2WORD(t, t_raw, publicKey->hLen/8);

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

	/*
	printf("PSEC1_Decryption: Q =\n");
	printf("%s\n%s\n%d\n\n", mpz_get_str(NULL, 16, Q.x),
	       mpz_get_str(NULL, 16, Q.y), Q.inf_id);
	*/

	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("Signature checking failed.\n");
		sprintf(message,"");
   } else {
		BYTE2WORD(m, u_raw_ptr, publicKey->mLen/8);
		sprintf(message, "0x%s", mpz_get_str(NULL, 16, m));
	}

	/* clean up */
	mpz_clear(u);
	mpz_clear(t);
	mpz_clear(m);

	memset(t_raw, 0, publicKey->hLen/8);
	memset(u_raw, 0, E->qLen/8);
	free(t_raw);
	free(u_raw);

	EC_clearPoint(&D);
	EC_clearPoint(&Q);

	uLen = 0;

	return TRUE;
}
