/*
 *  Copyright 2020-2023 Yuntu Microelectronics co.,ltd
 *  All rights reserved.
 *
 *  YUNTU Confidential. This software is owned or controlled by YUNTU and may only be
 *  used strictly in accordance with the applicable license terms. By expressly
 *  accepting such terms or by downloading, installing, activating and/or otherwise
 *  using the software, you are agreeing that you have read, and that you agree to
 *  comply with and are bound by, such license terms. If you do not agree to be
 *  bound by the applicable license terms, then you may not retain, install,
 *  activate or otherwise use the software. The production use license in
 *  Section 2.3 is expressly granted for this software.
 *
 * @file ECDSA_example.c
 * @brief This is an example of how to use the ECDSA signature and verification functions with the PSA layer.
 *
 */

#include <stddef.h>
#ifdef __cplusplus
extern "C"
{
#endif

/*==================================================================================================
                                              INCLUDE FILES
==================================================================================================*/
#include "ECDSA_example.h"
#include "psa/crypto.h"
#include "common.h"
#include "printf.h"

#include "psa_util.h"
// #include "SHA256_hash.h"
// #include "YTM32B1MD1.h"
#include "pins_driver.h"
#define USED_THIRD_PARTY_TOOL_GENERATED_KEYS        1              // (1-使用第三方工具生成密钥; 0-使用本工程中的ECDSA_key_generate函数生成密钥)
/*==================================================================================================
                                                LOCAL VARIABLES
==================================================================================================*/
#include "sdk_project_config.h"
/* The private key with 256R1 curve */
//Private Key：ec754e90d89ed89aa859ea68f51badfacc1c9cd336f30a0cd742fd1a8cdf34be
//Public Key：04735cea0069a4c81c54556c965644b21aa093bdaf160b39a2253fda30f34486863e0edbc0c89a1f74a1b37aeee7dbe21649e0e5c24d0babc680daf1ab70361591

static const uint8_t ECDSA_private_key[] =
{
    0xEC, 0x75, 0x4E, 0x90, 0xD8, 0x9E, 0xD8, 0x9A, 0xA8, 0x59, 0xEA, 0x68, 0xF5, 0x1B, 0xAD, 0xFA, 0xCC, 0x1C, 0x9C, 0xD3, 0x36, 0xF3, 0x0A, 0x0C, 0xD7, 0x42, 0xFD, 0x1A, 0x8C, 0xDF, 0x34, 0xBE
};

/* The public key with 256R1 curve */
static const uint8_t ECDSA_public_key[] =
{
    0x04, 0x73, 0x5C, 0xEA, 0x00, 0x69, 0xA4, 0xC8, 0x1C, 0x54, 0x55, 0x6C,
    0x96, 0x56, 0x44, 0xB2, 0x1A, 0xA0, 0x93, 0xBD, 0xAF, 0x16, 0x0B, 0x39,
    0xA2, 0x25, 0x3F, 0xDA, 0x30, 0xF3, 0x44, 0x86, 0x86, 0x3E, 0x0E, 0xDB,
    0xC0, 0xC8, 0x9A, 0x1F, 0x74, 0xA1, 0xB3, 0x7A, 0xEE, 0xE7, 0xDB, 0xE2,
    0x16, 0x49, 0xE0, 0xE5, 0xC2, 0x4D, 0x0B, 0xAB, 0xC6, 0x80, 0xDA, 0xF1, 0xAB, 0x70, 0x36, 0x15, 0x91
};

uint8_t signature_data_upper_der[] = {
    0x30, 0x46, 0x02, 0x21, 0x00, 0xCD, 0x55, 0x24, 0xBD, 0x64, 0x25, 0x2D, 0x2F, 0x0D, 0x84, 0xEC, 0x49, 0x4C, 0x05, 0xF4, 0x43, 0x05, 0x46, 0xAF, 0x2C, 0xBE, 0xE4, 0x8E, 0x11, 0x9A, 0xE5, 0x7B, 0x1D, 0xA0, 0x70, 0x77, 0x08, 0x02, 0x21, 0x00, 0xBA, 0x44, 0xBD, 0x45, 0xA5, 0x96, 0x60, 0x7F, 0x30, 0xCF, 0x19, 0x9D, 0xB7, 0xA3, 0xC0, 0x30, 0xA6, 0x3C, 0xBC, 0x8C, 0xAF, 0xC3, 0x0A, 0x43, 0x35, 0xAE, 0xA9, 0x58, 0xDF, 0x62, 0x8C, 0xFD
};

uint8_t signature_data[64] =
{
    // 0x91, 0x27, 0x9a, 0xd9, 0xba, 0xfc, 0x95, 0x3a, 0xf8, 0xfc, 0x48, 0x83, 0x6d, 0xca, 0x12, 0x16,
    // 0x17, 0x64, 0x40, 0x5a, 0xc3, 0x6d, 0xff, 0xc8, 0xc4, 0x25, 0x5a, 0x50, 0xe4, 0x0d, 0x02, 0xa1,
    // 0x1c, 0xc7, 0x0f, 0x09, 0x0d, 0x2a, 0x65, 0xb8, 0xe2, 0x48, 0xf2, 0x59, 0x10, 0x02, 0x39, 0x42,
    // 0xec, 0x51, 0xa8, 0x5b, 0x4b, 0x94, 0x5d, 0xfb, 0x53, 0x4b, 0x36, 0x45, 0x92, 0x03, 0x5c, 0xb4

    //Flash全FF，sha256后的签名
    0x22, 0x70, 0x8A, 0xD4, 0x5C, 0x86, 0x38, 0x75, 0x4D, 0x4E, 0xB1, 0x0D, 0x01, 0x14, 0xC7, 0x0C, 0x26, 0x73, 0x48, 0x48, 0x4D, 0x04, 0xB1, 0xF9, 0x22, 0x14, 0xD1, 0x55, 0x83, 0x4B, 0x13, 0xE8,
    0x55, 0x68, 0xD7, 0xFE, 0x91, 0x30, 0x31, 0xCA, 0x92, 0x0B, 0xEC, 0x15, 0x91, 0x6C, 0xAB, 0xBA, 0x4E, 0x55, 0x9B, 0x98, 0x2A, 0xD3, 0xA6, 0x43, 0x76, 0xAA, 0xCC, 0xE0, 0x7F, 0x8E, 0xC5, 0x96
};


unsigned char my_signature[] = {
    0x30, 0x44, 0x02, 0x20, 0x22, 0x70, 0x8A, 0xD4, 0x5C, 0x86, 0x38, 0x75, 0x4D, 0x4E, 0xB1, 0x0D, 0x01, 0x14, 0xC7, 0x0C, 0x26, 0x73, 0x48, 0x48, 0x4D, 0x04, 0xB1, 0xF9, 0x22, 0x14, 0xD1, 0x55, 0x83, 0x4B, 0x13, 0xE8, 0x02, 0x20, 0x55, 0x68, 0xD7, 0xFE, 0x91, 0x30, 0x31, 0xCA, 0x92, 0x0B, 0xEC, 0x15, 0x91, 0x6C, 0xAB, 0xBA, 0x4E, 0x55, 0x9B, 0x98, 0x2A, 0xD3, 0xA6, 0x43, 0x76, 0xAA, 0xCC, 0xE0, 0x7F, 0x8E, 0xC5, 0x96
};
/* The message to be signed */
uint8_t message[32] = {0};

/*==================================================================================================
                                          LOCAL FUNCTION
==================================================================================================*/
/**
 * @brief ECDSA signature test.
 *
 * @return int The result of the test.
 * @retval 0: The test succeeded.
 * @retval other status: The test failed.
 */
static int ECDSA_sing_test()
{
    psa_status_t status;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id = 0;
    uint8_t signature[512] = {0};
    size_t signature_length;

    //Set Key Attributes for Importing an ECDSA Private Key
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attributes, 256);

    /* Import the ECDSA Private Key*/
    status = psa_import_key(&attributes, ECDSA_private_key, sizeof(ECDSA_private_key), &key_id);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Key import failed! (status = %d)\n\r", status);
        return status;
    }
    /* Sign the message*/
    status = psa_sign_message(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), message, sizeof(message), signature, sizeof(signature), &signature_length);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Signature failed! (status = %d)\n\r", status);
        return status;
    }

    PRINTF("Signature length: %d\n\r", signature_length);
    print_buf("Signature", signature, signature_length);

    /* Destroy the key*/
    psa_destroy_key(key_id);
    return 0;
}

static int ECDSA_verify_hash_test()
{
    psa_status_t status;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id = 0;

    size_t der_length = 0;

    //Set Key Attributes for Importing an ECDSA Public Key
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attributes, 256);

    /* Import the ECDSA Public Key*/
    status = psa_import_key(&attributes, ECDSA_public_key, sizeof(ECDSA_public_key), &key_id);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Key import failed! (status = %d)\n\r", status);
        return status;
    }
    PRINTF("Message length: %d\n\r", sizeof(message));
    print_buf("Message to be verified is", message, sizeof(message));

    // #if USED_THIRD_PARTY_TOOL_GENERATED_KEYS
    //������һ��������ʾ��Բ���ߵ�λ����
    mbedtls_ecdsa_der_to_raw(256, signature_data_upper_der, sizeof(signature_data_upper_der),
                            signature_data, 256, &der_length);
    // #endif


    /* Verify the message*/
    GPIOE -> PSOR = 1 << 23;
    status = psa_verify_message(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), message, sizeof(message), signature_data, sizeof(signature_data));
    GPIOE -> PCOR = 1 << 23;
    if (status != PSA_SUCCESS)
    {
        PRINTF("Signature verification failed! (status = %d)\n\r", status);
        return status;
    }

    PRINTF("Signature verification succeeded!\n\r");

    /* Destroy the key*/
    psa_destroy_key(key_id);
    return 0;
}

/*==================================================================================================
                                          GLOBAL FUNCTIONS
==================================================================================================*/
/**
 * @brief Generate an ECDSA key pair.
 *
 * @param[in] key_length The length of the key. the key size is supported by the specific curves within the Elliptic Curve
 *
 * @return int The result of the test.
 * @retval 0 The test succeeded.
 * @retval othe status The test failed.
 */
int ECDSA_key_generate(uint32_t key_length)
{
    psa_status_t status;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id = 0;
    size_t output_length;
    uint8_t public_key[128];
    uint8_t private_key[128];

    /* Set key attributes for ECC*/
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_EXPORT);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attributes, key_length);

    /* Generate the key pair*/
    status = psa_generate_key(&attributes, &key_id);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Key generation failed! (status = %d)\n\r", status);
        return status;
    }

    /* Export the public key*/
    status = psa_export_public_key(key_id, public_key, sizeof(public_key), &output_length);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Public key export failed! (status = %d)\n\r", status);
        return status;
    }

    PRINTF("Public key length: %d\n\r", output_length);
    print_buf("Public key", public_key, output_length);

    /* Export the private key*/
    status = psa_export_key(key_id, private_key, sizeof(private_key), &output_length);
    if (status != PSA_SUCCESS)
    {
        PRINTF("Private key export failed! (status = %d)\n\r", status);
        return status;
    }

    PRINTF("Private key length: %d\n\r", output_length);
    print_buf("Private key", private_key, output_length);

    /* Destroy the key*/
    psa_destroy_key(key_id);
    return 0;
}

/**
 * @brief ECDSA sign and verify test.
 *
 * @return int The result of the test.
 * @retval 0 The test succeeded.
 * @retval -1 The test failed.
 */
int ECDSA_sign_verify_test()
{
#if (USED_THIRD_PARTY_TOOL_GENERATED_KEYS == 0)
    PRINTF("\nMbedTLS ECDSA Sign Test:\n\r");
    if (ECDSA_sing_test() == 0)
    {
        PRINTF("ECDSA sign test succeeded!\n\r");
    }
    else
    {
        PRINTF("ECDSA sign test failed!\n\r");
        return -1;
    }
#else
    PRINTF("\nMbedTLS ECDSA Verify Test:\n\r");
#endif
    if (ECDSA_verify_hash_test() == 0)
    {
        PRINTF("ECDSA verify test succeeded!\n\r");
    }
    else
    {
        PRINTF("ECDSA verify test failed!\n\r");
        return -1;
    }

    return 0;
}

#ifdef __cplusplus
}
#endif

/* End of file ECDSA_example.c */
