#ifndef QSEE_PKEY_H
#define QSEE_PKEY_H

/**
@file qsee_pkey.h
@brief Provides APIs to perform public-key operations
*/

/*===========================================================================
Copyright (c) {2012, 2018} Qualcomm Technologies, Inc.
All Rights Reserved.
Confidential and Proprietary - Qualcomm Technologies, Inc.
===========================================================================*/

/*----------------------------------------------------------------------------
 * Include Files
 * -------------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include "qsee_crypto_engine.h"

/**
@addtogroup qtee_pkey
@{
Public key algorithms

*/

/*----------------------------------------------------------------------------
 * Type Declarations
 * -------------------------------------------------------------------------*/
/**
  Context handle to be used with any public-key operations.
*/
typedef void * QSEE_PKEY_HANDLE;


/**
 * Public-key algorithm types
 */
typedef enum {
  QSEE_PKEY_SM2,                              /**< SM2 digital signature algorithms as published by the Chinese Commercial Cryptography Administration Office */

  QSEE_PKEY_MAX_ALG_COUNT
} QSEE_PKEY_ALG;

/**
 * Public-key control paramater types
 */
typedef enum {

  QSEE_PKEY_PARAM_SET_KEYGEN_BITS,            /**< Sets the key size (in bits) */

  QSEE_PKEY_PARAM_GET_KEYSIZE_BITS,           /**< Gets the key size (in bytes) */

  QSEE_PKEY_PARAM_SET_MOD,                    /**< Accepts a byte-array and length to set the modulus */

  QSEE_PKEY_PARAM_SET_PUBKEY,                 /**< Accepts a byte-array and length to set the public key/exponent */

  QSEE_PKEY_PARAM_SET_PRIVKEY,                /**< Accepts a byte-array and length to set the private exponent */

  QSEE_PKEY_PARAM_SET_PEERKEY,                /**< Accepts a byte-array and length to set the peer public key */

  QSEE_PKEY_PARAM_GET_MOD,                    /**< Accepts a byte-array and length to return the modulus */

  QSEE_PKEY_PARAM_GET_PUBKEY,                 /**< Accepts a byte-array and length to return the public exponent/key */

  QSEE_PKEY_PARAM_GET_PRIVKEY,                /**< Accepts a byte-array and length to return the private exponent/key */

  QSEE_PKEY_PARAM_SET_EC_CURVE,               /**< Accepts a curve ID to initialize the EC parameters */

  QSEE_PKEY_PARAM_SET_COEFFICIENT_A,          /**< Accepts a hexadecimal string and length to set the a-coefficient of the curve */

  QSEE_PKEY_PARAM_SET_COEFFICIENT_B,          /**< Accepts a hexadecimal string and length to set the b-coefficient of the curve */

  QSEE_PKEY_PARAM_SET_BASE_X,                 /**< Accepts a hexadecimal string and length to set the X co-ordinate of the generator/base point of the curve */

  QSEE_PKEY_PARAM_SET_BASE_Y,                 /**< Accepts a hexadecimal string and length to set the Y co-ordinate of the generator/base point of the curve */

  QSEE_PKEY_PARAM_SET_BASE_N,                 /**< Accepts a hexadecimal string and length to set the order of the base point of the curve */

  QSEE_PKEY_PARAM_SET_COFACTOR,               /**< Accepts a hexadecimal string and length to set the co-factor of the group generated by the base point */

  QSEE_PKEY_PARAM_SET_IDENTIFIER,             /**< Set the user 'identifier' - used primarily with SM2 sign, verify and key exchange operations.  */

  QSEE_PKEY_PARAM_SET_PEER_IDENTIFIER,        /**< Set the peer 'identifier' - used primarily with SM2 sign, verify and key exchange operations.  */

  QSEE_PKEY_PARAM_GET_SIGNATURE_SIZE,         /**< Get the size of the signature in bytes */

  QSEE_PKEY_PARAM_GET_SHARED_KEY_PARAM,       /**< Generate and retrieve the parameter 'R' (R=[r]G) for SM2 shared-key derivation */

  QSEE_PKEY_PARAM_SET_PEER_SHARED_KEY_PARAM,  /**< Set the peer's parameter 'R', used in shared-key derivation for SM2 */

  QSEE_PKEY_PARAM_SET_SHARED_KEY_INITIATOR,   /**< Set whether the user is the shared-key derivation initiator */

  QSEE_PKEY_PARAM_MAX

} QSEE_PKEY_PARAM_TYPE;


/*----------------------------------------------------------------------------
 * Function Declarations and Documentation
 * -------------------------------------------------------------------------*/

/**
 * Allocates memory for a context for pkey operations and returns a
 * handle to the caller.
 * It is the caller's responsiblity to call qsee_pkey_free() to
 * properly clean up pkey context and release any associated resources.
 *
 * @param None
 *
 * @return       Non zero value if successful.
 */
QSEE_PKEY_HANDLE qsee_pkey_new(void);

/**
 * Clears the pkey context and releases internal resources.
 *
 * @param h      [in] handle to the pkey context.
 *
 * @return       0 if successful, negative value otherwise.
 */
int qsee_pkey_free(QSEE_PKEY_HANDLE h);

/**
 * Initializes a previously-allocated handle for pkey operations, based
 * on the alogrithm and engine chosen.
 *
 * @param h      [in] handle to the pkey context
 * @param algo   [in] pkey algorithm type enumerated in QSEE_PKEY_ALG
 * @param engine [in] engine type enumerated in QSEE_CE_ENGINE_TYPE. If the
 *               engine parameter is passed as 0, the default engine will be
 *               used.
 *
 * @return       0 if successful, negative value otherwise.
 */
int qsee_pkey_init(QSEE_PKEY_HANDLE h,
                   QSEE_PKEY_ALG algo,
                   QSEE_CE_ENGINE_TYPE engine);

/**
 * Resets pkey context and clears internal states in order to re-use the
 * pkey context for another pkey operation. One can use the interface to
 * re-use the allocated pkey context for different pkey algorithm.
 *
 * @param h      [in] handle to the pkey context
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_reset(QSEE_PKEY_HANDLE h);

/**
 * Sets or gets control or context parameters, related to the operation
 * of the chosen algorithm. When the parameter name contains _GET_, this
 * typically signifies that the caller is requesting for the value of a
 * parameter to be returned to them. Otherwise the parameter signifies
 * the setting of a control variable.
 *
 * @param h     [in]      handle to the pkey context
 * @param type  [in]      pkey param type (parameter name indicates get/set)
 * @param val   [in]      Integer input parameter
 * @param buf   [in, out] pointer to a buffer-parameter which
 *                        can be used to pass data to or
 *                        retrieve data from the context
 * @param isz   [in]      Size-parameter, used to indicate the
 *                        length of the buffer parameter
 * @param osz   [out]     Size-parameter, used to indicate the
 *                        length of the buffer being returned
 *
 * @return      0 if successful. negative value otherwise.
 */
int qsee_pkey_ctrl(QSEE_PKEY_HANDLE h,
                   QSEE_PKEY_PARAM_TYPE type,
                   int val,
                   uint8_t *buf,
                   size_t isz,
                   size_t *osz);

/**
 * Generates a key.
 * Parameters can be set up using the qsee_pkey_ctrl() API.
 *
 * @param h      [in]  handle to the pkey context
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_keygen(QSEE_PKEY_HANDLE h);

/**
 * Signs the message digest using the private key and returns the
 * signature.
 * Parameters can be set up using the qsee_pkey_ctrl() API.
 *
 * @param h           [in]  handle to the pkey context
 * @param md          [in]  pointer to message digest
 * @param md_len      [in]  message digest length
 * @param sig         [out] pointer to signature output buffer
 * @param sig_buf_len [in]  output buffer length
 * @param out_len     [out] length of data filled into output buffer
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_sign(QSEE_PKEY_HANDLE h,
                   const uint8_t *md,
                   size_t md_len,
                   uint8_t *sig,
                   size_t sig_buf_len,
                   size_t *out_len);

/**
 * Verify the message digest and signature by using public key.
 * Parameters can be set up using the qsee_pkey_ctrl() API.
 *
 * @param h        [in]  handle to the pkey context
 * @param md       [in]  pointer to message digest
 * @param md_len   [in]  message digest length
 * @param sig      [in]  pointer to signature
 * @param sig_len  [in]  length of signature.
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_verify(QSEE_PKEY_HANDLE h,
                     const uint8_t *md,
                     size_t md_len,
                     const uint8_t *sig,
                     size_t sig_len);

/**
 * Encrypt the input message by using public key.
 * Parameters can be set up using the qsee_pkey_ctrl() API.
 * The value in out_len indicates the length of the data filled into
 * the out buffer.
 *
 * @param h           [in]  handle to the pkey context
 * @param in          [in]  pointer to message
 * @param in_len      [in]  message length
 * @param out         [out] pointer to cipher output buffer
 * @param out_buf_len [in]  output buffer length
 * @param out_len     [out] length of data filled into output buffer
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_encrypt(QSEE_PKEY_HANDLE h,
                      const uint8_t *in,
                      size_t in_len,
                      uint8_t *out,
                      size_t out_buf_len,
                      size_t *out_len);

/**
 * Decrypt the input cipher message by using private key.
 * Parameters can be set up using the qsee_pkey_ctrl() API.
 * The value in out_len indicates the length of the data filled into
 * the out buffer.
 *
 * @param h           [in]  handle to the pkey context
 * @param in          [in]  pointer to cipher message
 * @param in_len      [in]  cipher message length
 * @param out         [out] pointer to message output buffer
 * @param out_buf_len [in]  output buffer length
 * @param out_len     [out] length of data filled into output buffer
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_decrypt(QSEE_PKEY_HANDLE h,
                      const uint8_t *in,
                      size_t in_len,
                      uint8_t *out,
                      size_t out_buf_len,
                      size_t *out_len);

/**
 * Derive the shared secret/key
 *
 * @param h           [in]  handle to the pkey context
 * @param out         [out] pointer to output buffer
 * @param out_buf_len [in]  output buffer length
 * @param out_len     [out] length of data filled into output buffer
 *
 * @return 0 if successful. negative value otherwise.
 */
int qsee_pkey_derive(QSEE_PKEY_HANDLE h,
                     uint8_t *out,
                     size_t out_buf_len,
                     size_t *out_len);

/** @} */

#endif /* QSEE_PKEY_H */
