/** Isolated Keys support
 *
 * @file
 */
/*
 * Copyright (c) 2020 Silex Insight sa
 * Copyright (c) 2020 Beerten Engineering scs
 * SPDX-License-Identifier: BSD-3-Clause
 */


#ifndef IK_HEADER_FILE
#define IK_HEADER_FILE

#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup SX_PK_CORE
 *
 * @{
 */

/** List slots for a IK operation & activate IK mode.
 *
 * Once the function completes with ::SX_OK,
 * the hardware is in IK mode. Write each
 * operand to the address
 * found in the corresponding slot.
 *
 * That applies to all IK operations:
 * ::SX_PK_CMD_IK_PUBKEY_GEN, ::SX_PK_CMD_IK_ECDSA_SIGN,
 * ::SX_PK_CMD_IK_PTMULT, ::SX_PK_CMD_IK_EXIT
 *
 * @param[inout] req The acceleration request obtained
 * through sx_pk_acquire_req()
 * @param[in] key Index of key to be used for IK operation
 * @param[out] inputs List of input slots that will be filled in.
 * See inputslots.h for predefined lists of input slots per operation.
 * Null should be passed for operations that have no input operands. Example:
 * ::SX_PK_CMD_IK_PUBKEY_GEN, ::SX_PK_CMD_IK_EXIT
 *
 * @return ::SX_OK
 * @return ::SX_ERR_INVALID_PARAM
 */
int sx_pk_list_ik_inslots(sx_pk_req *req, unsigned int key, struct sx_pk_slot *inputs);

/** @} */

/**
 * @addtogroup SX_PK_IK_CMDS
 *
 * @{
 */

/** IK Public key generation
 *
 * This operation can be protected with blinding counter measures,
 * which can randomly fail with SX_ERR_NOT_INVERTIBLE. If it happens,
 * the operation should be retried. See the user guide
 * 'Isolated Key' section for more information.
*/
extern const struct sx_pk_cmd_def * const SX_PK_CMD_IK_PUBKEY_GEN;

/** IK ECDSA signature generation
 *
 * This operation can be protected with blinding counter measures,
 * which can randomly fail with SX_ERR_NOT_INVERTIBLE. If it happens,
 * the operation should be retried. See the user guide
 * 'Isolated Key' section for more information.
 *
 * This operation can return a SX_ERR_INVALID_SIGNATURE.
 * This error can happen when the nonce (k) generated by
 * IK generates an invalid signature. The operation should be
 * retried.
*/
extern const struct sx_pk_cmd_def * const SX_PK_CMD_IK_ECDSA_SIGN;

/** IK ECC point multiplication
 *
 * This operation can be protected with blinding counter measures,
 * which can randomly fail with SX_ERR_NOT_INVERTIBLE. If it happens,
 * the operation should be retried. See the user guide
 * 'Isolated Key' section for more information.
*/
extern const struct sx_pk_cmd_def * const SX_PK_CMD_IK_PTMULT;

/** Exit IK mode */
extern const struct sx_pk_cmd_def * const SX_PK_CMD_IK_EXIT;

/** @} */

/** Input slots for ::SX_PK_CMD_IK_ECDSA_SIGN*/
struct sx_pk_inops_ik_ecdsa_sign {
   struct sx_pk_slot h; /**< Hash digest **/
};

/** Input slots for ::SX_PK_CMD_IK_PTMULT*/
struct sx_pk_inops_ik_ptmult {
   struct sx_pk_slot px; /**< x-coordinate of point P **/
   struct sx_pk_slot py; /**< y-coordinate of point P **/
};

struct sx_pk_config_ik {
    /** Key Bundle name */
    uint32_t *key_bundle;

    /** Key Bundle size in 32 bit words
     *
     * If the size is 0 the string
     * is considered NULL and will not be used.
     */
    int key_bundle_sz;

    /** Device Secret */
    uint32_t *device_secret;

    /** Device Secret size in 32 bit words
     *
     * If the size is 0 the Device Secret
     * is considered NULL and will not be used.
     */
    int device_secret_sz;
};

/** Derive the keys inside the IK module
 *
 * Generate the hardware keys inside the IK module.
 * Must be run at least once before any IK operation, when sx_pk_open()
 * has skipped the IK derivation.
 *
 * This function can be run multiple times. Each time it will clear the keys
 * and will derive the keys again.
 *
 * @param[inout] cnx Connection structure obtained through sx_pk_open() at startup
 * @param[in] cfg Configuration to customize IK to application specific needs
 *
 * @return ::SX_OK
 * @return ::SX_ERR_OPERAND_TOO_LARGE
 * @return ::SX_ERR_UNKNOWN_ERROR
 */
int sx_pk_ik_derive_keys(struct sx_pk_cnx *cnx, struct sx_pk_config_ik *cfg);

struct sx_pk_config_rng {
    /** Personalization string */
    uint32_t *personalization;

    /** Personalization string size in 32 bit words
     *
     * If the size is 0 the personalization string
     * is considered NULL and will not be used.
     */
    int personalization_sz;
};

/** Reconfigure internal RNG of IK (advanced)
 *
 * This function shall be called after the key derivation and can be run
 * multiple times. Each time it will change the personalization string
 * for the internal RNG of IK.
 *
 * @remark This is an experimental function and might disappear in
 * newer versions. Normally users can ignore this function and use the default
 * RNG settings.
 *
 * @param[inout] cnx Connection structure obtained through sx_pk_open() at startup
 * @param[in] cfg Rng configuration structure to provide personalization string
 *
 * @return ::SX_OK
 * @return ::SX_ERR_OPERAND_TOO_LARGE when personalization string is too large
 */
int sx_pk_ik_rng_reconfig(struct sx_pk_cnx *cnx,
                            struct sx_pk_config_rng *cfg);

#ifdef __cplusplus
}
#endif

#endif
