/*
 * Copyright (c) 2023 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-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[in,out] 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[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_config_ik *cfg);

/** Exit IK mode.
 *
 * @param[in,out] cnx Connection structure obtained through sx_pk_open() at
 * startup
 *
 * @return Any \ref SX_PK_STATUS "status code"
 */
int sx_pk_ik_mode_exit(struct sx_pk_cnx *cnx);

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[in,out] 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
