/*
 * Copyright (c) 2015-2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== empty.c ========
 */

/* For usleep() */
#include <unistd.h>
#include <stdint.h>
#include <stddef.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/display/Display.h>
#include <ti/display/DisplayUart2.h>
#include <third_party/psa_crypto/include/psa/crypto.h>
#include <ti/drivers/cryptoutils/hsm/HSMLPF3.h>

/* Driver configuration */
#include "ti_drivers_config.h"


Display_Handle handle;
Display_Params d_params;

/** PSA Specific defines **/
#define KEY_BITS 256
#define KEY_TYPE PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)
#define KEY_ALG  PSA_ALG_ECDSA(PSA_ALG_SHA_256)

const uint8_t message[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{
    psa_status_t status;
    int_fast16_t ret;

    Display_Params_init(&d_params);
    handle = Display_open(CONFIG_Display_0, &d_params);

    /** Initialize PSA **/
    status = psa_crypto_init();
    if (status != PSA_SUCCESS)
    {
        /** Error Handling **/
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: Init failed.");
        while(1);
    }

    /** Provision the hardware unique key **/
    ret = HSMLPF3_provisionHUK();
    if (ret != HSMLPF3_STATUS_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: HUK provisioning failed.");
        while(1);
    }

    /**** ECDSA Key Generation ****/
    psa_key_id_t key_id;

    /* To store generated public key */
    uint8_t public_key[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(KEY_BITS)];
    size_t public_key_length = 0;

    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    /* Since we want to sign messages, we need PSA_KEY_USAGE_SIGN_HASH */
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);

    /* We are using these keys for ECDSA, and the hashing algorithm used is SHA-256 */
    psa_set_key_algorithm(&attributes, KEY_ALG);

    /* This is where we are setting out curve */
    psa_set_key_type(&attributes, KEY_TYPE);

    /* This is the bit size of the hash algorithm we are using (SHA-256) */
    psa_set_key_bits(&attributes, KEY_BITS);

    /* This will generate our key */
    status = psa_generate_key(&attributes, &key_id);
    if (status != PSA_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: Key generation failed. %d", status);
        while(1);
    }

    /* Now we want to export our PUBLIC key */
    status = psa_export_public_key(key_id, public_key, sizeof(public_key), &public_key_length);
    if (status != PSA_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: export failed. %d", status);
        while(1);
    }

    /**** ECDSA Key Generation Done ****/

    /**** ECDSA Signing ****/
    /** Our buffer to hold the signature **/
    uint8_t signature[PSA_SIGN_OUTPUT_SIZE(KEY_TYPE, KEY_BITS, KEY_ALG)];
    size_t signature_length = 0;

    status = psa_sign_message(key_id,
                              KEY_ALG,
                              message,
                              6,
                              signature,
                              PSA_SIGN_OUTPUT_SIZE(KEY_TYPE, KEY_BITS, KEY_ALG),
                              &signature_length);

    if (status != PSA_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: sign failed. %d", status);
        while(1);
    }
    /**** ECDSA Signing Done ****/

    /**** Import ECDSA Public Key ****/
    psa_key_id_t p_key_id = PSA_KEY_ID_USER_MIN + 1;
    psa_key_attributes_t p_attributes = PSA_KEY_ATTRIBUTES_INIT;

    /* the public key is used to verify */
    psa_set_key_usage_flags(&p_attributes, PSA_KEY_USAGE_VERIFY_HASH);

    /* We are using these keys for ECDSA, and the hashing algorithm used is SHA-256 */
    psa_set_key_algorithm(&p_attributes, KEY_ALG);

    /* This is where we are setting out curve */
    psa_set_key_type(&p_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

    /* Key bits of the curve type */
    psa_set_key_bits(&p_attributes, KEY_BITS);

    status = psa_import_key(&p_attributes, public_key, public_key_length, &p_key_id);

    if (status != PSA_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: import public key failed. %d", status);
        while(1);
    }
    /**** Import ECDSA Public Key Done ****/

    /**** Verify message ****/
    status = psa_verify_message(p_key_id,
                              KEY_ALG,
                              message,
                              6,
                              signature,
                              signature_length);

    if (status != PSA_SUCCESS)
    {
        Display_printf(handle, 0, DisplayUart2_SCROLLING, "PSA: Verify failed. %d", status);
        while(1);
    }
    /**** Verify message done ****/

    GPIO_write(GREEN_LED, 1);
    while(1);
}


































