/*
 * Copyright (c) 2021-2025 Yuntu Microelectronics Co., Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */
/*!
 * @file pke_driver.h
 */

#ifndef PKE_DRV_H
#define PKE_DRV_H

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "status.h"
#include "osif.h"
#include "hcu_driver.h"

/*! @file pke_driver.h */

/*!
 * @addtogroup pke_driver
 * @{
 */

#if FEATURE_HCU_RSA_ENGINE
/*! 
 * @brief HCU RSA algorithm selection
 *
 * Implements : hcu_rsa_alg_t_Class
 */
typedef enum
{
    RSA_1024 = 0x1FU,                     /*!< RSA-1024 selected */
    RSA_2048 = 0x3FU,                     /*!< RSA-2048 selected */
    RSA_3072 = 0x5FU,                     /*!< RSA-3072 selected */
    RSA_4096 = 0x7FU,                     /*!< RSA-4096 selected */
} hcu_rsa_alg_t;

/*! 
 * @brief Define input data and output data carried type 
 *
 * Implements : hcu_rsa_carry_type_t_Class
 */
typedef enum
{
    HCU_RSA_USING_POLLING         = 0U,          /*!< Carry data by polling */
    HCU_RSA_USING_INTERRUPT       = 1U,          /*!< Carry data by interrupt */
} hcu_rsa_carry_type_t;

typedef enum
{
    RSA_STEP_IDLE       = 0U,       /*!< RSA idle */
    RSA_STEP_INIT       = 1U,       /*!< RSA init for calculation */
    RSA_STEP_LOAD_N     = 2U,       /*!< RSA load N */
    RSA_STEP_LOAD_INPUT = 3U,       /*!< RSA load input data */
    RSA_STEP_LOAD_KEY   = 4U,       /*!< RSA load public/private key */
    RSA_STEP_GET_OUTPUT = 5U,       /*!< RSA get result */
} hcu_rsa_step_state_t;
#endif /* FEATURE_HCU_RSA_ENGINE */

#if FEATURE_HCU_ECC_ENGINE
/*! 
 * @brief HCU ECC algorithm selection
 *
 * Implements : hcu_ecc_alg_t_Class
 */
typedef enum
{
    ECC_P_192 = 0x05U,                     /*!< ECC p-192 selected */
    ECC_P_256 = 0x07U,                     /*!< ECC p-256 selected */
    ECC_P_384 = 0x0BU,                     /*!< ECC p-384 selected */
} hcu_ecc_alg_t;
#endif /* FEATURE_HCU_ECC_ENGINE */

#if FEATURE_HCU_RSA_ENGINE
/*!
 * @brief Specifies the RSA configuration. 
 *
 * @note private key is (n, d) and public key is (n, e)
 *
 * Implements : hcu_rsa_config_t_Class
 */
typedef struct
{
    uint8_t privateKeyLen;                       /*!< Specifies the words of private key length */
    uint32_t d[FEATURE_HCU_RSA_MAX_WORD_LENGTH]; /*!< Specifies the private key */
    uint8_t publicKeyLen;                        /*!< Specifies the words of public key length */
    uint32_t e[FEATURE_HCU_RSA_MAX_WORD_LENGTH]; /*!< Specifies the public key */
    hcu_rsa_alg_t opLength;                      /*!< Specifies the length of RSA operation */
    uint32_t n[FEATURE_HCU_RSA_MAX_WORD_LENGTH]; /*!< Specifies the N for RSA */
#if FEATURE_RSA_HAS_HARDWARE_KEY_LOAD
    bool rsaLoadHwPrivateKey;                    /*!< Specifies RSA if use hardware private key */
    uint8_t rsaHwPrivateKeySlot;                 /*!< Specifies RSA hardware private key select */
    bool rsaLoadHwPublicKey;                     /*!< Specifies RSA if use hardware public key */
    uint8_t rsaHwPublicKeySlot;                  /*!< Specifies RSA hardware public key select */
#endif /* FEATURE_RSA_HAS_HARDWARE_KEY_LOAD */
    hcu_rsa_carry_type_t rsaCarryType;           /*!< Specifies RSA carry data type */
} hcu_rsa_config_t;
#endif /* FEATURE_HCU_RSA_ENGINE */

#if FEATURE_HCU_ECC_ENGINE
/*!
 * @brief Specifies the ECC configuration. 
 *
 * @note Ellipse is y^2 = x^3 + ax + b (mod p), 
 *       and base point G is (gx, gy)
 *
 * Implements : hcu_ecc_config_t_Class
 */
typedef struct
{
    hcu_ecc_alg_t opLength;                         /*!< Specifies the length of ECC operation */
    uint32_t a[FEATURE_HCU_ECC_MAX_WORD_LENGTH];    /*!< Specifies the a of ellipse */
    uint32_t b[FEATURE_HCU_ECC_MAX_WORD_LENGTH];    /*!< Specifies the b of ellipse */
    uint32_t p[FEATURE_HCU_ECC_MAX_WORD_LENGTH];    /*!< Specifies the p of ellipse */
    uint32_t gx[FEATURE_HCU_ECC_MAX_WORD_LENGTH];   /*!< Specifies the Gx of base point G */
    uint32_t gy[FEATURE_HCU_ECC_MAX_WORD_LENGTH];   /*!< Specifies the Gy of base point G */
    uint32_t n[FEATURE_HCU_ECC_MAX_WORD_LENGTH];    /*!< Specifies the n of ellipse */
} hcu_ecc_config_t;

/*!
 * @brief Specifies the ECC kG output point. 
 *
 * Implements : hcu_ecc_point_t_Class
 */
typedef struct
{
    uint32_t *pointX;   /*!< Pointer to the X of point */
    uint32_t *pointY;   /*!< Pointer to the Y of point */
} hcu_ecc_point_t;

/*!
* @brief Specifies the ECDSA Signature Generation and
*        Signature Verification. 
*
* Implements : hcu_ecdsa_config_t_Class
*/
typedef struct
{
    uint32_t const *privateKey;              /*!< Specifies private key for ECDSA, ignore if during signature verification */
    hcu_ecc_point_t *publicKey;              /*!< Specifies public key generated by private key by ECC */
    uint32_t const *K;                       /*!< Specifies random number K for ECDSA signature generate, ignore if during signature verification */
    hcu_sha_type_t shaType;                  /*!< Specifies the type of SHA */
    uint32_t msgLen;                         /*!< Specifies the message length for ECDSA. */
    uint32_t const *message;                 /*!< Specifies the message for ECDSA. */
    uint32_t *hashResult;                    /*!< Specifies the hash result (little endian) for message. */
    uint32_t *R;                             /*!< Specifies the R of signature pair (r, s) for ECDSA */
    uint32_t *S;                             /*!< Specifies the S of signature pair (r, s) for ECDSA */
} hcu_ecdsa_config_t;
#endif /* FEATURE_HCU_ECC_ENGINE */

/*!
 * @brief Specifies the user configuration of HCU.
 *
 * Implements : hcu_user_config_t_Class
 */
typedef struct
{
#if FEATURE_HCU_ECC_ENGINE
    hcu_ecc_config_t const *eccConfig; /*!< Specifies the ecc configuration  */
#endif /* FEATURE_HCU_ECC_ENGINE */
#if FEATURE_HCU_RSA_ENGINE
    hcu_rsa_config_t const *rsaConfig; /*!< Specifies the rsa configuration  */
#endif /* FEATURE_HCU_RSA_ENGINE */
} pke_user_config_t;

/*!
 * @brief Internal driver state information.
 *
 * @note The contents of this structure are internal to the driver and should not be
 *       modified by users. Also, contents of the structure are subject to change in
 *       future releases.
 *
 * Implements : hcu_state_t_Class
 */
typedef struct
{
    status_t status;              /*!< Specifies the current status */
    semaphore_t cmdComplete;      /*!< Synchronization object for synchronous operation */
#if FEATURE_HCU_ECC_ENGINE
    hcu_ecc_config_t const *eccConfig; /*!< Specifies the ecc configuration  */
#endif /* FEATURE_HCU_ECC_ENGINE */
#if FEATURE_HCU_RSA_ENGINE
    hcu_rsa_config_t const *rsaConfig; /*!< Specifies the rsa configuration  */
    uint32_t const *inputData;
    uint32_t *outputData;
    uint32_t length;
    hcu_rsa_step_state_t rsaStep;
    bool rsaEncrypt;
#endif /* FEATURE_HCU_RSA_ENGINE */
} pke_state_t;


/*******************************************************************************
 * API
 ******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Initializes the internal state of the driver and enables the HCU interrupt.
 *
 * @param[in] userConfig Pointer to the configuration of hcu module.
 * @param[in] state Pointer to the state structure which will be used for holding
 * the internal state of the driver.
 * @return Error Code after command execution.
 */
status_t PKE_DRV_Init(const pke_user_config_t * userConfig, pke_state_t *state);

/*!
 * @brief De-initializes the internal state of the driver and disables the HCU interrupt.
 *
 * @param[in] state Pointer to the state structure which will be used for holding
 * the internal state of the driver.
 * @return Error Code after command execution.
 */
status_t PKE_DRV_DeInit(pke_state_t *state);

#if FEATURE_HCU_RSA_ENGINE
/*!
 * @brief Performs the RSA encryption.
 *
 * This function performs the RSA encryption of the input
 * plaintext buffer.
 *
 * @param[in] plainText Pointer to the plain text buffer.
 *            @note Address passed in this parameter must be 32 bit aligned.
 * @param[in] length Number of bytes of plain text message to be encrypted.
 *            @note Should be multiple of 16 bytes.
 * @param[out] cipherText Pointer to the cipher text buffer. 
 *            @note Address passed in this parameter must be 32 bit aligned.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_EncryptRSA(uint32_t const *plainText, uint32_t length, uint32_t *cipherText);

/*!
 * @brief Performs the RSA decryption.
 *
 * This function performs the RSA decryption of the input
 * cipher text buffer.
 *
 * @param[in] cipherText Pointer to the cipher text buffer. 
 *            @note Address passed in this parameter must be 32 bit aligned.
 * @param[in] length Number of bytes of plain text message to be encrypted.
 *            @note Should be multiple of 16 bytes.
 * @param[in] plainText Pointer to the plain text buffer.
 *            @note Address passed in this parameter must be 32 bit aligned.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_DecryptRSA(uint32_t const *cipherText, uint32_t length, uint32_t *plainText);

/*!
 * @brief Performs the RSA step calculation.
 *
 * This function performs the RSA calculation
 */
void HCU_DRV_StepCalcRSA(void);
/*!
 * @brief Get RSA calculation if done.
 *
 * Get RSA calculation if done in asynchronous mode.
 *
 * @return return STATUS_SUCCESS if RSA done, other return STATUS_BUSY
 */
status_t HCU_DRV_GetRSAStatus(void);
#endif /* FEATURE_HCU_RSA_ENGINE */

#if FEATURE_HCU_ECC_ENGINE
/*!
 * @brief Performs the ECC point multiply.
 *
 * This function performs the ECC point multiply.
 *  point = K * pointP
 *
 * @param[in] K Pointer to the random number for point multiply.
 *            @note Address passed in this parameter must be 32 bit aligned.
 * @param[in] pointP Pointer to the point to multiply.
 * @param[out] point Pointer to the result point.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_ECCPointMul(uint32_t const *K, hcu_ecc_point_t const *pointP, 
                             hcu_ecc_point_t *point);

/*!
 * @brief Performs the ECC point add.
 *
 * This function performs the ECC point add.
 *  pointR = pointP + pointQ
 *
 * @param[in] pointP Pointer to the point to add.
 * @param[in] pointQ Pointer to the point to add.
 * @param[out] pointR Pointer to the result point.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_ECCPointAdd(hcu_ecc_point_t const *pointP, hcu_ecc_point_t const *pointQ, 
                             hcu_ecc_point_t *pointR);

/*!
 * @brief Performs the ECDSA generate signature.
 *
 * Generate public key of ECC by private key.
 * Generate HASH for message.
 * Generate signature (r, s) of ECDSA
 *
 * @param[inout] ecdsaCfg Pointer to the ECDSA configuration.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_ECDSA_GenerateSignature(hcu_ecdsa_config_t * ecdsaCfg);

/*!
 * @brief Performs the ECDSA verify signature.
 *
 * Generate HASH for message.
 * Verify signature (r, s) of ECDSA
 *
 * @param[inout] ecdsaCfg Pointer to the ECDSA configuration.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_ECDSA_VerifySignature(hcu_ecdsa_config_t * ecdsaCfg);
#endif /* FEATURE_HCU_ECC_ENGINE */

#if FEATURE_HCU_PKE_ENGINE
/*!
 * @brief Performs the PKE pre-calculate.
 *
 * @param[in] N Pointer to the data for N FIFO.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_PreCalculate(uint32_t const *N, uint32_t *result);

/*!
 * @brief Performs the PKE subtract.
 * 
 * This function performs the subtract.
 * result = A - E
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[in] E Pointer to the data for E FIFO.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKESub(uint32_t const *A, uint32_t const *E, uint32_t *result);

/*!
 * @brief Performs the PKE add.
 * 
 * This function performs the add.
 * result = A + E
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[in] E Pointer to the data for E FIFO.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKEAdd(uint32_t const *A, uint32_t const *E, uint32_t *result);

/*!
 * @brief Performs the PKE double.
 * 
 * This function performs the double.
 * result = A + A
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKEDouble(uint32_t const *A, uint32_t *result);

/*!
 * @brief Performs the PKE square.
 * 
 * This function performs the square.
 * result = A * A
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[in] R2 Pointer to the R^2.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKESquare(uint32_t const *A, uint32_t const *R2, uint32_t *result);

/*!
 * @brief Performs the PKE multiply.
 * 
 * This function performs the multiply.
 * result = A * E
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[in] E Pointer to the data for E FIFO.
 * @param[in] R2 Pointer to the R^2.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKEMultiply(uint32_t const *A, uint32_t const *E, uint32_t const *R2, uint32_t *result);

/*!
 * @brief Performs the PKE inverse .
 * 
 * This function performs the Fermat's little theorem.
 * result = 1 / A 
 *
 * @param[in] A Pointer to the data for A FIFO.
 * @param[in] E Pointer to the data of prime.
 * @param[in] R2 Pointer to the R^2.
 * @param[out] result Pointer to the result.
 * @return Error Code after command execution. Output parameters are valid if
 * the error code is STATUS_SUCCESS.
 */
status_t HCU_DRV_GetPKEInverse(uint32_t const *A, uint32_t const *N, uint32_t const *R2, uint32_t *result);
#endif /* FEATURE_HCU_PKE_ENGINE */

#if defined(__cplusplus)
}
#endif

/*! @}*/

#endif /* PKE_DRV_H */

/*******************************************************************************
 * EOF
 ******************************************************************************/
