#include "hcu_cases.h"
#include "trng_driver.h"

#define ECC_USE_SECP256K1   (1)
#define ECC_USE_SECP256R1   (0)

#if ECC_USE_SECP256K1
/*
SECP256-K1
a = 0x0000000000000000000000000000000000000000000000000000000000000000
b = 0x0000000000000000000000000000000000000000000000000000000000000007
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
*/
/* SECP256K1 parameter */
static const hcu_ecc_config_t secp256k1 = {
    .opLength = ECC_P_256,
    .a = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
    .b = {0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
    .p = {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, },
    .gx = {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E,},
    .gy = {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77,},
    .n = {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, }
};

/* public key generate by private with SECP256K1 */
static const uint32_t publicKey_k1[16] = {
    0xF6D84F2D, 0x6148E3C5, 0xB6CCBDA3, 0x3D70A802, 0x770E46F7, 0x93A0AE32, 0xAFBB46CD, 0xA7ED61A4, 
    0x26FD2A3F, 0x19EAD2DF, 0x8CE917EB, 0x79A5C72F, 0x490AD331, 0xC8086BB9, 0xE56B0842, 0xAEA15B46, 
};

/* signature pair (r, s) by K of SECP256K1 */
static const uint32_t signature_k1[16] = {
    0xB53F3FF9, 0x7B1CEE7E, 0x74719881, 0x1B2C1ABC, 0x4C61B90D, 0xD0A9A10C, 0xE795FD46, 0x62581565, 
    0xC3C95659, 0xA3E76335, 0xFAADB6BE, 0x3B0D3C05, 0xF885F69D, 0xC50F3730, 0x549A2B84, 0xCCCB94E7, 
};
#endif /* ECC_USE_SECP256K1 */

#if ECC_USE_SECP256R1
/*
# secp256-r1
p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
Gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296
Gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
*/
/* SECP256R1 parameter */
static const hcu_ecc_config_t secp256r1 = {
    .opLength = ECC_P_256,
    .a = {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF, },
    .b = {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8, },
    .p = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF, },
    .gx = {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2,},
    .gy = {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2,},
    .n = {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, }
};

/* public key generate by private with SECP256R1 */
static const uint32_t publicKey_r1[16] = {
    0xD27178D3, 0xAE470C5D, 0x38681354, 0x336D7609, 0x7F9922C8, 0xC277F164, 0x1DBE3F08, 0x71EB2054, 
    0x51F9AE0F, 0xD02EE9DD, 0xA8E8E86B, 0xAC7DA342, 0xE0AA42AC, 0x66AE6994, 0x8CC20FBA, 0x2E12FE24, 
};

/* signature pair (r, s) by K of SECP256R1 */
static const uint32_t signature_r1[16] = {
    0x61756E4D, 0x864D2F9D, 0x6EB49CE6, 0xA7064260, 0xD392DD4D, 0x03A75B63, 0x7B1A3CB6, 0x55473B84, 
    0xAF66E3E8, 0x01F45058, 0xB498316E, 0xA6C5458A, 0xC5F6D899, 0x17C782E3, 0x3322436B, 0x613A3C83, 
};
#endif /* ECC_USE_SECP256R1 */

static const uint32_t privateKey[8] = {
    0x0C83ED7A, 0xC4CACE34, 0xD1104E2A, 0x47EC5B82, 0xDA4C7BE8, 0x4B5A50F4, 0x9D2A92A8, 0x480E97ED,  
};

/* generate by TRNG and used for signature generated */
static const uint32_t k[8] = {
    0x953B3859, 0x433AA2B0, 0x95D1E7BC, 0x0A74A206, 0x2B774C97, 0xE8CB86D6, 0x2B837A17, 0xA68B002F, 
};

/* Message to encrypt */
static const uint32_t message[16] = { 
    0x6bc1bee2, 0x2e409f96, 0xe93d7e11, 0x7393172a,
    0xae2d8a57, 0x1e03ac9c, 0x9eb76fac, 0x45af8e51,
    0x30c81c46, 0xa35ce411, 0xe5fbc119, 0x1a0a52ef,
    0xf69f2445, 0xdf4f9b17, 0xad2b417b, 0xe66c3710
};

/* store public key */
static uint32_t pb_key_x[8];
static uint32_t pb_key_y[8];
static hcu_ecc_point_t point_public_key = {pb_key_x, pb_key_y};
/* store hash result */
static uint32_t hashResult[8];
/* store signature R, S */
static uint32_t R[8], S[8];
static hcu_ecdsa_config_t ecdsaCfg = {
    .privateKey = privateKey,
    .publicKey = &point_public_key,
    .K = k,
    .shaType = HCU_SHA_256,
    .msgLen = 64,
    .message = message,
    .hashResult = hashResult,
    .R = R,
    .S = S,
};

/* random K generate by TRNG */
static uint32_t randomK[8];

static pke_user_config_t pkeUserConfig;

static pke_state_t pkeState;

static status_t status = STATUS_SUCCESS;

/* if A >= B, return true */
static bool CompareValue(const uint32_t *valueA, const uint32_t *valueB, uint32_t wordLen)
{
    for(uint32_t i = wordLen - 1; i > 0; i--)
    {
        if(valueA[i] > valueB[i])
        {
            return true;
        }
        if (valueA[i] < valueB[i]) 
        {
            return false;
        }
    }
    return true;
}

static void checkResult(const uint32_t *expected, const uint32_t *actual, uint32_t length)
{
    for (uint32_t i = 0; i < length; i++)
    {
        if (expected[i] != actual[i])
        {
            PRINTF("Expected[%zu]: 0x%08X, Actual[%zu]: 0x%08X\r\n", i, expected[i], i, actual[i]);
        }
    }
}

void hcu_ecdsa_demo(void)
{
#if ECC_USE_SECP256K1
    pkeUserConfig.eccConfig = &secp256k1;
    /* PKE init */
    PKE_DRV_Init(&pkeUserConfig, &pkeState);

    PRINTF("SECP256K1 ECDSA generate signature use specified K.\r\n");
    status |= HCU_DRV_ECDSA_GenerateSignature(&ecdsaCfg);
    PRINTF("Check public key!\r\n");
    checkResult(publicKey_k1, pb_key_x, 8);
    checkResult(&publicKey_k1[8], pb_key_y, 8);
    PRINTF("Check signature (r, s)\r\n");
    checkResult(signature_k1, R, 8);
    checkResult(&signature_k1[8], S, 8);

    PRINTF("SECP256K1 ECDSA verify signature.\r\n");
    ecdsaCfg.privateKey = NULL;
    ecdsaCfg.K = NULL;
    status |= HCU_DRV_ECDSA_VerifySignature(&ecdsaCfg);
    if(status != STATUS_SUCCESS)
    {
        PRINTF("SECP256K1 ECDSA verify signature FAIL.\r\n");
    }else {
        PRINTF("SECP256K1 ECDSA verify signature PASS.\r\n");
    }

    PRINTF("SECP256K1 ECDSA generate signature use random K.\r\n");
    while(1)
    {
        /* Generate random K and check less than N */
        TRNG_DRV_Get_Ent(0, &randomK[0]);
        while(STATUS_SUCCESS != TRNG_DRV_GetStatus(0));
        TRNG_DRV_Get_Ent(0, &randomK[4]);
        while(STATUS_SUCCESS != TRNG_DRV_GetStatus(0));
        if(CompareValue(randomK, secp256k1.n, 8) == false)
        {
            break;
        }
    }
    ecdsaCfg.privateKey = privateKey;
    ecdsaCfg.K = randomK;
    status |= HCU_DRV_ECDSA_GenerateSignature(&ecdsaCfg);

    PRINTF("SECP256K1 ECDSA verify signature.\r\n");
    ecdsaCfg.privateKey = NULL;
    ecdsaCfg.K = NULL;
    status |= HCU_DRV_ECDSA_VerifySignature(&ecdsaCfg);
    if(status != STATUS_SUCCESS)
    {
        PRINTF("SECP256K1 ECDSA verify signature FAIL.\r\n");
    }else {
        PRINTF("SECP256K1 ECDSA verify signature PASS.\r\n");
    }

    PKE_DRV_DeInit(&pkeState);
#endif /* ECC_USE_SECP256K1 */

#if ECC_USE_SECP256R1
    pkeUserConfig.eccConfig = &secp256r1;
    /* PKE init */
    PKE_DRV_Init(&pkeUserConfig, &pkeState);
    PRINTF("SECP256R1 ECDSA generate signature use specified K.\r\n");
    ecdsaCfg.privateKey = privateKey;
    ecdsaCfg.K = k;
    status |= HCU_DRV_ECDSA_GenerateSignature(&ecdsaCfg);
    PRINTF("Check public key!\r\n");
    checkResult(publicKey_r1, pb_key_x, 8);
    checkResult(&publicKey_r1[8], pb_key_y, 8);
    PRINTF("Check signature (r, s)\r\n");
    checkResult(signature_r1, R, 8);
    checkResult(&signature_r1[8], S, 8);

    PRINTF("SECP256R1 ECDSA verify signature.\r\n");
    ecdsaCfg.privateKey = NULL;
    ecdsaCfg.K = NULL;
    status |= HCU_DRV_ECDSA_VerifySignature(&ecdsaCfg);
    if(status != STATUS_SUCCESS)
    {
        PRINTF("SECP256R1 ECDSA verify signature FAIL.\r\n");
    }else {
        PRINTF("SECP256R1 ECDSA verify signature PASS.\r\n");
    }

    PRINTF("SECP256R1 ECDSA generate signature use random K.\r\n");
    while(1)
    {
        /* Generate random K and check less than N */
        TRNG_DRV_Get_Ent(0, &randomK[0]);
        while(STATUS_SUCCESS != TRNG_DRV_GetStatus(0));
        TRNG_DRV_Get_Ent(0, &randomK[4]);
        while(STATUS_SUCCESS != TRNG_DRV_GetStatus(0));
        if(CompareValue(randomK, secp256r1.n, 8) == false)
        {
            break;
        }
    }
    ecdsaCfg.privateKey = privateKey;
    ecdsaCfg.K = randomK;
    status |= HCU_DRV_ECDSA_GenerateSignature(&ecdsaCfg);

    PRINTF("SECP256R1 ECDSA verify signature.\r\n");
    ecdsaCfg.privateKey = NULL;
    ecdsaCfg.K = NULL;
    status |= HCU_DRV_ECDSA_VerifySignature(&ecdsaCfg);
    if(status != STATUS_SUCCESS)
    {
        PRINTF("SECP256R1 ECDSA verify signature FAIL.\r\n");
    }else {
        PRINTF("SECP256R1 ECDSA verify signature PASS.\r\n");
    }

    PKE_DRV_DeInit(&pkeState);
#endif /* ECC_USE_SECP256R1 */
}
