/*
 encrypt.c - PSEC-1 encryption function

 Copyright NTT MCL, 2000.

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

#include <stdio.h>
#include <gmp.h>
#include "ec_arith.h"
#include "psec1.h"
#include "hash.h"
#include "utils.h"
#include "random.h"


/*
PSEC-1 encryption
Return: TRUE if succeed; otherwise FALSE
*/
BYTE PSEC1_Encryption (
   BYTE             *message,    /* plaintext */
   PSEC1_PUB_KEY    *publicKey,  /* PSEC1 public key */
   PSEC1_CIPHERTEXT *ciphertext,  /* returned ciphertext */
   EC_PARAM         *E
)
{
mpz_t m, r, t, m_n_r;
EC_POINT Q;
BYTE *m_raw, *r_raw, *m_n_r_raw, *t_raw, *tmp_ptr;
RANDOM_STRUCT randomStruct;
unsigned int bytesNeeded;
static unsigned char seedByte = 0;
WORD m_n_r_raw_len;
long i;

	mpz_init(m);
	mpz_init(r);
	mpz_init(t);
	mpz_init(m_n_r);
	m_raw = (BYTE *) malloc (publicKey->mLen/8);
	r_raw = (BYTE *) malloc (E->pLen/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);

	/* convert (BYTE *) message to raw format */
	mpz_set_str(m, message, 0);
	WORD2BYTE(m_raw+(publicKey->mLen/8-ABS(m->_mp_size)*4), m->_mp_d,
	          ABS(m->_mp_size));
	/*
	printf("PSEC1_encryption: m_raw =\n");
	for(i=0; i< publicKey->mLen/8; i++)
		printf("%02x ", m_raw[i]);
	printf("\n\n");
	*/

	/* initialize random number generator */
	RandomInit(&randomStruct);
	/* initialize with all zero seed bytes for testing purpose only */
	while (1) {
		GetRandomBytesNeeded (&bytesNeeded, &randomStruct);
		if (bytesNeeded == 0) break;
		RandomUpdate (&randomStruct, &seedByte, 1);
	}

	/* generate r */
	GenerateBytes(r_raw, publicKey->rLen/8, &randomStruct);
	/*
	printf("PSEC1_Encryption: r_raw =\n");
	for(i=0; i< publicKey->rLen/8; i++)
		printf("%02x ", r_raw[i]);
	printf("\n\n");
	*/
	/* testing */
	/*
	r_raw[0] = 0xe7;
	r_raw[1] = 0x81;
	r_raw[2] = 0x63;
	*/

	BYTE2WORD(r, r_raw, publicKey->rLen/8);
	printf("r = 0x%s\n", mpz_get_str(NULL, 16, r));

	/* m_n_r_raw := m_raw || r_raw */
	assignBYTE(m_n_r_raw, m_raw, publicKey->mLen/8);
	tmp_ptr = m_n_r_raw + publicKey->mLen/8;
	assignBYTE(tmp_ptr, r_raw, publicKey->rLen/8);
	m_n_r_raw_len = (publicKey->mLen + publicKey->rLen)/8;

	/* testing */
	/*
	m_n_r_raw--;
	m_n_r_raw[0]=0;
	m_n_r_raw_len++;
	*/

	/*
	printf("PSEC1_Encryption: m_n_r_raw =\n");
	for(i=0; i< m_n_r_raw_len; i++)
		printf("%02x ", m_n_r_raw[i]);
	printf("\n\n");
	*/

	BYTE2WORD(m_n_r, m_n_r_raw, m_n_r_raw_len);
	/*
	printf("PSEC1_Encryption: m_n_r =\n");
	printf("%s\n\n", mpz_get_str(NULL, 16, m_n_r));
	*/

	/* t_raw := H(m_n_r_raw) */
	indexedSHA( t_raw, publicKey->hLen/8, m_n_r_raw, m_n_r_raw_len);
	/*
	printf("PSEC1_Encryption: 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("PSEC1_Encryption: t =\n");
	printf("%s\n\n", mpz_get_str(NULL, 16, t));
	*/

	/* Q := t * pk */
	EC_initPoint(&Q);
	EC_Mult(&Q, t, &(publicKey->pk), E);
	/*
	printf("PSEC1_Encryption: 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);
	*/

	/* C1 := t * P */
	EC_initPoint(&(ciphertext->C1));
	EC_Mult(&(ciphertext->C1), t, &(E->P), E);
	/*
	printf("PSEC1_Encryption: ciphertext->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);
	*/

	/* c2 := m_n_r \xor x_Q */
	mpz_init(ciphertext->c2);
	mpz_xor(ciphertext->c2, m_n_r, Q.x);
	/*
	printf("PSEC1_Encryption: ciphertext->c2 =\n");
	printf("%s\n\n", mpz_get_str(NULL, 16, ciphertext->c2));
	*/


	/* clean up */
	mpz_clear(m);
	mpz_clear(r);
	mpz_clear(t);
	mpz_clear(m_n_r);

	memset(m_raw, 0, publicKey->mLen/8);
	memset(r_raw, 0, E->pLen/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(m_n_r_raw);
	free(t_raw);

	m_n_r_raw_len = 0;

	return TRUE;
}
