/*
* Creation date : Fri May 29 9:00:00 2007
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of RND functions.
*
* \version LLF_RND.c#1:csrc:1
* \author Yermalayeu Ihar
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

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

#include "LLF_RND.h"
#include "CE2_HASH.h"
#include <memory.h>
#include "tomcrypt.h"

#ifdef RND_FIPS_PUB_186_2

/************************ Defines *****************************/

#define LLF_RND_M1_SIZE_IN_BITS 512
#define LLF_RND_M1_SIZE_IN_BYTES 64

#define LLF_RND_XKEY_SIZE_IN_WORDS 5

#define LLF_RND_F0(B,C,D)  (D ^ (B & (C ^ D)))
#define LLF_RND_F1(B,C,D)  (B ^ C ^ D)
#define LLF_RND_F2(B,C,D)  ((B & C) | (D & (B | C)))
#define LLF_RND_F3(B,C,D)  (B ^ C ^ D)

#define LLF_RND_FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + LLF_RND_F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
#define LLF_RND_FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + LLF_RND_F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
#define LLF_RND_FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + LLF_RND_F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
#define LLF_RND_FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + LLF_RND_F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);

/************************ Enums *******************************/
/************************ Typedefs ****************************/

typedef DxUint32_t LLF_RND_G_OutBuff_t[CE2_HASH_SHA1_DIGEST_SIZE_IN_WORDS];

/************************ Global Data *************************/

const DxUint32_t LLF_RND_t[CE2_HASH_SHA1_DIGEST_SIZE_IN_WORDS] = {
  0x67452301UL, 0xefcdab89UL, 0x98badcfeUL, 0x10325476UL, 0xc3d2e1f0UL
};

DxUint32_t LLF_RND_XKEY[LLF_RND_XKEY_SIZE_IN_WORDS];

/************************ Private function prototype **********/
/************************ Private Functions *******************/

/**
****************************************************************
* Function Name: 
*  LLF_RND_G
*
*  @param[in] C - The pointer to the input C-buffer.
*  @param[in] SizeOfC - The size of input C-buffer.
*  @param[out] H - The output buffer.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  The LLF_RND_G function Constructing the function G from the SHA-1, 
*  as defined in FIPS-PUB 186-2 standard, Appendix 3.3
*
*  \b 
* Algorithm:
*  -# 
***************************************************************/
CE2Error_t LLF_RND_G(DxUint8_t *C, DxUint16_t  SizeOfC, 
                     LLF_RND_G_OutBuff_t H)
{
  DxUint8_t M1[LLF_RND_M1_SIZE_IN_BYTES];
  DxUint32_t a, b, c, d, e, W[80], i;

  /* Set H = t ; t is LLF_RND_t */
  memcpy(H, LLF_RND_t, sizeof(LLF_RND_G_OutBuff_t));

  /* Set M1 = c || 0^(512-b) ; b = SizeOfC*8 */
  memset(M1, 0, LLF_RND_M1_SIZE_IN_BYTES);
  memcpy(M1, C, SizeOfC);

  /* copy the state into 512-bits into W[0..15] */
  for (i = 0; i < 16; i++) {
    LOAD32H(W[i], M1 + (4*i));
  }

  /* copy H */
  a = H[0];
  b = H[1];
  c = H[2];
  d = H[3];
  e = H[4];

  /* expand it */
  for (i = 16; i < 80; i++) {
    W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); 
  }

  /* compress */
  /* round one */
  for (i = 0; i < 20; ) {
    LLF_RND_FF0(a,b,c,d,e,i++);
    LLF_RND_FF0(e,a,b,c,d,i++);
    LLF_RND_FF0(d,e,a,b,c,i++);
    LLF_RND_FF0(c,d,e,a,b,i++);
    LLF_RND_FF0(b,c,d,e,a,i++);
  }

  /* round two */
  for (; i < 40; )  { 
    LLF_RND_FF1(a,b,c,d,e,i++);
    LLF_RND_FF1(e,a,b,c,d,i++);
    LLF_RND_FF1(d,e,a,b,c,i++);
    LLF_RND_FF1(c,d,e,a,b,i++);
    LLF_RND_FF1(b,c,d,e,a,i++);
  }

  /* round three */
  for (; i < 60; )  { 
    LLF_RND_FF2(a,b,c,d,e,i++);
    LLF_RND_FF2(e,a,b,c,d,i++);
    LLF_RND_FF2(d,e,a,b,c,i++);
    LLF_RND_FF2(c,d,e,a,b,i++);
    LLF_RND_FF2(b,c,d,e,a,i++);
  }

  /* round four */
  for (; i < 80; )  { 
    LLF_RND_FF3(a,b,c,d,e,i++);
    LLF_RND_FF3(e,a,b,c,d,i++);
    LLF_RND_FF3(d,e,a,b,c,i++);
    LLF_RND_FF3(c,d,e,a,b,i++);
    LLF_RND_FF3(b,c,d,e,a,i++);
  }

  /* store */
  H[0] = H[0] + a;
  H[1] = H[1] + b;
  H[2] = H[2] + c;
  H[3] = H[3] + d;
  H[4] = H[4] + e;

  return CE2_OK;
}


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

/**
****************************************************************
* Function Name: 
*  LLF_RND_GenerateVector
*
*  @param[in] RndSize - The size of random vector that is required.
*  @param[in/out] Output_ptr - The output vector.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  The LLF_RND_GenerateVector function generates a random vector using
*  the FIPS-PUB 186-2 standard, Appendix 3.
*  The random function is based on the HASH SHA1 and works as follows:
*  1. Loads the secret key stored internally into a global variable.
*  2. Executes the following steps according to the number of hash result 
*     blocks required (RndSize/20).
*    a. Executes a SHA1 hash on the current key
*       (if the key is less than 512 bytes, adds zeros to it).
*    b. Stores the result to the data 
*    c. The next key is 1 ^ key ^ result. This is the new key.
*
*  \b 
* Algorithm:
*  -# 
***************************************************************/
CE2Error_t LLF_RND_GenerateVector(DxUint16_t  RndSize,
                                  DxUint8_t  *Output_ptr)
{
  return CE2_OK;
}

/**
****************************************************************
* Function Name: 
*  LLF_RND_ResetSeed
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  The LLF_RND_ResetSeed resets the SEED generated by the low level
*  (the hardware or operating system service on software).
*
*  \b 
* Algorithm:
*  -#  
***************************************************************/
CE2Error_t LLF_RND_ResetSeed(void)
{
  return CE2_OK;
}

/**
****************************************************************
* Function Name: 
*  LLF_RND_GenerateVectorInRange
*
*  @RndSize[in] - The size of random vectore that is required.
*  @MaxVect_ptr[in]  - The pointer to vector defines high limit of random vector.
*  @RndVect_ptr[in/out] The output vector.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  This function generates a random vector RndVect in range:
*  1 < RndVect < MaxVect,   using the FIPS-PUB 186-2 standard appendex 3 :
*  The function performs the following:
*    1. Calls the CE2_RND_GenerateVector() function for generating random vector 
*       RndVect of size in bytes.
*    2. Zeroes extra bits of RndVect.
*    3. Compares RndVect with 1 and MaxVect. If condition  1 < RandVect < MaxVect
*       is not satisfied goues to step 1.
*
*  \b 
* Algorithm:
*  -#  
***************************************************************/
CE2Error_t LLF_RND_GenerateVectorInRange(DxUint32_t RndSizeInBits, 
                                         DxUint8_t *MaxVect_ptr, 
                                         DxUint8_t *RndVect_ptr)
{
  return CE2_OK;
}

#elif RND_FIPS_SP_800_90

#include "LLF_AES.h"

/************************ Defines *****************************/

#define LLF_RND_INITIAL_3H ((DxUint8_t *)LLF_RND_AdditionalInput)
#define LLF_RND_INITIAL_3I ((DxUint8_t *)&LLF_RND_AdditionalInput[LLF_RND_DEFAULT_DATA_SIZE])
#define LLF_RND_RESEEDING_3 ((DxUint8_t *)LLF_RND_AdditionalInput)

/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/

#ifdef RND_FIPS_SP_800_90_TEST

DxUint32_t LLF_RND_GlobalInstantiationEntropy[4]= {0x9c0ee427,0x8fa1ef42,0xcb6fe62a,0xd4f2dba9};
DxUint32_t LLF_RND_GlobalInstantiationNonce[2]	= {0xcd4f6233,0x605fb2f5};
DxUint32_t LLF_RND_GlobalReseedEntropy[4]		= {0x879fd22f,0xadfb6db7,0x0291f95e,0x98686e0e};

#endif

/*
CCSystemSpec_RNG11

Internal State
The working state of the random bit generator algorithm
(CTR_DRBG, described in section 10.2.1 of [SP800-90]) consists
of the following registers:
	V register (128 bits)1.
	K register (128 bits).
	Request size counter (12 bits).
	Reseed counter (48 bits).
	Additional-input register (256 bits).
As a performance optimization, the V value kept by the engine
will be pre-incremented (i.e., it will be 1 more than the value
expected in the standard), as all uses of V in the standard
algorithms begin with incrementing it. Since V is a 128-bit
register, incrementing it can be expensive, and is best
parallelized with other operations (such as encryption).

RNG_SW_SDDv0.3
Internal State
The working state of the random bit generator consists of the
following global data:
	V vector - length of 128 bits.
	K vector - length of 128 bits.
	Additional_input vector - length of 256 bits.
	Additional_input flag - two bytes.
*/
DxUint8_t	LLF_RND_V[LLF_RND_DEFAULT_DATA_SIZE]			= { 0 };
DxUint8_t	LLF_RND_K[LLF_RND_DEFAULT_DATA_SIZE]			= { 0 };
//DxUint64_t	LLF_RND_RESEED_COUNTER							= 0;
DxUint8_t	LLF_RND_AdditionalInput[LLF_RND_ADDITIONAL_DATA_SIZE]= {0};
DxUint16_t	LLF_RND_AdditionalInputSize						= 0;
DxUint16_t	LLF_RND_AdditionalInputFlag						= 0;
DxUint8_t	LLF_RND_InitialSkippedFlag						= 0;
DxUint8_t	LLF_RND_Data[2][LLF_RND_DEFAULT_DATA_SIZE]		= { { 0 }, { 0 } };
DxUint8_t	LLF_RND_RequestSizeCounter						= 0;

/* LLF_RND_Instantiation data: blocks, values and keys */
DxUint8_t	LLF_RND_Block2[2][LLF_RND_DEFAULT_DATA_SIZE] =
{
	{
		0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20
	},
	{
		0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20
	},
};

DxUint8_t	LLF_RND_Value2[2][LLF_RND_DEFAULT_DATA_SIZE] =
{
	{
		0xC6, 0xA1, 0x3B, 0x37, 0x87, 0x8F, 0x5B, 0x82,
		0x6F, 0x4F, 0x81, 0x62, 0xA1, 0xC8, 0xD8, 0x79
	},
	{
		0x95, 0x03, 0xE3, 0xA2, 0x24, 0x5A, 0x2B, 0xE4,
		0x3C, 0x98, 0x74, 0xED, 0xFE, 0x1B, 0xED, 0x9E
	}
};

DxUint8_t	LLF_RND_Value3[2][LLF_RND_DEFAULT_DATA_SIZE] =
{
	{
		0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
		0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a
	},
	{
		0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
		0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78
	}
};

DxUint8_t	LLF_RND_Key2[] =
{
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};

DxUint8_t	LLF_RND_Block2c[] =
{
	0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* LLF_RND_Reseeding data: blocks, values and keys */
DxUint8_t	LLF_RND_Block3[] =
{
	0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20
};

DxUint8_t	LLF_RND_Block2a[3][LLF_RND_DEFAULT_DATA_SIZE] =
{
	{
		0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20
	},
	{
		0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20
	},
	{
		0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20
	}
};

/************************ Private function prototype **********/
/************************ Private Functions *******************/

/**
****************************************************************
* Function Name: 
*  LLF_RND_EntropyCollect
*
* Input:
*  @param[in/out] aEntropy_ptr - Entropy output buffer;
*  @param[in]     aEntropySize - Entropy output buffer size.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*
*
*  \b 
* Algorithm:
*  -# ...
***************************************************************/
CE2Error_t LLF_RND_EntropyCollect(DxUint8_t	 *aEntropy_ptr,	/* in/out */
								  DxUint16_t aEntropySize)	/* in */
{
	DxUint16_t i;

	for (i = 0; i < aEntropySize; ++i)
		aEntropy_ptr[i] = (DxUint8_t)rand();

	return CE2_OK;
} /* End of LLF_RND_EntropyCollect */

/**
****************************************************************
* Function Name: 
*  LLF_RND_Initial
*
* Input:
*  None.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*
*
*  \b 
* Algorithm:
*  -# ...
***************************************************************/
CE2Error_t LLF_RND_Initial()
{
	DxUint8_t	*vInternal[2];
	DxUint64_t	*vData_ptr;
	DxUint64_t	*vBlock_ptr;
	DxUint8_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG v1.5

	2.3.2.4.1 Initial update of working state
	*/

	/*
	1. Test if reseed counter has overflowed (i.e., reached 248);
		if it has, abort the random generation sequence
		(clear the control field and return to an "idle" state).
	*/

	/*
		Ignored according to
		RNG_SW_SDDv0.3 [2.2 Assumptions and Constraints]
	*/

	/*
	2. Test if additional input register was written since it
		was last reset (by a previous initial update or by a
		reseeding).
		If no, skip the rest of this sequence.
	*/

	if (!LLF_RND_AdditionalInputFlag)
	{
		LLF_RND_InitialSkippedFlag = 1;
		goto exit_label;
	}

	/*
	3. Computation of the internal 256-bit additional_input:
	*/

	/*
	a. Compute the first word:
		it is 0x00000010 if additional input register contains
		up to 128 valid bits,
		or 0x00000020 if it contains more than 128 valid bits.
	*/

	vBlock_ptr =
		(DxUint64_t *)
			&LLF_RND_Block2a[
				(LLF_RND_AdditionalInputSize <= LLF_RND_DEFAULT_DATA_SIZE) ?
					(0) : (1)];

	for (i = 0; i < 2; ++i)
	{
		vData_ptr = (DxUint64_t *)LLF_RND_Data[i];

		/*
		b. XOR the block
			(word from step a) || 0x00000020 || (additional input bits [63:0])
			with the value
			0xC6A13B37878F5B826F4F8162A1C8D879;
			encrypt the result using the key
			0x000102030405060708090A0B0C0D0E0F.
		*/

		/*
		e. XOR the block
			(word from step a) || 0x00000020 || (additional input bits [63:0])
			with the value
			0x9503E3A2245A2BE43C9874EDFE1BED9E;
			encrypt using the same key as in step b.
		*/

		vData_ptr[0] =
			*((DxUint64_t *)vBlock_ptr) ^
			*((DxUint64_t *)LLF_RND_Value2[i]);

		vData_ptr[1] =
			*(((DxUint64_t *)LLF_RND_AdditionalInput)) ^
			*(((DxUint64_t *)LLF_RND_Value2[i]) + 1);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		if (!LLF_RND_AdditionalInputSize)
		{
			continue;
		}

		if (LLF_RND_AdditionalInputSize == LLF_RND_DEFAULT_DATA_SIZE)
		{
			/*
			d.
				If only 128 bits of additional input are available,
				XOR the result of step b with
				(additional input bits [127:64]) || 0x8000000000000000;
				encrypt the result using the same key.
			*/

			/*
			g.
				If only 128 bits of additional input are available,
				XOR the result of step e with
				(additional input bits [127:64]) || 0x8000000000000000;
				encrypt the result using the same key.
			*/

			vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 1);
			vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c));

			vError =
				LLF_AES(
					NULL,
					*(CE2_AES_Key_t *)LLF_RND_Key2,
					CE2_AES_Key128BitSize,
					CE2_AES_Encrypt,
					CE2_AES_ECB_mode,
					(DxUint8_t *)vData_ptr,
					LLF_RND_DEFAULT_DATA_SIZE,
					(DxUint8_t *)vData_ptr);

			if (vError != CE2_OK)
			{
				vError = CE2_ERROR_BASE;
				goto exit_label;
			}

			continue;
		}

		/*
		c. If the full 256 bits of additional input are available,
			XOR the result of step b with
			(additional input bits [191:64]);
			encrypt the result using the same key.
		*/

		/*
		f. If the full 256 bits of additional input are available,
			XOR the result of step e with
			(additional input bits [191:64]);
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 1);
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 2);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		/*
		d. If the full 256 bits of additional input are available,
			XOR the result of step c with
			(additional input bits [255:192]) || 0x8000000000000000;
			encrypt the result using the same key.
		*/

		/*
		g. If the full 256 bits of additional input are available,
			XOR the result of step f with
			(additional input bits [255:192]) || 0x8000000000000000;
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 3);
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c));

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	h. Encrypt the result of step g, using the output from step d as key.
	*/

	/*
	i. Encrypt the result of step h (again), still using the same key.
	*/

	/*
	Store results from steps h and i in the currently unused AdditionalInfo:
		first default data size is h and next is i.
	*/

	/*
	Fill internal with:
		0. result of step g;
		1. result of step h;
	*/

	vInternal[0] = LLF_RND_Data[1];
	vInternal[1] = LLF_RND_AdditionalInput;

	for (i = 0; i < 2; ++i)
	{
		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Data[0],
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vInternal[i],
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)&LLF_RND_AdditionalInput[i * LLF_RND_DEFAULT_DATA_SIZE]);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/* Unset initial skipped flag for final update usage of h and i values */
	LLF_RND_InitialSkippedFlag = 0;

	/*
	4. Encrypt the V register using the K register as key.
		Increment V (using full 128-bit arithmetic).
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_Data[1]);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/* Increment V (using full 128-bit arithmetic) */
	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	5. XOR the result of step 4 with the result of step 3h,
		and keep for future use as the next value for the K register.
	*/

	*(((DxUint64_t *)LLF_RND_Data[1]) + 0) ^=
		*(((DxUint64_t *)LLF_RND_INITIAL_3H) + 0);

	*(((DxUint64_t *)LLF_RND_Data[1]) + 1) ^=
		*(((DxUint64_t *)LLF_RND_INITIAL_3H) + 1);

	/*
	6. Encrypt the V register using the (still un-updated)
		K register as key.
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_V);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	7. XOR the result of step 6 with the result of step 3i,
		and store the result in the V register.
	*/

	*(((DxUint64_t *)LLF_RND_V) + 0) ^= *(((DxUint64_t *)LLF_RND_INITIAL_3I) + 0);
	*(((DxUint64_t *)LLF_RND_V) + 1) ^= *(((DxUint64_t *)LLF_RND_INITIAL_3I) + 1);

	/*
	8. Copy the result from step 5 to the K register.
	*/

	*(((DxUint64_t *)LLF_RND_K) + 0) = *(((DxUint64_t *)LLF_RND_Data[1]) + 0);
	*(((DxUint64_t *)LLF_RND_K) + 1) = *(((DxUint64_t *)LLF_RND_Data[1]) + 1);

	/*
	9. Increment the V register, using full 128-bit arithmetic.
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	The algorithm performs 10 encryptions, and requires one
	128-bit temporary register for the result of step 3d
	and later the result of step 5.
	(Since random bits have not been generated yet,
	the temporary values may be kept in the readout register).
	*/

	/*
	Note:
	The results from steps 3h and 3i have to be kept for use by
	the final working state update algorithm;
	instead of dedicating an extra 256-bit register for this task,
	these may be copied back into the additional-input register,
	which will become blocked for writing until the final update
	is completed.
	*/

exit_label:
	return vError;
} /* End of LLF_RND_Initial */

/**
****************************************************************
* Function Name: 
*  LLF_RND_Generation
*
* Input:
*  None.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*
*
*  \b 
* Algorithm:
*  -# ...
***************************************************************/
CE2Error_t LLF_RND_Generation(DxUint8_t *Output_ptr)
{
	DxUint8_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG11 v1.3

	2.3.2.4.2 Generation of random bits
	*/

	/*
	1. Encrypt the V register using the K register as key1; keep the
		result in an output register
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)Output_ptr);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	3. Output the result of the encryption as the next block of
		random bits.
	*/



	/*
	2. Increment V (using full 128-bit arithmetic).
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	4. Increment the request size counter;
		if the counter reaches 2^12, disable random bit generation
		until next working state update.
	*/

	++LLF_RND_RequestSizeCounter;

exit_label:
	return vError;
} /* End of LLF_RND_Generation */

/**
****************************************************************
* Function Name: 
*  LLF_RND_Final
*
* Input:
*  None.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*
*
*  \b 
* Algorithm:
*  -# ...
***************************************************************/
CE2Error_t LLF_RND_Final()
{
	DxUint8_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG v1.5

	2.3.2.4.3 Final update of working state
	*/

	/*
	1. Encrypt the V register using the K register as key1; keep the
		result in an output register (will be used in the next step).
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_Data[1]);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	2. XOR the result with the output from step 2.3.2.4.1 3h
		of the initial update process (or "0" if the process
		was skipped).
		Keep the result for future use as the next value for
		the K register.
	*/

	if (!LLF_RND_InitialSkippedFlag)
	{
		*(((DxUint64_t *)LLF_RND_Data[1]) + 0) ^=
			*(((DxUint64_t *)LLF_RND_INITIAL_3H) + 0);

		*(((DxUint64_t *)LLF_RND_Data[1]) + 1) ^=
			*(((DxUint64_t *)LLF_RND_INITIAL_3H) + 1);
	}

	/*
	3. Increment V (using full 128-bit arithmetic).
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	4. Encrypt the V register using the (existing value of)
		K register as key1; keep the result in an output register
		(will be used in the next step).
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_V);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	5. XOR the result with the output from step 2.3.2.4.1 3i
		of the initial update process (or "0" if the process
		was skipped).
		Store the result in the V register.
	*/

	if (!LLF_RND_InitialSkippedFlag)
	{
		*(((DxUint64_t *)LLF_RND_V) + 0) ^= *(((DxUint64_t *)LLF_RND_INITIAL_3I) + 0);
		*(((DxUint64_t *)LLF_RND_V) + 1) ^= *(((DxUint64_t *)LLF_RND_INITIAL_3I) + 1);
	}

	/*
	6. Copy the result from step 2 to the K register.
	*/

	*(((DxUint64_t *)LLF_RND_K) + 0) = *(((DxUint64_t *)LLF_RND_Data[1]) + 0);
	*(((DxUint64_t *)LLF_RND_K) + 1) = *(((DxUint64_t *)LLF_RND_Data[1]) + 1);

	/*
	7. Increment the V register, using full 128-bit arithmetic.
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	8. Reset the request size counter.
	*/

	LLF_RND_RequestSizeCounter = 0;

	/*
	9. Increment the reseed counter;
		if reseed counter reaches 2^48, disable random generation
		until next reseed.
	*/

	/*
	Ignored according to
	RNG_SW_SDDv0.3 [2.2 Assumptions and Constraints]
	*/

	/*
	10. Reset the additional input register.
	*/

	/* ... */

	LLF_RND_AdditionalInputFlag = 0;
	LLF_RND_AdditionalInputSize = 0;

	/*
	The process performs two encryptions, and requires one 128-bit
	temporary register for storing the output from step 2.
	*/


exit_label:
	return vError;
} /* End of LLF_RND_Final */

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

/**
****************************************************************
* Function Name: 
*  LLF_RND_Instantiation
*
* Input:
*  None
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  Initializes RND engine according to FIPS-SP 800-90:
*  - CCSystemSpec_RNG v1.5 [2.3.2.2 Instantiation];
*  - RNG_SW_SDDv0.3.
*
*  \b 
* Algorithm:
*  - 1. Collect 128 bits of entropy (from entropy_input);
*  - 2. Computing the seed_material value;
*  - 3. CTR_DRBG_Update;
*  - 4. Increment the V variable, using full 128-bit arithmetic;
*  - 5. Reset the additional input flag.
***************************************************************/
CE2Error_t LLF_RND_Instantiation(void)
{
#ifndef RND_FIPS_SP_800_90_TEST
	DxUint8_t	vEntropy[LLF_RND_DEFAULT_DATA_SIZE + LLF_RND_DEFAULT_DATA_SIZE / 2];
#endif
	DxUint64_t	*vEntropy_ptr;
	DxUint64_t	*vNonce_ptr;
	DxUint64_t	*vInternal[] = { (DxUint64_t *)LLF_RND_K, (DxUint64_t *)LLF_RND_V };
	DxUint64_t	*vData_ptr;
	DxUint64_t	*vBlock2_ptr;
	DxUint8_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG v1.5

	2.3.2.2 Instantiation
	*/

	/*
	1. Collect 128 bits of entropy (from entropy_input).
	a. If a random nonce is used (selectable by a synthesis flag),
		use the TRNG to produce 192 bits of entropy; use EHR bits [127:0]
		for the seed (entropy_input, used in steps 2b and
		2c below), and bits [191:128] for the nonce
		(used in step 2). In addition, bits [191:64] of the
		additional input register will be used in step 2d.
	*/

#ifdef RND_FIPS_SP_800_90_TEST
	vEntropy_ptr = (DxUint64_t *)LLF_RND_GlobalInstantiationEntropy;
	vNonce_ptr = (DxUint64_t *)LLF_RND_GlobalInstantiationNonce;
#else
	vEntropy_ptr = ((DxUint64_t *)vEntropy) + 1;
	vNonce_ptr = (DxUint64_t *)vEntropy;

	LLF_RND_EntropyCollect(vEntropy, sizeof(vEntropy));
#endif

	/*
	b. If an externally-supplied nonce is to be used, use the TRNG
		to produce a 128-bit random entropy_input (EHR bits [127:0]).
		Bits [63:0] of the additional input register will be used for
		the nonce (step 2 below), and bits [191:64] will
		be used as additional input in step step 2d.
	*/

	/* Ignored ... */

	/*
	2. Computing the seed_material value:
	*/

	/*
	a. Compute a value for the first word:
		it is 0x00000028 if additional input register holds at least 128 bits,
		or 0x00000018 otherwise.
	*/

	vBlock2_ptr = (DxUint64_t *)LLF_RND_Block2[(LLF_RND_AdditionalInputSize >= LLF_RND_DEFAULT_DATA_SIZE) ? (0) : (1)];

	for (i = 0; i < 2; ++i)
	{
		vData_ptr = (DxUint64_t *)LLF_RND_Data[i];

		/*
		b. XOR the block
			(word from step a) || 0x00000020 || (bits [127:64] of EHR)
			with the value
			0xC6A13B37878F5B826F4F8162A1C8D879;
			encrypt the result using the key
			0x000102030405060708090A0B0C0D0E0F.
		*/

		/*
		f. XOR the block
			(word from step a) || 0x00000020 || (bits [127:64] of EHR)
			with the value
			0x9503E3A2245A2BE43C9874EDFE1BED9E;
			encrypt using the same key as in the previous steps.
		*/

		vData_ptr[0] =
			*((DxUint64_t *)vBlock2_ptr) ^
			*((DxUint64_t *)LLF_RND_Value2[i]);

		vData_ptr[1] =
			*(((DxUint64_t *)vEntropy_ptr)) ^
			*(((DxUint64_t *)LLF_RND_Value2[i]) + 1);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		/*
		c. XOR the result of step b with
			(bits [63:0] of EHR) || (64-bit nonce);
			encrypt the result using the same key.
		*/

		/*
		g. XOR the result of step f with
			(bits [63:0] of EHR) || (64-bit nonce);
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)vEntropy_ptr) + 1);
		vData_ptr[1] ^= *(((DxUint64_t *)vNonce_ptr));

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		/*
		d. If additional input register holds at least 128 bits,
			XOR the result of step c with
			(additional input register bits [127:0]);
			encrypt the result using the same key.
			If additional input register holds less than 128 bits,
			pass through the result from step c as-is.
		*/

		/*
		h. If additional input register holds at least 128 bits,
			XOR the result of step g with
			(additional input register bits [127:0]);
			encrypt the result using the same key.
			If additional input register holds less than 128 bits,
			pass through the result from step g as-is.
		*/

		if (LLF_RND_AdditionalInputSize >= LLF_RND_DEFAULT_DATA_SIZE)
		{
			vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput));
			vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 1);

			vError =
				LLF_AES(
					NULL,
					*(CE2_AES_Key_t *)LLF_RND_Key2,
					CE2_AES_Key128BitSize,
					CE2_AES_Encrypt,
					CE2_AES_ECB_mode,
					(DxUint8_t *)vData_ptr,
					LLF_RND_DEFAULT_DATA_SIZE,
					(DxUint8_t *)vData_ptr);

			if (vError != CE2_OK)
			{
				vError = CE2_ERROR_BASE;
				goto exit_label;
			}
		}

		/*
		e. XOR the result of step d with the block
			0x80000000000000000000000000000000;
			encrypt the result using the same key.
		*/

		/*
		i. XOR the result of step h with the block
			0x80000000000000000000000000000000;
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_Block2c));
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c) + 1);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	The next steps produce the 256-bit seed_material:
	*/
	/*
	j. Encrypt the result of step i, using the output from step e as key.
	*/

	/*
	k. Encrypt (again) the output of step j, using the same key.
	*/

	for (i = 0; i < 2; ++i)
	{
		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Data[0],
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)LLF_RND_Data[1],
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)LLF_RND_Data[1 - i]);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	3. CTR_DRBG_Update:
	*/
	/*
	a. XOR the result of step 2j with the value
		0x58e2fccefa7e3061367f1d57a4e7455a (this is the encryption
		of a block with a value of "1" using a zero key).
		Store the result in the internal state "K" register.
	*/

	/*
	b. XOR the result of step 2k with the value
		0x0388dace60b6a392f328c2b971b2fe78 (this is the encryption
		of a block with a value of "2" using a zero key).
		Store the result in the internal state "V" register.
	*/

	for (i = 0; i < 2; ++i)
	{
		vInternal[i][0] =
			*((DxUint64_t *)&LLF_RND_Data[1 - i]) ^
			*((DxUint64_t *)LLF_RND_Value3[i]);

		vInternal[i][1] =
			*(((DxUint64_t *)&LLF_RND_Data[1 - i]) + 1) ^
			*(((DxUint64_t *)LLF_RND_Value3[i]) + 1);
	}

	/*
	4. Increment the V variable, using full 128-bit arithmetic.
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	5. Reset the additional input register.
	*/

	LLF_RND_AdditionalInputFlag = 0;
	LLF_RND_AdditionalInputSize = 0;

exit_label:
	return vError;
} /* End of LLF_RND_Instantiation */

/**
****************************************************************
* Function Name: 
*  LLF_RND_GenerateVector
*
* Input:
*  @param[in]     RndSize    - The size of random vector that is required;
*  @param[in/out] Output_ptr - The output vector.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  Generates pseudo random data vector according to FIPS-SP 800-90:
*  - CCSystemSpec_RNG v1.5 [2.3.2.4 Random Number Generation];
*  - RNG_SW_SDDv0.3.
*
*  \b 
* Algorithm:
*  -# Verify Initial update of working state with additional input;
*  -# Generation of output bits;
*  -# Final update of the working state.
***************************************************************/
CE2Error_t LLF_RND_GenerateVector(DxUint16_t RndSize,		/* in */
								  DxUint8_t  *Output_ptr)	/* in/out */
{
	DxUint8_t	vRemainder[LLF_RND_DEFAULT_DATA_SIZE];
	DxUint16_t	vCount;
	DxUint16_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG v1.5

	2.3.2.4 Random Number Generation
	*/

	/*
	The random bit generation algorithm from section 10.2.1.5.2 of
	[SP800-90] is split into three functions:
	*/

	/*
	Initial update of working state with additional input
	*/

	vError = LLF_RND_Initial();

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	Generation of output bits
	*/

	/* Randomize blocks of default size directly to output */
	vCount = RndSize - (RndSize % LLF_RND_DEFAULT_DATA_SIZE);

	for (i = 0; i < vCount; i += LLF_RND_DEFAULT_DATA_SIZE)
	{
		vError = LLF_RND_Generation(&Output_ptr[i]);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/* Randomize remainder length */
	vCount = (RndSize % LLF_RND_DEFAULT_DATA_SIZE);

	if (vCount)
	{
		vError = LLF_RND_Generation(vRemainder);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		memcpy(&Output_ptr[i], vRemainder, vCount);
	}

	/*
	Final update of the working state
	*/

	vError = LLF_RND_Final();

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

exit_label:
	return vError;
} /* End of LLF_RND_GenerateVector */

/**
****************************************************************
* Function Name: 
*  LLF_RND_Reseeding
*
* Input:
*  None
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  Preforms RND engine reseeding according to FIPS-SP 800-90:
*  - CCSystemSpec_RNG v1.5 [2.3.2.3 Reseeding];
*  - RNG_SW_SDDv0.3.
*
*  \b 
* Algorithm:
*  - 1. Collect 128 bits of entropy;
*  - 2. Computation of the new 256-bit seed_material;
*  - 3. Encrypt the V register using the K register as key.
*       Increment V (using full 128-bit arithmetic);
*  - 4. XOR the result of step 3 with the result of step 2j,
*       and keep for future use as the next value for the K register;
*  - 5. Encrypt the V register (after it was incremented in step 3)
*       using the K register as key;
*  - 6. XOR the result of step 5 with the result of step 2k,
*       and store the result in the V register;
*  - 7. Copy the result from step 4 to the K register;
*  - 8. Increment the V register, using full 128-bit arithmetic;
*  - 9. Reset the additional input flag.
***************************************************************/
CE2Error_t LLF_RND_Reseeding(void)
{
#ifndef RND_FIPS_SP_800_90_TEST
	DxUint8_t	vEntropy[LLF_RND_DEFAULT_DATA_SIZE];
#endif
	DxUint64_t	*vEntropy_ptr;
	DxUint64_t	*vInternal[] = { (DxUint64_t *)LLF_RND_K, (DxUint64_t *)LLF_RND_V };
	DxUint64_t	*vData_ptr;
	DxUint64_t	*vBlock_ptr;
	DxUint8_t	i;
	CE2Error_t	vError = CE2_OK;

	/*
	CCSystemSpec_RNG v1.5

	2.3.2.3 Reseeding
	*/

	/*
	1. Collect 128 bits of entropy.
	*/

#ifdef RND_FIPS_SP_800_90_TEST
	vEntropy_ptr = (DxUint64_t *)LLF_RND_GlobalReseedEntropy;
#else
	vEntropy_ptr = (DxUint64_t *)vEntropy;

	LLF_RND_EntropyCollect((DxUint8_t *)vEntropy_ptr, LLF_RND_DEFAULT_DATA_SIZE);
#endif

	/*
	2. Computation of the new 256-bit seed_material:
	*/

	/*
	a. Compute the first word:
		it is 0x00000010 if the additional input register is empty,
		0x00000020 if the additional input register contains only 128 valid bits,
		or 0x00000030 if full (256-bit) additional input is available.
	*/

	vBlock_ptr =
		(DxUint64_t *)
			LLF_RND_Block2a[LLF_RND_AdditionalInputSize / LLF_RND_DEFAULT_DATA_SIZE];

	for (i = 0; i < 2; ++i)
	{
		vData_ptr = (DxUint64_t *)LLF_RND_Data[i];

		/*
		b. XOR the block
			(word from step a) || 0x00000020 || (EHR bits [127:64])
			with the value
			0xC6A13B37878F5B826F4F8162A1C8D879;
			encrypt the result using the key
			0x000102030405060708090A0B0C0D0E0F.
		*/

		/*
		f. XOR the block
			(word from step a) || 0x00000020 || (EHR bits [127:64])
			with the value
			0x9503E3A2245A2BE43C9874EDFE1BED9E;
			encrypt the result using the same key.
		*/

		vData_ptr[0] =
			*((DxUint64_t *)vBlock_ptr) ^
			*((DxUint64_t *)LLF_RND_Value2[i]);

		vData_ptr[1] =
			*(((DxUint64_t *)vEntropy_ptr)) ^
			*(((DxUint64_t *)LLF_RND_Value2[i]) + 1);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		if (!LLF_RND_AdditionalInputSize)
		{
			/*
			e.
				If no additional input is available,
				XOR the result of step b with
				(EHR bits [63:0]) || 0x8000000000000000;
				encrypt the result using the same key used in the previous steps.
			*/
			/*
			i.
				If additional input is not available,
				XOR the result of step f with
				(EHR bits [63:0]) ||0x8000000000000000;
				encrypt the result using the same key.
			*/

			vData_ptr[0] ^= *(((DxUint64_t *)vEntropy_ptr) + 1);
			vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c));

			vError =
				LLF_AES(
					NULL,
					*(CE2_AES_Key_t *)LLF_RND_Key2,
					CE2_AES_Key128BitSize,
					CE2_AES_Encrypt,
					CE2_AES_ECB_mode,
					(DxUint8_t *)vData_ptr,
					LLF_RND_DEFAULT_DATA_SIZE,
					(DxUint8_t *)vData_ptr);

			if (vError != CE2_OK)
			{
				vError = CE2_ERROR_BASE;
				goto exit_label;
			}

			continue;

		}

		/*
		c. If at least 128 bits of additional input are available,
			XOR the result of step b with
			(EHR bits [63:0]) || (additional input bits [63:0]);
			encrypt the result using the same key used in the previous step.
		*/

		/*
		g. If at least 128 bits of additional input are available,
			XOR the result of step f with
			(EHR bits [63:0]) || (additional input bits [63:0]);
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)vEntropy_ptr) + 1);
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput));

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		if (LLF_RND_AdditionalInputSize == LLF_RND_DEFAULT_DATA_SIZE)
		{
			/*
			e.
				If only 128-bit additional input is available,
				XOR the result of step c with
				(additional input bits [127:64]) || 0x8000000000000000;
				encrypt the result using the same key.
			*/

			/*
			i.
				If only 128 bits of additional input are available,
				XOR the result of step g with
				(additional input bits [127:64]) || 0x8000000000000000;
				encrypt the result using the same key.
			*/

			vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 1);
			vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c));

			vError =
				LLF_AES(
					NULL,
					*(CE2_AES_Key_t *)LLF_RND_Key2,
					CE2_AES_Key128BitSize,
					CE2_AES_Encrypt,
					CE2_AES_ECB_mode,
					(DxUint8_t *)vData_ptr,
					LLF_RND_DEFAULT_DATA_SIZE,
					(DxUint8_t *)vData_ptr);

			if (vError != CE2_OK)
			{
				vError = CE2_ERROR_BASE;
				goto exit_label;
			}

			continue;
		}

		/*
		d. If the full 256-bit additional input is available,
			XOR the result of step c with
			(additional input bits [191:64]);
			encrypt the result using the same key.
		*/

		/*
		h. If the full 256-bit additional input is available,
			XOR the result of step g with
			(additional input bits [191:64]);
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 1);
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 2);

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}

		/*
		e. If the full 256-bit additional input is available,
			XOR the result of step d with
			(additional input bits [255:192])  || 0x8000000000000000;
			encrypt the result using the same key.
		*/

		/*
		i. If the full 256-bit additional input is available,
			XOR the result of step h with
			(additional input bits [255:192])  || 0x8000000000000000;
			encrypt the result using the same key.
		*/

		vData_ptr[0] ^= *(((DxUint64_t *)LLF_RND_AdditionalInput) + 3);
		vData_ptr[1] ^= *(((DxUint64_t *)LLF_RND_Block2c));

		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Key2,
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)vData_ptr,
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)vData_ptr);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	j. Encrypt the result of step i, using the output from step e as key.
	*/

	/*
	k. Encrypt the result of step j (again), still using the same key. 
	*/

	for (i = 0; i < 2; ++i)
	{
		vError =
			LLF_AES(
				NULL,
				*(CE2_AES_Key_t *)LLF_RND_Data[0],
				CE2_AES_Key128BitSize,
				CE2_AES_Encrypt,
				CE2_AES_ECB_mode,
				(DxUint8_t *)LLF_RND_Data[1],
				LLF_RND_DEFAULT_DATA_SIZE,
				(DxUint8_t *)LLF_RND_Data[1 - i]);

		if (vError != CE2_OK)
		{
			vError = CE2_ERROR_BASE;
			goto exit_label;
		}
	}

	/*
	3. Encrypt the V register using the K register as key.
	Increment V (using full 128-bit arithmetic).
	Keep the result in an other register.
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_RESEEDING_3);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/* Increment V (using full 128-bit arithmetic) */
	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	4. XOR the result of step 3 with the result of step 2j,
		and keep for future use as the next value for the K register.
	*/

	*(((DxUint64_t *)LLF_RND_Data[1]) + 0) ^= *(((DxUint64_t *)LLF_RND_RESEEDING_3) + 0);
	*(((DxUint64_t *)LLF_RND_Data[1]) + 1) ^= *(((DxUint64_t *)LLF_RND_RESEEDING_3) + 1);

	/*
	5. Encrypt the V register (after it was incremented in step 3)
	using the K register as key.
	*/

	vError =
		LLF_AES(
			NULL,
			*(CE2_AES_Key_t *)LLF_RND_K,
			CE2_AES_Key128BitSize,
			CE2_AES_Encrypt,
			CE2_AES_ECB_mode,
			(DxUint8_t *)LLF_RND_V,
			LLF_RND_DEFAULT_DATA_SIZE,
			(DxUint8_t *)LLF_RND_V);

	if (vError != CE2_OK)
	{
		vError = CE2_ERROR_BASE;
		goto exit_label;
	}

	/*
	6. XOR the result of step 5 with the result of step 2k,
	and store the result in the V register.
	*/

	*(((DxUint64_t *)LLF_RND_V) + 0) ^= *(((DxUint64_t *)LLF_RND_Data[0]) + 0);
	*(((DxUint64_t *)LLF_RND_V) + 1) ^= *(((DxUint64_t *)LLF_RND_Data[0]) + 1);

	/*
	7. Copy the result from step 4 to the K register.
	*/

	*(((DxUint64_t *)LLF_RND_K) + 0) = *(((DxUint64_t *)LLF_RND_Data[1]) + 0);
	*(((DxUint64_t *)LLF_RND_K) + 1) = *(((DxUint64_t *)LLF_RND_Data[1]) + 1);

	/*
	8. Increment the V register, using full 128-bit arithmetic.
	*/

	for (i = LLF_RND_DEFAULT_DATA_SIZE; ;)
		if (i == 0 || ++LLF_RND_V[--i])
			break;

	/*
	9. Reset the additional input register.
	*/

	LLF_RND_AdditionalInputFlag = 0;
	LLF_RND_AdditionalInputSize = 0;

exit_label:
	return vError;
} /* End of LLF_RND_Reseeding */

/**
****************************************************************
* Function Name: 
*  LLF_RND_AddAdditionalInput
*
* Input:
*  @param[in] AdditionalInput     - Additional input data;
*  @param[in] AdditionalInputSize - Additional input data size.
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - on failure a value from CE2_error.h:
*
* \brief \b 
* Description:
*  Adds additional info vector to RND engine according to:
*  - CCSystemSpec_RNG v1.5;
*  - RNG_SW_SDDv0.3.
*
*  \b 
* Algorithm:
*  -# Set additional info data.
***************************************************************/
CE2Error_t LLF_RND_AddAdditionalInput(DxUint8_t  *AdditionalInput,		/* in */
									  DxUint16_t AdditionalInputSize)	/* in */
{
	LLF_RND_AdditionalInputSize = AdditionalInputSize;

	if (LLF_RND_AdditionalInputSize)
	{
		/* Set additional input using entire input */
		memcpy(LLF_RND_AdditionalInput, AdditionalInput, AdditionalInputSize);
	}

	/*
	Set the additional input flag.
	*/

	LLF_RND_AdditionalInputFlag = 1;

	return CE2_OK;
} /* End of LLF_RND_AddAdditionalInput */

#endif