  /*
   *  Object %name    : %CRYS_ECDH.c
   *  State           :  %state%
   *  Creation date   :  28.02.2006
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief The file includes definitions of CRYS level functions
   *         of Diffie_Hellman shared secret value derivation primitives.
   *         
   *
   *  \version CRYS_ECDH.c#1:csrc:1
   *  \author  R.Levin
   *  \remarks Copyright (C) 2006 by Discretix Technologies Ltd.
   *           All Rights reserved
   */

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

/* CRYS level includes  */
#include "DX_VOS_Mem.h"
#include "CRYS_ECPKI_DH.h"
#include "CRYS_ECPKI_error.h"
#include "SEPDriver.h"
#include "crys_host_op_code.h"
#include "error.h"
//#include "CRYS_ECPKI_Local.h"

/* LLF level includes  */
//#include "LLF_ECPKI_Export.h"


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

/************************ Enums ***************************************/

/************************ Typedefs ************************************/

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

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


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


/***********************************************************************
 *		         CRYS_ECDH_SVDP_DH function 						   *							  
 ***********************************************************************/
/**
 @brief    Creates the shared secret value accordingly to the IEEE 1363-2000 
 			standard. 

	       This function performs the following:
 			
		-# Checks input parameters: pointers and EC Domain ID.
		-# Derives the partner public key and calls the LLF_ECPKI_SVDP_DH function,
		    which performs EC SVDP operations. On errors, outputs error messages.
		-# Exits.
	\note  The term "user" indicates any party who performs a calculation of a shared 
	secret value using this primitive. The term "partner" indicates any other party of 
	shared secret value calculation.
 
 @param[in]  BuildedPartnerPublKey_ptr  A pointer to a partner public key W 
 @param[in]  UserPrivKey_ptr	        A pointer to a user private key  
 @param[out] SharedSecretValue_ptr      A pointer to an output buffer that will contain
                                        the shared secret value 
 @param[in,out] SharedSecrValSize_ptr   A pointer to the size of user passed buffer (in) and 
                                        actual output size  of calculated shared secret value.
 @param[in]  TempBuff_ptr               A pointer to a temporary buffers of size specified in 
                                        the CRYS_ECDH_TempData_t structure.
 @return <b>CRYSError_t</b>: <br> 
			 CRYS_OK<br> 
                         CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR<br> 
                         CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR<br> 
 			 CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR<br> 
			 CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR<br> 
                         CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR<br> 
			 CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR<br> 
			 CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR<br> 
			 CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR<br> 
			 
   NOTE:    1. The partner public key and user private key must relate to the same DomainID.
            2. The public key must be full validated befor using in this primitive.
            3. Buffer size for SharedSecretValue must be >= ModulusSizeInWords*4 bytes,  
               output size of shared value is equal to ModulusSizeInWords*4. 		 
*/
CEXPORT_C CRYSError_t CRYS_ECDH_SVDP_DH(CRYS_ECPKI_UserPublKey_t    *BuildedPartnerPublKey_ptr, /*in*/
                            						CRYS_ECPKI_UserPrivKey_t    *UserPrivKey_ptr,           /*in*/							                
                            						DxUint8_t                   *SharedSecretValue_ptr,     /*out*/
                            						DxUint32_t                  *SharedSecrValSize_ptr,     /*in/out*/
                            						CRYS_ECDH_TempData_t        *TempBuff_ptr               /*in*/ )
{
  /* the error identifier */
  CRYSError_t         Error;
  
  /* offset */
  DxUint32_t          sramOffset;
   
  /* read param */
  DxUint32_t          messageParam[2];
  
  /* max length */
  DxUint32_t          maxLength; 

  /*--------------------------------------
      CODE
  ------------------------------------------*/  
                       
#ifndef CRYS_NO_HASH_SUPPORT                                    
#ifndef CRYS_NO_ECPKI_SUPPORT 

    
  /* Initialize Error */
  Error = CRYS_OK;                                     
 
  /* ................. checking the validity of the pointer arguments ...... */
  /* ----------------------------------------------------------------------- */
      
  /* ...... checking the validity of the user private key pointer .......... */
  if( UserPrivKey_ptr == DX_NULL )
  {
    Error = CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR;
    goto end_function;
  }
     
       
  /* .... checking the validity of the other partner public key pointer .... */
  if( BuildedPartnerPublKey_ptr == DX_NULL )
  {
    Error = CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR;
    goto end_function;
  }   
   
   
  /* ...... checking the validity of the SharedSecretValue pointer ..........*/
  if( SharedSecretValue_ptr == DX_NULL )
  {
    Error = CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR;
    goto end_function;
  }   
  
  /* ...... checking the validity of SharedSecrValSize_ptr pointer ......... */
  if( SharedSecrValSize_ptr == DX_NULL )
  {
    Error = CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR;
    goto end_function;
  }   
 
  /* ...... checking the validity of temp buffers         .................. */
  if( TempBuff_ptr == DX_NULL )
  {
    Error = CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR;
    goto end_function;
  }
  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_ECC_DH_OP_CODE;
  /* send the size of buffer for shared secret value */
  messageParam[1] = *SharedSecrValSize_ptr;

  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam ,
                           2*sizeof(DxUint32_t),
                           2*sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send private key */
  maxLength = ((sizeof(CRYS_ECPKI_UserPrivKey_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)UserPrivKey_ptr ,
                            sizeof(CRYS_ECPKI_UserPrivKey_t),
                            maxLength,
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send public key */
  maxLength = ((sizeof(CRYS_ECPKI_UserPublKey_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)BuildedPartnerPublKey_ptr ,
                            sizeof(CRYS_ECPKI_UserPublKey_t),
                            maxLength,
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_POLL_FOR_REPONSE();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
  
                                            
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam ,
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_ECC_DH_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
  
  /* data out size  */
  Error = SEPDriver_ReadParamater((DxUint32_t)SharedSecrValSize_ptr ,
                          sizeof(DxUint32_t),
                          sizeof(DxUint32_t),
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                          
  /* read data out */
  maxLength = ((*SharedSecrValSize_ptr + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)SharedSecretValue_ptr ,
                          *SharedSecrValSize_ptr,
                          maxLength,
                          &sramOffset , 
                          DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
  /* ...................... end of function ................................ */   

end_function_unlock:   

  /* lock access to the SEP */
  SEPDriver_Unlock();
  
                       
end_function:

  return Error;
                   
  #endif /* CRYS_NO_ECPKI_SUPPORT */
  #endif /* CRYS_NO_HASH_SUPPORT */                                   

}/* END OF LLF_ECPKI_DH */                                       

