/*
* Creation date : Tue May 13 15:21:48 2008
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of 
* DH (Diffie-Hellman key exchange) functions. 
*
* \version LLF_DH_KG.c#1:csrc:1
* \author Aliaksandr Masiuk
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

/************************ Include Files ***********************/

#include "LLF_DH_KG.h"
#include "CE2_HASH.h"
#include "tomcrypt.h"
#include "tommath.h"

/************************ Defines *****************************/
/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/
/************************ Private function prototype **********/
/************************ Private Functions *******************/

/**
****************************************************************
* Function Name: 
*  LLF_DH_SetBit
*
* Inputs:
* @param a       [in/out] - integer;
* @param bit_pos [in]     - bit position to set in integer a.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  Sets bit in the integer a.
*
* \b
* Algorithm:
*  -# Resize integer a if needed;
*  -# Set bit to 1.
***************************************************************/
CE2Error_t LLF_DH_SetBit(
	mp_int						*a,						/* [in/out] */
	unsigned int				bit_pos)				/* [in] */
{
	CE2Error_t	result = CE2_OK,
				error_code;

	/* Grow a to accommodate the single bit */
	if ((error_code = mp_grow(a, bit_pos / DIGIT_BIT + 1)) != MP_OKAY)
		return error_code;

	/* Set the used count of where the bit will go */
	a->used = bit_pos / DIGIT_BIT + 1;

	/* Put the single bit in its place */
	a->dp[bit_pos / DIGIT_BIT] |= ((mp_digit)1) << (bit_pos % DIGIT_BIT);

	return CE2_OK;
} /* End of LLF_DH_SetBit */

/**
****************************************************************
* Function Name: 
*  LLF_DH_KG_SelectGenerator
*
* Inputs:
* @param p [in]  - prime p, such p = jq + 1;
* @param q [in]  - prime q;
* @param j [in]  - integer j [optoinal];
* @param g [out] - selected generator according to p, q.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function performs selection of a Generator for q-order
*  Subgroup according to ANSI X9.42-2001 [Annex B.2].
*   The generator g is a field element of GF(p). The generator g
*  shall be chosen so that it is of prime order q, where q divides
*  p-1. In other words, g shall be chosen such that it generates
*  the subgroup of order q in the multiplicative group of GF(p).
*
*  Assume that p and q are valid parameters. The following algorithm
*  will generate such a generator g.
*
* \b
* Algorithm:
*  -# Let j = (p - 1)/q;
*  -# Set g = any integer not already tried, where 1 < g < (p - 1);
*  -# Set g = g^j mod p;
*  -# If g = 1, go to step 2. Otherwise, go to step 5;
*  -# Output g.
***************************************************************/
CE2Error_t LLF_DH_KG_SelectGenerator(
	void						*p,						/* [in] */
	void						*q,						/* [in] */
	void						*j,						/* [in] */
	void						*g)						/* [out] */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*i, *jj;
	void		*g_curr;
	void		*p_1, *d;
	mp_digit	r;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&i, &g_curr, &p_1, &d, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	If j is not provided externally than
	1. Let j = (p - 1)/q
	*/

	/* p_1 = (p - 1) */
	error_code = mp_sub_d(p, 1, p_1);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (j == 0)
	{
		/* Initialize local j value */
		error_code = ltc_init_multi(&jj, NULL);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		j = jj;

		/* j = (p - 1)/q */
		error_code = mp_div(p_1, q, j, d);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}
	else
		jj = NULL;

	/*
	2. Set g = any integer not already tried, where 1 < g < (p - 1).
	*/

	/* Generate random shift */
	r = ((rand() << 16) + rand()) | 0x01;

	/* g = p - rand */
	error_code = mp_sub_d(p_1, r, g_curr);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	for (;;)
	{
		/*
		3. Set g = g^j mod p.
		*/

		error_code = mp_exptmod(g_curr, j, p, g);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/*
		4. If g = 1, go to step 2. Otherwise, go to step 5.
		*/

		if (mp_cmp_d(g, 1) != MP_EQ)
		{
			/*
			5. Output g.
			*/
			break;
		}

		/* where 1 < g < (p - 1) */
		if (mp_cmp_d(g, 1) != MP_GT)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			break;
		}

		/* Generate random shift */
		r = ((rand() << 16) + rand()) | 0x01;

		/* g = g - rand */
		error_code = mp_sub_d(g_curr, r, g_curr);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

exit_label:
	ltc_deinit_multi(i, g_curr, p_1, d, NULL);

	/* Release j if needed */
	if (jj != NULL)
		ltc_deinit_multi(jj, NULL);

	return result;
} /* End of LLF_DH_KG_SelectGenerator */

/**
****************************************************************
* Function Name: 
*  LLF_DH_KG_CalculateJ
*
* Inputs:
* @param p [in]  - prime p, such p = jq + 1;
* @param q [in]  - prime q;
* @param j [out] - selected j according to p, q.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function performs calculation of a j factor according to
*  ANSI X9.42-2001.
*
*  Assume that p and q are valid parameters. The following algorithm
*  will compute such a factor j and return error when p and q
*  aren't valid.
*
* \b
* Algorithm:
*  -# Calculate j = (p - 1)/q;
*  -# Validate residue of division = 0.
***************************************************************/
CE2Error_t LLF_DH_KG_CalculateJ(
	void						*p,						/* [in] */
	void						*q,						/* [in] */
	void						*j)						/* [out] */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p_1;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p_1, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	1. Calculate j = (p - 1)/q
	*/

	/* p_1 = (p - 1) */
	error_code = mp_sub_d(p, 1, p_1);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* j = (p - 1)/q */
	error_code = mp_div(p_1, q, j, p_1);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	2. Validate j: p_1 == 0
	*/
	if (mp_cmp_d(p_1, 0) != MP_EQ)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(p_1, NULL);

	return result;
} /* End of LLF_DH_KG_CalculateJ */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CreateDomainParams_Q
*
* Inputs:
* @param[in]  orderQSizeBits     - The size of order of generator in bits. Must be m >= 160 and
*                                  multiple of 32 bits. According to ANSI X9.30-1: m = 160.
* @param[out] q                  - The pointer to the order Q of generator. Size of the buffer for output 
*                                  generated value must be not less, than order size. 
* @param[in]  seed               - The random seed used for generation of primes. If the pointer == NULL,  
*                                  the function not puts this parametr out. Size of the buffer for output 
*                                  generated value must be not less, than passed seed size. 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  The function generates a DH (DLP) domain parameter Q in GF(P)
*  (see X9.42-2001).
*
* \b
* Algorithm:
*  -# Set m' = [m/160];
*  -# [ignored]
*  -# [ignored]
*  -# [ignored]
*  -# Set q = 0;
*  -# For i = 0 to m'-1 do
*       q = q + (SHA1(seed + i) (+) SHA1(seed + m' + i)) 2^160i;
*  -# Set q = q (mod 2^m) and then update q, if necessary, by
*     setting the first and the last bits equal to 1 in the
*     binary representation of q;
*  -# Perform a primality test as given in Section B.1.1 on q.
*     If q is composite, then go to step 4 to select a new value
*     for seed.
***************************************************************/
CE2Error_t LLF_DH_CreateDomainParams_Q( 
	DxUint32_t					orderQsizeBits,			/* [in] */
	mp_int						*q,						/* [out] */
	mp_int						*seed,					/* [in] */
	int							*prime_result)			/* [out] */
{
	/*
	m = orderQsizeBits;
	*/
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*seed_i, *SHA1_seed_i,
				*seed_m_, *SHA1_seed_m_,
				*SHA1,
				*_2_power_160i;
	int			length;
	unsigned long hash_size;
	int			hash_idx = 0;
	DxUint32_t	i, j;
	DxUint32_t	buff_seed_i[CE2_DH_MAX_MOD_BUFFER_SIZE_IN_WORDS];
	DxUint32_t	buff_seed_m_[CE2_DH_MAX_MOD_BUFFER_SIZE_IN_WORDS];
	/*
	1. Set m' = [m/160].
	*/
	DxUint32_t m_ = ((orderQsizeBits) / 160) + (((orderQsizeBits) % 160) ? (1) : (0));

	/* register prng */
	if (register_prng(&yarrow_desc) == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Register SHA1 hash */
	if (register_hash(&sha1_desc) == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	hash_idx = find_hash("sha1");

	if (hash_idx == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Initialize LibTomCrypt primitives */
	error_code =
		ltc_init_multi(
			&seed_i, &SHA1_seed_i, &seed_m_, &SHA1_seed_m_,
			&SHA1, &_2_power_160i, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	error_code = mp_copy(seed, seed_i);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	error_code = mp_add_d(seed, m_, seed_m_);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	5. Set q = 0.
	*/
	error_code = mp_set_int(q, 0);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	6. For i = 0 to m'-1 do
		q = q + (SHA1(seed + i) (+) SHA1(seed + m' + i)) 2^160i.
	*/

	/* q = q + (SHA1(seed + i) (+) SHA1(seed + m' + i)) 2^160i. */
	for (i = 0; i <= m_ - 1; ++i)
	{
		/* Calculate SHA1(seed + i): */
		/* seed_i += 1 */
		if (i > 0)
		{
			error_code = mp_add_d(seed_i, 1, seed_i);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		length = mp_unsigned_bin_size(seed_i);

		/* write seed_i to buffer */
		error_code = mp_to_unsigned_bin(seed_i, (unsigned char *)buff_seed_i);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* calculate SHA1(seed + i) */
		hash_size = CE2_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
		error_code =
			hash_memory(
				hash_idx, (const unsigned char *)buff_seed_i, length,
				(unsigned char *)buff_seed_i, &hash_size);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Calculate SHA1(seed + m' + i): */
		/* seed_m_ += 1 */
		if (i > 0)
		{
			error_code = mp_add_d(seed_m_, 1, seed_m_);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		length = mp_unsigned_bin_size(seed_m_);

		/* write seed_i to buffer */
		error_code = mp_to_unsigned_bin(seed_m_, (unsigned char *)buff_seed_m_);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* calculate SHA1(seed + m' + i) */
		hash_size = CE2_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
		error_code =
			hash_memory(
				hash_idx, (const unsigned char *)buff_seed_m_, length,
				(unsigned char *)buff_seed_m_, &hash_size);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* buff_seed_i = buff_seed_i xor buff_seed_m_ */
		for (j = 0; j < (DxUint32_t)hash_size; ++j)
			buff_seed_i[j] ^= buff_seed_m_[j];

		/* SHA1 = (SHA1(seed + i) (+) SHA1(seed + m' + i)) */
		error_code = mp_read_unsigned_bin(SHA1, (const unsigned char *)buff_seed_i, hash_size);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		if (i > 0)
		{
			/* _2_power_160i = 2^160i */
			error_code = mp_2expt(_2_power_160i, 160*i);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}

			/* SHA1 = SHA1 * 2^160i */
			error_code = mp_mul(SHA1, _2_power_160i, SHA1);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		/* q = q + (SHA1(seed + i) (+) SHA1(seed + m' + i)) 2^160i. */
		error_code = mp_add(q, SHA1, q);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	7. Set q = q (mod 2^m) and then update q, if necessary, by setting the first and the last bits
		equal to 1 in the binary representation of q.
	*/

	/* q = q (mod 2^m) */
	error_code = mp_mod_2d(q, orderQsizeBits, q);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* setting the first and the last bits equal to 1 in the binary representation of q */
	error_code = LLF_DH_SetBit(q, 0);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	error_code = LLF_DH_SetBit(q, orderQsizeBits - 1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	8. Perform a primality test as given in Section B.1.1 on q. If q is composite, then go to
		step 4 to select a new value for seed.
	*/
	error_code = mp_prime_is_prime(q, 50, prime_result);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(
		seed_i, SHA1_seed_i, seed_m_, SHA1_seed_m_,
		SHA1, _2_power_160i, NULL);

	return result;
} /* End of LLF_DH_CreateDomainParams_Q */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CreateDomainParams
*
* Inputs:
* @param[in]  modPSizeBits       - The  modulus (prime) P size in bits equal 256*n, where n >= 4. 
* @param[in]  orderQSizeBits     - The size of order of generator in bits. Must be m >= 160 and
*                                  multiple of 32 bits. According to ANSI X9.30-1: m = 160.
* @param[out] p                  - The prime modulus P of structure P = J*Q + 1, where Q is prime
*                                  and j is an integer. Size of the buffer for output generated value must 
*                                  be not less, than modulus size. 
* @param[out] q                  - The pointer to the order Q of generator. Size of the buffer for output 
*                                  generated value must be not less, than order size. 
* @param[out] g                  - The pointer to the generator of multiplicative subgroup in GF(P).
*                                  Size of the buffer for output generated value must be not less, 
*                                  than modulus size. If the pointer == NULL, the function not puts this 
*                                  parametr out (in this case generGsizeBytes_ptr must be set to NULL also, 
*                                  otherwise the function returns an error). Size of the buffer must be not less,
*                                  than modulus size. 
* @param[out] j                  - The pointer to buffer for integer factor J. If the pointer == NULL, the function 
*                                  not puts this parametr out  (in this case JsizeBytes_ptr must be set to NULL also, 
*                                  otherwise the function returns an error). Size of the buffer must be not less,
*                                  than ( modPSizesBytes - orderQSizeBytes + 1 ). 
* @param[in/out] seed            - The random seed used for generation of primes. If the pointer == NULL,  
*                                  the function not puts this parametr out. Size of the buffer for output 
*                                  generated value must be not less, than passed seed size. 
* @param[out] pgenCounter_ptr    - The pointer to counter of tries to generate the primes. If the pointer == NULL, 
*                                  the function not puts this parametr out.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  The function generates a DH (DLP) domain parameters P in GF(P)
*  (see X9.42-2001).
*
* \b
* Algorithm:
*  -# Perform DH domain parameters creation according to
*     ANSI X9.42-2001 [7.1, Annex B.1.2].
***************************************************************/
CE2Error_t LLF_DH_CreateDomainParams_P(
	DxUint32_t					modPsizeBits,			/* [in] */
	DxUint32_t					orderQsizeBits,			/* [in] */
	mp_int						*p,						/* [out] */
	mp_int						*q,						/* [in] */
	mp_int						*g,						/* [out] */
	DxUint8_t					*j,						/* [out] */
	mp_int						*seed,					/* [in/out] */
	DxUint32_t					*pgenCounter_ptr,		/* [out] */
	DxUint32_t					pgenCounterMax)			/* [in] */
{
	/*
	m = orderQsizeBits;
	L = modPsizeBits;
	*/
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*seed_i, *SHA1_seed_i,
				*seed_m_, *SHA1_seed_m_,
				*SHA1,
				*_2_power_160i,
				*R;
	int			length;
	int			prime_result;
	unsigned long hash_size;
	int			hash_idx = 0;
	DxUint32_t	i;
	DxUint32_t	buff_seed_i[CE2_DH_MAX_MOD_BUFFER_SIZE_IN_WORDS];
	/*
	1. Set m' = [m/160].
	2. Set L' = [L/160].
	3. Set N = [L/1024].
	*/
	DxUint32_t m_ = ((orderQsizeBits) / 160) + (((orderQsizeBits) % 160) ? (1) : (0));
	DxUint32_t L_ = ((modPsizeBits) / 160) + (((modPsizeBits) % 160) ? (1) : (0));
	DxUint32_t N = ((modPsizeBits) / 1024) + (((modPsizeBits) % 1024) ? (1) : (0));

	/* Get HASH id */
	hash_idx = find_hash("sha1");

	if (hash_idx == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Initialize LibTomCrypt primitives */
	error_code =
		ltc_init_multi(
			&seed_i, &SHA1_seed_i,
			&seed_m_, &SHA1_seed_m_, &SHA1,
			&_2_power_160i, &R, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	9. Set pgenCounter = 0.
	*/
	*pgenCounter_ptr = 0;

step_10:
	/*
	10. Set R = seed + 2m' + (L' * pgenCounter).
	*/
	error_code = mp_add_d(seed, 2*m_ + L_ * (*pgenCounter_ptr), R);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	11. Set p = 0.
	*/
	error_code = mp_set_int(p, 0);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	12. For i = 0 to L'-1 do
		p = p + SHA1(R + i) 2^160i.
	*/

	for (i = 0; i <= L_ - 1; ++i)
	{
		/* Calculate SHA1(R + i): */
		/* R += 1 */
		if (i > 0)
		{
			error_code = mp_add_d(R, 1, R);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		length = mp_unsigned_bin_size(R);

		/* write seed_i to buffer */
		error_code = mp_to_unsigned_bin(R, (unsigned char *)buff_seed_i);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* calculate SHA1(R + i) */
		hash_size = CE2_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
		error_code =
			hash_memory(
				hash_idx, (const unsigned char *)buff_seed_i, length,
				(unsigned char *)buff_seed_i, &hash_size);

		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* SHA1 */
		error_code = mp_read_unsigned_bin(SHA1, (const unsigned char *)buff_seed_i, hash_size);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		if (i > 0)
		{
			/* _2_power_160i = 2^160i */
			error_code = mp_2expt(_2_power_160i, 160*i);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}

			/* SHA1 = SHA1 * 2^160i */
			error_code = mp_mul(SHA1, _2_power_160i, SHA1);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		/* p = p + SHA1(R + i) 2^160i */
		error_code = mp_add(p, SHA1, p);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	13. Set p = p (mod 2^L) and then update p, if necessary, by setting the most significant bit
		equal to 1 in the binary representation of p.
	*/

	/* p = p (mod 2^L) */
	error_code = mp_mod_2d(p, modPsizeBits, p);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* setting the most significant bit equal to 1 in the binary representation of p */
	error_code = LLF_DH_SetBit(p, modPsizeBits - 1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	14. Set p = p - (p mod 2q) + 1.
	*/

	/* R = 2*q */
	error_code = mp_mul_2(q, R);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* R = p mod R */
	error_code = mp_mod(p, R, R);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* p = p - R */
	error_code = mp_sub(p, R, p);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* p = p + 1 */
	error_code = mp_add_d(p, 1, p);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	15. If p > 2^(L-1), use a primality test as specified in Section B.1.1 to test if p is prime.
		Otherwise, go to step 17.
	*/

	/* R = 2^(L-1) */
	error_code = mp_2expt(R, modPsizeBits - 1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* If p > 2^(L-1), use a primality test as specified in Section B.1.1 to test if p is prime.
		Otherwise, go to step 17. */
	if (mp_cmp(p, R) != MP_GT)
	{
		goto step_17;
	}

	/*
	16. If the primality test in Section B.1.1 indicates that p is probably a prime, output p, q,
		seed, pgenCounter. Otherwise, go to step 17.
	*/
	error_code = mp_prime_is_prime(p, 50, &prime_result);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (prime_result == MP_YES)
	{
		/* p is probably a prime, output p, q, seed, pgenCounter. */

		/* Calculate extended parameters: j factor and generator */
		if (j != NULL)
		{
			/* Calculate j factor */
			error_code = LLF_DH_KG_CalculateJ(p, q, j);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		if (g != NULL)
		{
			/* Select generator */
			error_code = LLF_DH_KG_SelectGenerator(p, q, j, g);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		goto exit_label;
	}

	/*
	17. Set pgenCounter = pgenCounter + 1.
	*/
step_17:

	/*
	18. If pgenCounter < 4096*N, then go to step 10. Otherwise, go to step 19.
	*/
	if (++*pgenCounter_ptr < 4096*N)
	{
		/* If pgenCounter validation is present: validate it */
		if (*pgenCounter_ptr <= pgenCounterMax)
			goto step_10;
	}

	/*
	19. Output “failure”.
	*/
	result = CE2_LLF_DH_MODULE_ERROR_BASE;

exit_label:
	ltc_deinit_multi(
		seed_i, SHA1_seed_i, seed_m_,
		SHA1_seed_m_, SHA1,
		_2_power_160i, R, NULL);

	return result;
} /* End of LLF_DH_CreateDomainParams_P */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckDomainParams_pqs
*
* Inputs:
* @param[in]  p                  - The prime modulus P. Must be of structure P = j*Q + 1, 
*                                  where Q is prime and j is an integer.
* @param[in]  modPSizeBytes      - The modulus (prime) size in bytes. Size in bits must be 
*                                  equal 256*n, where n >= 4.
* @param[in]  q                  - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of generator order in bytes. Size in bytes must be >= 20.
* @param[in]  seed               - The random seed used for generation of primes (must be set if 
*                                  primes will be checked).
* @param[in]  pgenCounter        - The counter of tries to generate the primes (must be set if primes 
*                                  will be checked).
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function checks the obtained DH domain parameters according X9.42-2001.
*
*        There may be 3 case of checking:
*        1. Checking of primes only ( modulus P and order Q according to passed seed S and pgenCounter).
*           In this case all pointers and sizes of said parameters must be passed (not NULL), but generator 
*           G pointer and it size must be both set to NULL.
*
*        If any of checked domain parameters is not compliant to X9.42-2001 standard, the function returns
*        an error according to errors definitions in CE2_DH_error.h file.  
*
*     Note:  Input vectors are in big endianness.
*
* \b
* Algorithm:
*  -# Perform DH domain parameters validation according to
*     ANSI X9.42-2001 [7.2 (1), Annex B.1.3].
***************************************************************/
CE2Error_t LLF_DH_CheckDomainParams_pqs(
	mp_int						*p,						/* [in] */
	DxUint32_t					modPsizeBytes,			/* [in] */
	mp_int						*q,						/* [in] */
	DxUint32_t					orderQsizeBytes,		/* [in] */
	mp_int						*seed,					/* [in] */
	DxUint32_t					pgenCounter)			/* [in] */
{
	/*
	m = orderQsizeBytes * 8;
	L = modPsizeBytes * 8;
	*/
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p_,
				*q_,
				*seed_i, *SHA1_seed_i,
				*seed_m_, *SHA1_seed_m_,
				*SHA1,
				*_2_power_160i,
				*R;
	int			prime_result;
	int			hash_idx = 0;
	/*
	1. If L >= 1024, L == 0 mod 256, and m >= 160 then go to step 2. Otherwise, return
	“Invalid”.
	*/
	/*
	2. Set m' = [m/160].
	3. Set L' = [L/160].
	4. Set N = [L/1024]. If pgenCounter > 4096N, then return “Invalid”.
	*/
	DxUint32_t m_ = ((orderQsizeBytes * 8) / 160) + (((orderQsizeBytes * 8) % 160) ? (1) : (0));
	DxUint32_t L_ = ((modPsizeBytes * 8) / 160) + (((modPsizeBytes * 8) % 160) ? (1) : (0));
	DxUint32_t N = ((modPsizeBytes * 8) / 1024) + (((modPsizeBytes * 8) % 1024) ? (1) : (0));
	DxUint32_t pgenCounter_;

	/* Register SHA1 hash */
	if (register_hash(&sha1_desc) == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	hash_idx = find_hash("sha1");

	if (hash_idx == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Initialize LibTomCrypt primitives */
	error_code =
		ltc_init_multi(
			&p_, &q_, &seed_i, &SHA1_seed_i,
			&seed_m_, &SHA1_seed_m_, &SHA1,
			&_2_power_160i, &R, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Compute Q parameter */
	error_code =
		LLF_DH_CreateDomainParams_Q(
			orderQsizeBytes * 8, q_, seed, &prime_result);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (prime_result != MP_YES)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}
	else
	{
		/* is q == q’ */
		if (mp_cmp(q, q_) != MP_EQ)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/* Compute P parameter */
	error_code =
		LLF_DH_CreateDomainParams_P(
			modPsizeBytes * 8,
			orderQsizeBytes * 8,
			p_,
			q_,
			NULL,
			NULL,
			seed,
			&pgenCounter_,
			pgenCounter);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}
	else
	{
		/*
		19. If pgenCounter = pgenCounter’ and p = p’, output “Valid”. Otherwise, return
		“Invalid”.
		*/

		/* is p = p’ */
		if (mp_cmp(p, p_) == MP_EQ)
		{
			goto exit_label;
		}

		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(
		p_, q_, seed_i, SHA1_seed_i, seed_m_,
		SHA1_seed_m_, SHA1,
		_2_power_160i, R, NULL);

	return result;
} /* End of LLF_DH_CheckDomainParams_pqs */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckDomainParams_pqg
*
* Inputs:
* @param[out] p                  - The prime modulus P. Must be of structure P = j*Q + 1, 
*                                  where Q is prime and j is an integer.
* @param[in]  modPSizeBytes      - The modulus (prime) size in bytes. Size in bits must be 
*                                  equal 256*n, where n >= 4.
* @param[in]  q                  - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of generator order in bytes. Size in bytes must be >= 20.
* @param[in]  g                  - The pointer to the generator of multiplicative subgroup in GF(P).
* @param[in]  generatorSizeBytes - The size of generator in bytes (must be set if generator will be checked). 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function checks the obtained DH domain parameters according X9.42-2001.
*
*        There may be 3 case of checking:
*        2. Checking of generator G only in assuming that primes parameters P, Q are valid. In ths case 
*           the user must to pass the P,Q,G pointers and sizes. The seed S pointer and size must be both
*           set to NULL, otherwise the function returns an error.
*
*        If any of checked domain parameters is not compliant to X9.42-2001 standard, the function returns
*        an error according to errors definitions in CE2_DH_error.h file.  
*
*     Note:  Input vectors are in big endianness.
*
* \b
* Algorithm:
*  -# Perform DH domain parameters validation according to
*     ANSI X9.42-2001 [7.1 (2), Annex B.1.2].
***************************************************************/
CE2Error_t LLF_DH_CheckDomainParams_pqg( 
	mp_int						*p,						/* [in] */
	DxUint32_t					modPsizeBytes,			/* [in] */
	mp_int						*q,						/* [in] */
	DxUint32_t					orderQsizeBytes,		/* [in] */
	mp_int						*g,						/* [in] */
	DxUint32_t					generatorSizeBytes)		/* [in] */
{
	/*
	m = orderQsizeBytes * 8;
	L = modPsizeBytes * 8;
	*/
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p_1;

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p_1, NULL);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	2. Verify whether g is a generator of order q by checking that 2 <= g <= (p-2), and that g^q =
	1 mod p. If yes, go to step 3. Otherwise, output “Invalid”.
	*/

	/* checking that 1 < g < (p-1) */

	/* checking that 1 < g */
	if (mp_cmp_d(g, 1) != MP_GT)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* p_1 = p - 1 */
	error_code = mp_sub_d(p, 1, p_1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* checking that g < (p-1) */
	if (mp_cmp(g, p_1) != MP_LT)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* checking that g^q = 1 mod p.  */
	error_code = mp_exptmod(g, q, p, p_1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (mp_cmp_d(p_1, 1) != MP_EQ)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(p_1, NULL);

	return result;
} /* End of LLF_DH_CheckDomainParams_pqg */

/************************ Public Functions ********************/

/**
****************************************************************
* Function Name: 
*  LLF_DH_CreateDomainParams
*
* Inputs:
* @param[in]  modPSizeBits       - The  modulus (prime) P size in bits equal 256*n, where n >= 4. 
* @param[in]  orderQSizeBits     - The size of order of generator in bits. Must be m >= 160 and
*                                  multiple of 32 bits. According to ANSI X9.30-1: m = 160.
* @param[in]  seedSizeBits       - The  seed size in bits. Requirements:  seedSizeBytes >= 20,
*                                  seedSizeBytes <= modPSizeBytes (the last requiered by implementation).
* @param[out] modP_ptr           - The prime modulus P of structure P = J*Q + 1, where Q is prime
*                                  and j is an integer. Size of the buffer for output generated value must 
*                                  be not less, than modulus size. 
* @param[out] orderQ_ptr         - The pointer to the order Q of generator. Size of the buffer for output 
*                                  generated value must be not less, than order size. 
* @param[out] generatorG_ptr     - The pointer to the generator of multiplicative subgroup in GF(P).
*                                  Size of the buffer for output generated value must be not less, 
*                                  than modulus size. If the pointer == NULL, the function not puts this 
*                                  parametr out (in this case generGsizeBytes_ptr must be set to NULL also, 
*                                  otherwise the function returns an error). Size of the buffer must be not less,
*                                  than modulus size. 
* @param[in/out] generGsizeBytes_ptr- The pointer to the word-buffer, containing the generator size value (in bytes). 
*                                  If output of generator is needed, the user must the set size value equalled to size 
*                                  of allocated buffer, and the function returns the actual size of generator in bytes. 
* @param[out] factorJ_ptr        - The pointer to buffer for integer factor J. If the pointer == NULL, the function 
*                                  not puts this parametr out  (in this case JsizeBytes_ptr must be set to NULL also, 
*                                  otherwise the function returns an error). Size of the buffer must be not less,
*                                  than ( modPSizesBytes - orderQSizeBytes + 1 ). 
* @param[in/out] JsizeBytes_ptr  - The pointer to size of integer factor J. If the pointer == NULL, 
*                                  the function not puts this parametr out. If output of the factor J is needed, the
*                                  user must set the J size value equal to the size of allocated buffer, and the 
*                                  function returns the actual size of J in bytes. 
* @param[in/out] seedS_ptr       - The random seed used for generation of primes. If the pointer == NULL,  
*                                  the function not puts this parametr out. Size of the buffer for output 
*                                  generated value must be not less, than passed seed size. 
* @param[in] generateSeed        - The flag defining whether the seed generated randomly  by the function
*                                  (generateSeed = 1) or it is passed by the input (generateSeed = 0).                                 
* @param[out] pgenCounter_ptr    - The pointer to counter of tries to generate the primes. If the pointer == NULL, 
*                                  the function not puts this parametr out.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  The function generates a DH (DLP) domain parameters in GF(P) (see X9.42-2001)
*
*     Note:  1. Input and Output vectors are in big endianness (high most byte is left most).
*            2. For reliability of checking of input parameters, in case that the user don't wont output of
*               some parameters (generator or factorJ), he must set both - a pointer to appropriate buffer and a 
*               pointer to its size equalled to NULL for these parameters, otherwise the function returns an error.
*            2. In case of any error the function may clean the output buffers. 
*
* \b
* Algorithm:
*  -# Perform DH domain parameters creation according to
*     ANSI X9.42-2001 [7.1, Annex B.1.2].
***************************************************************/
CE2Error_t LLF_DH_CreateDomainParams(
                          DxUint32_t          modPsizeBits,             /*in */
                          DxUint32_t          orderQsizeBits,           /*in */
                          DxUint32_t          seedSizeBits,             /*in */
                          DxUint8_t          *modP_ptr,                 /*out*/  
                          DxUint8_t          *orderQ_ptr,               /*out*/
                          DxUint8_t          *generatorG_ptr,           /*out*/
						  DxUint32_t         *generGsizeBytes_ptr,      /*in/out*/
                          DxUint8_t          *factorJ_ptr,              /*out*/
                          DxUint32_t         *JsizeBytes_ptr,           /*in/out*/ 
                          DxUint8_t          *seedS_ptr,                /*in/out*/
                          DxInt8_t            generateSeed,             /*in*/ 
                          DxUint32_t         *pgenCounter_ptr)          /*out*/
{
	/*
	m = orderQsizeBits;
	L = modPsizeBits;
	*/
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p,
				*q,
				*j,
				*g,
				*seed,
				*seed_i, *SHA1_seed_i,
				*seed_m_, *SHA1_seed_m_,
				*SHA1,
				*_2_power_160i,
				*R;
	int			length;
	int			prime_result;
	int			hash_idx = 0;
	int			prng_idx = 0;
	prng_state	yarrow_prng;
	DxUint32_t	buff_seed[CE2_DH_MAX_MOD_BUFFER_SIZE_IN_WORDS];
	DxUint32_t	seedSizeBytes;
	DxUint8_t	seedMSBPosition;
	DxUint8_t	seedMSB;
	/*
	1. Set m' = [m/160].
	2. Set L' = [L/160].
	3. Set N = [L/1024].
	*/
	DxUint32_t m_ = ((orderQsizeBits) / 160) + (((orderQsizeBits) % 160) ? (1) : (0));
	DxUint32_t L_ = ((modPsizeBits) / 160) + (((modPsizeBits) % 160) ? (1) : (0));
	DxUint32_t N = ((modPsizeBits) / 1024) + (((modPsizeBits) % 1024) ? (1) : (0));

	/* register prng */
	if (register_prng(&yarrow_desc) == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Register SHA1 hash */
	if (register_hash(&sha1_desc) == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	hash_idx = find_hash("sha1");
	prng_idx = find_prng("yarrow");

	error_code = rng_make_prng(128, prng_idx, &yarrow_prng, 0);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (hash_idx == -1 || prng_idx == -1)
	{
		error_code = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Initialize LibTomCrypt primitives */
	error_code =
		ltc_init_multi(
			&p, &q, &j, &g, &seed, &seed_i, &SHA1_seed_i,
			&seed_m_, &SHA1_seed_m_, &SHA1,
			&_2_power_160i, &R, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	seedSizeBytes = (seedSizeBits >> 3) + ((seedSizeBits & 0x07) ? (1) : (0));

	/*
	4. Select a seed such that ||seed|| >= m.
	*/
	if (!generateSeed)
	{
		error_code = mp_read_unsigned_bin(seed, seedS_ptr, seedSizeBytes);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}
	else
	{
		seedMSBPosition = (DxUint8_t)((seedSizeBits - 1) & 0x07);
		seedMSB			= 1 << seedMSBPosition;
		seedMSBPosition = (seedMSB - 1) | (seedMSB);

step_4:
		if (prng_descriptor[prng_idx].read((unsigned char *)buff_seed, seedSizeBytes, &yarrow_prng) != (unsigned long)seedSizeBytes)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* set MS bit */
		*((unsigned char *)buff_seed) = (*((unsigned char *)buff_seed) | seedMSB) & seedMSBPosition;

		error_code = mp_read_unsigned_bin(seed, (unsigned char *)buff_seed, seedSizeBytes);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/* Calculate Q parameter */
	error_code =
		LLF_DH_CreateDomainParams_Q(
			orderQsizeBits, q, seed, &prime_result);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (prime_result != MP_YES)
	{
		if (!generateSeed)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}
		goto step_4;
	}

	/* Calculate P parameter */
	error_code =
		LLF_DH_CreateDomainParams_P(
			modPsizeBits,
			orderQsizeBits,
			p,
			q,
			g,
			j,
			seed,
			pgenCounter_ptr,
			0xffffffff);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}
	else
	{
		/* p is probably a prime, output p, q, seed, pgenCounter. */

		/* Calculate extended parameters: j factor and generator */
		if (factorJ_ptr != NULL)
		{
			/* Calculate j factor */
			error_code = LLF_DH_KG_CalculateJ(p, q, j);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}

			/* Select generator */
			error_code = LLF_DH_KG_SelectGenerator(p, q, j, g);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}
		else if (generatorG_ptr != NULL)
		{
			error_code = LLF_DH_KG_SelectGenerator(p, q, NULL, g);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		/* write p to buffer */
		error_code = mp_to_unsigned_bin(p, (unsigned char *)modP_ptr);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* write q to buffer */
		error_code = mp_to_unsigned_bin(q, (unsigned char *)orderQ_ptr);
		if (error_code != CRYPT_OK)
		{
			result = CE2_LLF_DH_MODULE_ERROR_BASE;
			goto exit_label;
		}

		if (generatorG_ptr != NULL)
		{
			*generGsizeBytes_ptr = mp_unsigned_bin_size(g);

			/* write g to buffer */
			error_code = mp_to_unsigned_bin(g, (unsigned char *)generatorG_ptr);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		/* write seed to buffer if needed */
		if (generateSeed)
		{
			error_code = mp_to_unsigned_bin(seed, (unsigned char *)seedS_ptr);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		if (factorJ_ptr != NULL)
		{
			length = mp_unsigned_bin_size(j);

			if ((int)*JsizeBytes_ptr < length)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}

			*JsizeBytes_ptr = (DxUint32_t)length;

			/* write j to buffer */
			error_code = mp_to_unsigned_bin(j, (unsigned char *)factorJ_ptr);
			if (error_code != CRYPT_OK)
			{
				result = CE2_LLF_DH_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(
		p, q, j, g, seed, seed_i, SHA1_seed_i, seed_m_,
		SHA1_seed_m_, SHA1,
		_2_power_160i, R, NULL);

	return result;
} /* End of LLF_DH_CreateDomainParams */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckDomainParams_PQS
*
* Inputs:
* @param[out] modP_ptr           - The prime modulus P. Must be of structure P = j*Q + 1, 
*                                  where Q is prime and j is an integer.
* @param[in]  modPSizeBytes      - The modulus (prime) size in bytes. Size in bits must be 
*                                  equal 256*n, where n >= 4.
* @param[in]  orderQ_ptr         - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of generator order in bytes. Size in bytes must be >= 20.
* @param[in]  seedS_ptr          - The random seed used for generation of primes (must be set if 
*                                  primes will be checked).
* @param[in]  seedSizeBytes      - The pointer to seed size in bytes (if seed is used, the size 
*                                  must be >= 20 bytes).
* @param[in]  pgenCounter        - The counter of tries to generate the primes (must be set if primes 
*                                  will be checked).
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function checks the obtained DH domain parameters according X9.42-2001.
*
*        There may be 3 case of checking:
*        1. Checking of primes only ( modulus P and order Q according to passed seed S and pgenCounter).
*           In this case all pointers and sizes of said parameters must be passed (not NULL), but generator 
*           G pointer and it size must be both set to NULL.
*
*        If any of checked domain parameters is not compliant to X9.42-2001 standard, the function returns
*        an error according to errors definitions in CE2_DH_error.h file.  
*
*     Note:  Input vectors are in big endianness.
*
* \b
* Algorithm:
*  -# Validates domain params p, q, seed by using
*     LLF_DH_CheckDomainParams_pqs;
***************************************************************/
CE2Error_t LLF_DH_CheckDomainParams_PQS( 
	DxUint8_t					*modP_ptr,				/* [in] */
	DxUint32_t					modPsizeBytes,			/* [in] */
	DxUint8_t					*orderQ_ptr,			/* [in] */
	DxUint32_t					orderQsizeBytes,		/* [in] */
	DxUint8_t					*seedS_ptr,				/* [in] */
	DxUint32_t					seedSizeBytes,			/* [in] */
	DxUint32_t					pgenCounter)			/* [in] */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p, *q, *seed;

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p, &q, &seed, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read p, q, seed and validate them */

	/* read p */
	error_code = mp_read_unsigned_bin(p, (const unsigned char *)modP_ptr, modPsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read q */
	error_code = mp_read_unsigned_bin(q, (const unsigned char *)orderQ_ptr, orderQsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read seed */
	error_code = mp_read_unsigned_bin(seed, (const unsigned char *)seedS_ptr, seedSizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* validate p, q, seed */
	error_code =
		LLF_DH_CheckDomainParams_pqs(
			p, modPsizeBytes,
			q, orderQsizeBytes,
			seed,
			pgenCounter);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(p, q, seed, NULL);

	return result;
} /* End of LLF_DH_CheckDomainParams_PQS */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckDomainParams_PQG
*
* Inputs:
* @param[out] modP_ptr           - The prime modulus P. Must be of structure P = j*Q + 1, 
*                                  where Q is prime and j is an integer.
* @param[in]  modPSizeBytes      - The modulus (prime) size in bytes. Size in bits must be 
*                                  equal 256*n, where n >= 4.
* @param[in]  orderQ_ptr         - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of generator order in bytes. Size in bytes must be >= 20.
* @param[in]  generatorG_ptr     - The pointer to the generator of multiplicative subgroup in GF(P).
* @param[in]  generatorSizeBytes - The size of generator in bytes (must be set if generator will be checked). 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*   The function checks the obtained DH domain parameters according X9.42-2001.
*
*        There may be 3 case of checking:
*        2. Checking of generator G only in assuming that primes parameters P, Q are valid. In ths case 
*           the user must to pass the P,Q,G pointers and sizes. The seed S pointer and size must be both
*           set to NULL, otherwise the function returns an error.
*
*        If any of checked domain parameters is not compliant to X9.42-2001 standard, the function returns
*        an error according to errors definitions in CE2_DH_error.h file.  
*
*     Note:  Input vectors are in big endianness.
*
* \b
* Algorithm:
*  -# Validates domain params p, q, g by using
*     LLF_DH_CheckDomainParams_pqg;
***************************************************************/
CE2Error_t LLF_DH_CheckDomainParams_PQG( 
	DxUint8_t					*modP_ptr,				/* [in] */
	DxUint32_t					modPsizeBytes,			/* [in] */
	DxUint8_t					*orderQ_ptr,			/* [in] */
	DxUint32_t					orderQsizeBytes,		/* [in] */
	DxUint8_t					*generatorG_ptr,		/* [in] */
	DxUint32_t					generatorSizeBytes)		/* [in] */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p, *q, *g;

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p, &q, &g, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read p, q, g and validate them */

	/* read p */
	error_code = mp_read_unsigned_bin(p, (const unsigned char *)modP_ptr, modPsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read q */
	error_code = mp_read_unsigned_bin(q, (const unsigned char *)orderQ_ptr, orderQsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read g */
	error_code = mp_read_unsigned_bin(g, (const unsigned char *)generatorG_ptr, generatorSizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* validate g */
	error_code =
		LLF_DH_CheckDomainParams_pqg(
			p, modPsizeBytes,
			q, orderQsizeBytes,
			g, generatorSizeBytes);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(p, q, g, NULL);

	return result;
} /* End of LLF_DH_CheckDomainParams_PQG */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckDomainParams
*
* Inputs:
* @param[out] modP_ptr           - The prime modulus P. Must be of structure P = j*Q + 1, 
*                                  where Q is prime and j is an integer.
* @param[in]  modPSizeBytes      - The modulus (prime) size in bytes. Size in bits must be 
*                                  equal 256*n, where n >= 4.
* @param[in]  orderQ_ptr         - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of generator order in bytes. Size in bytes must be >= 20.
* @param[in]  generatorG_ptr     - The pointer to the generator of multiplicative subgroup in GF(P).
* @param[in]  generatorSizeBytes - The size of generator in bytes (must be set if generator will be checked). 
* @param[in]  seedS_ptr          - The random seed used for generation of primes (must be set if 
*                                  primes will be checked).
* @param[in]  seedSizeBits       - The pointer to seed size in bytes (if seed is used, the size 
*                                  must be >= 20 bytes).
* @param[in]  pgenCounter        - The counter of tries to generate the primes (must be set if primes 
*                                  will be checked).
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_DH_CHECK_DOMAIN_PRIMES_NOT_VALID_ERROR
*   - CE2_DH_CHECK_GENERATOR_NOT_VALID_ERROR
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  The function checks the obtained DH domain parameters according X9.42-2001.
*
*        There may be 3 case of checking:
*        1. Checking of primes only ( modulus P and order Q according to passed seed S and pgenCounter).
*           In this case all pointers and sizes of said parameters must be passed (not NULL), but generator 
*           G pointer and it size must be both set to NULL.
*        2. Checking of generator G only in assuming that primes parameters P, Q are valid. In ths case 
*           the user must to pass the P,Q,G pointers and sizes. The seed S pointer and size must be both
*           set to NULL, otherwise the function returns an error.
*        3. Checking all domain parameters. In this case all input parameters must be passed to the function.
*
*        If any of checked domain parameters is not compliant to X9.42-2001 standard, the function returns
*        an error according to errors definitions in CE2_DH_error.h file.  
*
*     Note:  Input vectors are in big endianness.
*
* \b
* Algorithm:
*  -# Perform DH domain parameters validation according to
*     ANSI X9.42-2001 [7.2 (1, 2), Annex B.1.3].
***************************************************************/
CE2Error_t LLF_DH_CheckDomainParams( 
                          DxUint8_t               *modP_ptr,           /*in */  
                          DxUint32_t               modPsizeBytes,      /*in */
                          DxUint8_t               *orderQ_ptr,         /*in */
                          DxUint32_t               orderQsizeBytes,    /*in */
                          DxUint8_t               *generatorG_ptr,     /*in */
                          DxUint32_t               generatorSizeBytes, /*in */
                          DxUint8_t               *seedS_ptr,          /*in */
                          DxUint32_t               seedSizeBits,       /*in */
                          DxUint32_t               pgenCounter)        /*in */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p, *q, *seed, *g;

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p, &q, &seed, &g, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read p, q, seed, g and validate them */

	/* read p */
	error_code = mp_read_unsigned_bin(p, (const unsigned char *)modP_ptr, modPsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read q */
	error_code = mp_read_unsigned_bin(q, (const unsigned char *)orderQ_ptr, orderQsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read seed */
	error_code = mp_read_unsigned_bin(seed, (const unsigned char *)seedS_ptr, (seedSizeBits >> 3) + ((seedSizeBits & 0x07) ? (1) : (0)));
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* validate p, q, seed */
	error_code =
		LLF_DH_CheckDomainParams_pqs(
			p, modPsizeBytes,
			q, orderQsizeBytes,
			seed,
			pgenCounter);

	if (error_code != CRYPT_OK)
	{
		result = CE2_DH_CHECK_DOMAIN_PRIMES_NOT_VALID_ERROR;
		goto exit_label;
	}

	/* read g */
	error_code = mp_read_unsigned_bin(g, (const unsigned char *)generatorG_ptr, generatorSizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* validate g */
	error_code =
		LLF_DH_CheckDomainParams_pqg(
			p, modPsizeBytes,
			q, orderQsizeBytes,
			g, generatorSizeBytes);

	if (error_code != CRYPT_OK)
	{
		result = CE2_DH_CHECK_GENERATOR_NOT_VALID_ERROR;
		goto exit_label;
	}

exit_label:
	ltc_deinit_multi(p, q, seed, g, NULL);

	return result;
} /* End of LLF_DH_CheckDomainParams */

/**
****************************************************************
* Function Name: 
*  LLF_DH_CheckPubKey
*
* Inputs:
* @param[out] modP_ptr           - The modulus (prime) P.
* @param[in]  modPSizeBytes      - The modulus size in bytes.
* @param[in]  orderQ_ptr         - The pointer to prime order Q of generator,
* @param[in]  orderQSizeBytes    - The size of order of generator in bytes.
* @param[in]  pubKey_ptr         - The pointer to public key to be validated . 
* @param[in]  pubKeySizeBytes    - The public key size in bytes. 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*   - CE2_DH_INVALID_PUBLIC_KEY_ERROR
*   - CE2_LLF_DH_MODULE_ERROR_BASE
*
* \brief \b
* Description:
*  The function checks the obtained DH public key according to its domain 
*        parameters (see X9.42-2001)
*
*              Assuming: The DH domain parameters are valid.
*
* \b
* Algorithm:
*  -# Perform DH public key validation according to
*     ANSI X9.42-2001 [7.4].
***************************************************************/
CE2Error_t LLF_DH_CheckPubKey( 
                          DxUint8_t              *modP_ptr,             /*in */  
                          DxUint32_t              modPsizeBytes,        /*in */
                          DxUint8_t              *orderQ_ptr,           /*in */
                          DxUint32_t              orderQsizeBytes,      /*in */
                          DxUint8_t              *pubKey_ptr,           /*in */
                          DxUint32_t              pubKeySizeBytes)      /*in */
{
	CE2Error_t	result = CE2_OK,
				error_code;
	void		*p, *p_1, *q, *y;

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Initialize LibTomCrypt primitives */
	error_code = ltc_init_multi(&p, &p_1, &q, &y, NULL);

	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read p, q, seed, g and validate them */

	/* read p */
	error_code = mp_read_unsigned_bin(p, (const unsigned char *)modP_ptr, modPsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read q */
	error_code = mp_read_unsigned_bin(q, (const unsigned char *)orderQ_ptr, orderQsizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* read y */
	error_code = mp_read_unsigned_bin(y, (const unsigned char *)pubKey_ptr, pubKeySizeBytes);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	1. Verify that 2 <= y <= p-2.
	*/

	/* p_1 = p - 1 */
	error_code = mp_sub_d(p, 1, p_1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	Verify that 2 <= y <= p-2
	Verify that 1 < y < p-1
	*/
	if (mp_cmp_d(y, 1) != MP_GT ||
		mp_cmp(y, p_1) != MP_LT)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/*
	2. Verify that y^q = 1 mod p.
	*/

	/* y = y^q */
	error_code = mp_exptmod(y, q, p, p_1);
	if (error_code != CRYPT_OK)
	{
		result = CE2_LLF_DH_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Validate public key */
	if (mp_cmp_d(p_1, 1) != MP_EQ)
	{
		result = CE2_DH_INVALID_PUBLIC_KEY_ERROR;
		goto exit_label;
	}

	/*
	3. If either of the above checks fails, then output “invalid”.
	Otherwise, output “valid”.
	*/

exit_label:
	ltc_deinit_multi(p, p_1, q, y, NULL);

	return result;
} /* End of LLF_DH_CheckPubKey */