2438 lines
80 KiB
C
2438 lines
80 KiB
C
/**
|
|
* @file pke.c
|
|
* @brief Semidrive CRYPTO pke source file.
|
|
*
|
|
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "pke.h"
|
|
|
|
#include "sdrv_crypto_utility.h"
|
|
#include "trng.h"
|
|
|
|
static uint32_t g_oper_step;
|
|
|
|
/* function: get pke IP version
|
|
* parameters: none
|
|
* return: pke IP version
|
|
* caution:
|
|
*/
|
|
uint32_t pke_get_version(void) { return PKE_VERSION; }
|
|
|
|
/* function: load input operand to baseaddr
|
|
* parameters:
|
|
* baseaddr ------------------- output, destination data
|
|
* data ----------------------- input, source data
|
|
* wordlen -------------------- input, word length of data
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_load_operand(uint32_t *baseaddr, uint32_t *data, uint32_t wordlen)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (baseaddr != data) {
|
|
for (i = 0; i < wordlen; i++) {
|
|
*((volatile uint32_t *)baseaddr + i) = data[i];
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
|
|
/* function: get result operand from baseaddr
|
|
* parameters:
|
|
* baseaddr ------------------- input, source data
|
|
* data ----------------------- output, destination data
|
|
* wordlen -------------------- input, word length of data
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_read_operand(uint32_t *baseaddr, uint32_t *data, uint32_t wordlen)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (baseaddr != data) {
|
|
for (i = 0; i < wordlen; i++) {
|
|
data[i] = *((volatile uint32_t *)baseaddr + i);
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
|
|
/* function: clear finished and interrupt tag
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_clear_interrupt(void) { PKE_RISR &= ~0x1; }
|
|
|
|
/* function: enable pke interrupt
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_enable_interrupt(void)
|
|
{
|
|
PKE_CFG |= (((uint32_t)1) << PKE_INT_ENABLE_OFFSET);
|
|
}
|
|
|
|
/* function: disable pke interrupt
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_disable_interrupt(void)
|
|
{
|
|
PKE_CFG &= ~(((uint32_t)1) << PKE_INT_ENABLE_OFFSET);
|
|
}
|
|
|
|
/* function: set operand width
|
|
* parameters:
|
|
* bitlen --------------------- input, bit length of operand
|
|
* return: none
|
|
* caution: please make sure 0 < bitlen <= OPERAND_MAX_BIT_LEN
|
|
*/
|
|
void pke_set_operand_width(uint32_t bitlen)
|
|
{
|
|
uint32_t cfg, len;
|
|
|
|
len = (bitlen + 255) / 256;
|
|
|
|
if (1 == len) {
|
|
cfg = 2;
|
|
g_oper_step = 0x20;
|
|
} else if (2 == len) {
|
|
cfg = 3;
|
|
g_oper_step = 0x40;
|
|
} else if (len <= 4) {
|
|
cfg = 4;
|
|
g_oper_step = 0x80;
|
|
} else if (len <= 8) {
|
|
cfg = 5;
|
|
g_oper_step = 0x100;
|
|
} else if (len <= 16) {
|
|
cfg = 6;
|
|
g_oper_step = 0x200;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
cfg = (cfg << 16) | (len << 8);
|
|
|
|
PKE_CFG &= ~(0x07FFFF);
|
|
PKE_CFG |= cfg;
|
|
}
|
|
|
|
/* function: get current operand byte length
|
|
* parameters: none
|
|
* return: current operand byte length
|
|
* caution: none
|
|
*/
|
|
uint32_t pke_get_operand_bytes(void) { return g_oper_step; }
|
|
|
|
/* function: set operation micro code
|
|
* parameters:
|
|
* addr ----------------------- input, specific micro code
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_set_microcode(uint32_t addr) { PKE_MC_PTR = addr; }
|
|
|
|
/* function: start pke calc
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_start(void) { PKE_CTRL |= PKE_START_CALC; }
|
|
|
|
/* function: return calc return code
|
|
* parameters: none
|
|
* return 0(success), other(error)
|
|
* caution:
|
|
*/
|
|
uint32_t pke_check_rt_code(void) { return (uint8_t)(PKE_RT_CODE & 0x07); }
|
|
|
|
/* function: wait till done
|
|
* parameters: none
|
|
* return: none
|
|
* caution:
|
|
*/
|
|
void pke_wait_till_done(void)
|
|
{
|
|
while (!(PKE_RISR & 0x1)) {
|
|
;
|
|
}
|
|
}
|
|
|
|
/* function: set operation micro code, start hardware, wait till done, and
|
|
* return code parameters: micro_code ----------------- input, specific micro
|
|
* code return: PKE_SUCCESS(success), other(inverse not exists or error)
|
|
* caution:
|
|
*/
|
|
uint32_t pke_set_micro_code_start_wait_return_code(uint32_t micro_code)
|
|
{
|
|
pke_set_microcode(micro_code);
|
|
|
|
pke_clear_interrupt();
|
|
|
|
pke_start();
|
|
|
|
pke_wait_till_done();
|
|
|
|
return pke_check_rt_code();
|
|
}
|
|
|
|
/* function: ainv = a^(-1) mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* ainv ----------------------- output, ainv = a^(-1) mod modulus
|
|
* modwordlen ----------------- input, word length of modulus and ainv
|
|
* awordlen ------------------- input, word length of a
|
|
* return: PKE_SUCCESS(success), other(inverse not exists or error)
|
|
* caution:
|
|
* 1. please make sure awordlen <= modwordlen <= OPERAND_MAX_WORD_LEN and a
|
|
* < modulus
|
|
*/
|
|
uint32_t pke_modinv(const uint32_t *modulus, const uint32_t *a, uint32_t *ainv,
|
|
uint32_t modwordlen, uint32_t awordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(modwordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
modwordlen);
|
|
|
|
if ((g_oper_step / 4) > modwordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + modwordlen,
|
|
(g_oper_step / 4) - modwordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)a,
|
|
awordlen);
|
|
|
|
if ((g_oper_step / 4) > awordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + awordlen,
|
|
(g_oper_step / 4) - awordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_MODINV);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), modwordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), awordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), modwordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), ainv, modwordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: out = (a+b) mod modulus or out = (a-b) mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a+b mod modulus or out = (a-b)
|
|
* mod modulus wordlen -------------------- input, word length of modulus, a, b
|
|
* micro_code ----------------- input, must be MICROCODE_MODADD or
|
|
* MICROCODE_MODSUB return: PKE_SUCCESS(success), other(error) caution:
|
|
* 1. a,b must be less than modulus
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modadd_modsub_internal(const uint32_t *modulus, const uint32_t *a,
|
|
const uint32_t *b, uint32_t *out,
|
|
uint32_t wordlen, uint32_t micro_code)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), (uint32_t *)a,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)b,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(micro_code);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: out = (a+b) mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a+b mod modulus
|
|
* wordlen -------------------- input, word length of modulus, a, b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. a,b must be less than modulus
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modadd(const uint32_t *modulus, const uint32_t *a,
|
|
const uint32_t *b, uint32_t *out, uint32_t wordlen)
|
|
{
|
|
return pke_modadd_modsub_internal(modulus, a, b, out, wordlen,
|
|
MICROCODE_MODADD);
|
|
}
|
|
|
|
/* function: out = (a-b) mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a-b mod modulus
|
|
* wordlen -------------------- input, word length of modulus, a, b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. a,b must be less than modulus
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modsub(const uint32_t *modulus, const uint32_t *a,
|
|
const uint32_t *b, uint32_t *out, uint32_t wordlen)
|
|
{
|
|
return pke_modadd_modsub_internal(modulus, a, b, out, wordlen,
|
|
MICROCODE_MODSUB);
|
|
}
|
|
|
|
/* function: out = a+b or out = a-b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a+b or out = a-b
|
|
* wordlen -------------------- input, word length of a, b, out
|
|
* micro_code ----------------- input, must be MICROCODE_INTADD or
|
|
* MICROCODE_INTSUB return: PKE_SUCCESS(success), other(error) caution:
|
|
* 1. if a+b output may overflow, if a-b please make sure a > b
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_add_sub_internal(const uint32_t *a, const uint32_t *b,
|
|
uint32_t *out, uint32_t wordlen,
|
|
uint32_t micro_code)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), (uint32_t *)a,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)b,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(micro_code);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: out = a+b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a+b
|
|
* wordlen -------------------- input, word length of a, b, out
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. a+b may overflow
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_add(const uint32_t *a, const uint32_t *b, uint32_t *out,
|
|
uint32_t wordlen)
|
|
{
|
|
return pke_add_sub_internal(a, b, out, wordlen, MICROCODE_INTADD);
|
|
}
|
|
|
|
/* function: out = a-b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a-b
|
|
* wordlen -------------------- input, word length of a, b, out
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure a > b
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_sub(const uint32_t *a, const uint32_t *b, uint32_t *out,
|
|
uint32_t wordlen)
|
|
{
|
|
return pke_add_sub_internal(a, b, out, wordlen, MICROCODE_INTSUB);
|
|
}
|
|
|
|
/* function: out = a*b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* a_wordlen ------------------ input, word length of a
|
|
* b -------------------------- input, integer b
|
|
* b_wordlen ------------------ input, word length of b
|
|
* out ------------------------ output, out = a*b
|
|
* out_wordlen----------------- input, word length of out
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure out buffer word length is bigger than
|
|
* (2*max_bit_len(a,b)+0x1F)>>5
|
|
* 2. please make sure ab_wordLen is not bigger than OPERAND_MAX_WORD_LEN/2
|
|
*/
|
|
uint32_t pke_mul_internal(const uint32_t *a, const uint32_t *b, uint32_t *out,
|
|
uint32_t a_wordlen, uint32_t b_wordlen,
|
|
uint32_t out_wordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(GET_MAX_LEN(out_wordlen << 5, 512));
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), (uint32_t *)a,
|
|
a_wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)b,
|
|
b_wordlen);
|
|
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + a_wordlen,
|
|
(g_oper_step / 4) - a_wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + b_wordlen,
|
|
(g_oper_step / 4) - b_wordlen);
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_INTMUL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), a_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), b_wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, out_wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: out = a*b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a*b
|
|
* wordlen -------------------- input, word length of a, b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure out buffer word length is bigger than
|
|
* (2*max_bit_len(a,b)+0x1F)>>5
|
|
* 2. please make sure ab_wordLen is not bigger than OPERAND_MAX_WORD_LEN/2
|
|
*/
|
|
uint32_t pke_mul(const uint32_t *a, const uint32_t *b, uint32_t *out,
|
|
uint32_t ab_wordLen)
|
|
{
|
|
uint32_t bitlen, tempLen;
|
|
|
|
bitlen = get_valid_bits(a, ab_wordLen);
|
|
tempLen = get_valid_bits(b, ab_wordLen);
|
|
|
|
bitlen = GET_MAX_LEN(bitlen, tempLen);
|
|
tempLen = GET_WORD_LEN(bitlen << 1);
|
|
|
|
if (tempLen < (ab_wordLen << 1)) {
|
|
tempLen = (ab_wordLen << 1) - 1;
|
|
} else {
|
|
tempLen = (ab_wordLen << 1);
|
|
}
|
|
|
|
return pke_mul_internal(a, b, out, ab_wordLen, ab_wordLen, tempLen);
|
|
}
|
|
|
|
/* function: calc n0(- modulus ^(-1) mod 2^w) for modMul, and pointMul. etc.
|
|
* parameters: none
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. before calling, please make sure the modulus is set in PKE_A(a, 0)
|
|
* 2. please make sure the modulus is odd, and word length of the modulus
|
|
* is not bigger than OPERAND_MAX_WORD_LEN
|
|
* 3. the result is set in the internal register, no need to output.
|
|
*/
|
|
uint32_t pke_pre_calc_mont_N0(void)
|
|
{
|
|
pke_set_microcode(MICROCODE_MGMR_PRE_N0);
|
|
|
|
pke_clear_interrupt();
|
|
|
|
pke_start();
|
|
|
|
pke_wait_till_done();
|
|
|
|
return pke_check_rt_code();
|
|
}
|
|
|
|
/* function: calc H(R^2 mod modulus) for modMul, and pointMul. etc.
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* bitlen --------------------- input, bit length of modulus
|
|
* H -------------------------- output, R^2 mod modulus
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. modulus must be odd
|
|
* 2. please make sure word length of buffer H is equal to word length of
|
|
* modulus
|
|
* 3. bitlen must not be bigger than OPERAND_MAX_BIT_LEN
|
|
*/
|
|
uint32_t pke_pre_calc_mont(const uint32_t *modulus, uint32_t bitlen,
|
|
uint32_t *H)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(bitlen);
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(bitlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
if (256 == bitlen || 512 == bitlen || 1024 == bitlen || 2048 == bitlen ||
|
|
4096 == bitlen) {
|
|
ret =
|
|
pke_set_micro_code_start_wait_return_code(MICROCODE_MGMR_PRE_H_MM);
|
|
} else {
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_MGMR_PRE_H);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(0, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else if (NULL != H) {
|
|
pke_read_operand((uint32_t *)(PKE_B(0, g_oper_step)), H, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: like function pke_pre_calc_mont(), but this one is without output
|
|
* here parameters: modulus -------------------- input, modulus wordlen
|
|
* -------------------- input, word length of modulus return:
|
|
* PKE_SUCCESS(success), other(error) caution:
|
|
* 1. modulus must be odd
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_pre_calc_mont_no_output(const uint32_t *modulus, uint32_t wordlen)
|
|
{
|
|
return pke_pre_calc_mont(modulus, get_valid_bits(modulus, wordlen), NULL);
|
|
}
|
|
|
|
/* function: load the pre-calculated mont parameters H(R^2 mod modulus)
|
|
* parameters:
|
|
* H -------------------------- input, R^2 mod modulus
|
|
* wordlen -------------------- input, word length of modulus or H
|
|
* return: none
|
|
* caution:
|
|
* 1. please make sure the 2 input parameters are both valid
|
|
* 2. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
void pke_load_pre_calc_mont(uint32_t *H, uint32_t wordlen)
|
|
{
|
|
pke_set_operand_width(wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(0, g_oper_step)), H, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
|
|
/* function: out = a*b mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a*b mod modulus
|
|
* wordlen -------------------- input, word length of modulus, a, b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. modulus must be odd
|
|
* 2. a, b must less than modulus
|
|
* 3. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
* 4. before calling this function, please make sure the pre-calculated mont
|
|
* argument of modulus is located in the right address.
|
|
*/
|
|
uint32_t pke_modmul_internal(const uint32_t *modulus, const uint32_t *a,
|
|
const uint32_t *b, uint32_t *out, uint32_t wordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), (uint32_t *)a,
|
|
wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)b,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_MODMUL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: out = a*b mod modulus
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* a -------------------------- input, integer a
|
|
* b -------------------------- input, integer b
|
|
* out ------------------------ output, out = a*b mod modulus
|
|
* wordlen -------------------- input, word length of modulus, a, b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. modulus must be odd
|
|
* 2. a, b must less than modulus
|
|
* 3. wordlen must not be bigger than OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modmul(const uint32_t *modulus, const uint32_t *a,
|
|
const uint32_t *b, uint32_t *out, uint32_t wordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
ret = pke_pre_calc_mont(modulus, get_valid_bits(modulus, wordlen), NULL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
return pke_modmul_internal((uint32_t *)(PKE_A(0, g_oper_step)), a, b,
|
|
out, wordlen);
|
|
}
|
|
}
|
|
|
|
/* function: mod exponent, this could be used for rsa
|
|
* encrypting,decrypting,signing,verifing. parameters: modulus
|
|
* -------------------- input, modulus exponent ------------------- input,
|
|
* exponent base ----------------------- input, base number out
|
|
* ------------------------ output, out = base^(exponent) mod modulus
|
|
* mod_wordlen ---------------- input, word length of modulus and base
|
|
* number exp_wordlen ---------------- input, word length of exponent return:
|
|
* PKE_SUCCESS(success), other(error) caution:
|
|
* 1. before calling this function, please make sure R^2 mod modulus, the
|
|
* pre-calculated mont arguments of modulus is located in the right address
|
|
* 2. modulus must be odd
|
|
* 3. please make sure exp_wordlen <= mod_wordlen <= OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modexp(const uint32_t *modulus, const uint32_t *exponent,
|
|
const uint32_t *base, uint32_t *out, uint32_t mod_wordlen,
|
|
uint32_t exp_wordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(mod_wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), (uint32_t *)exponent,
|
|
exp_wordlen);
|
|
|
|
if ((g_oper_step / 4) > exp_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + exp_wordlen,
|
|
(g_oper_step / 4) - exp_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
mod_wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)base,
|
|
mod_wordlen);
|
|
|
|
if ((g_oper_step / 4) > mod_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_MODEXP);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), mod_wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, mod_wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: c = a mod b
|
|
* parameters:
|
|
* a -------------------------- input, integer a
|
|
* awordlen ------------------- input, word length of integer
|
|
* b -------------------------- input, integer b, modulus
|
|
* b_h ------------------------ input, H parameter of b
|
|
* bwordlen ------------------- input, word length of integer b and b_h
|
|
* c -------------------------- output, c = a mod b
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. b must be odd, and please make sure bwordlen is real word length of b
|
|
* 2. pleae make sure awordlen <= 2*OPERAND_MAX_WORD_LEN, bwordlen <=
|
|
* OPERAND_MAX_WORD_LEN,
|
|
* 3. real bit length of a can not be bigger than 2*(real bit length of b)
|
|
*/
|
|
uint32_t pke_mod(uint32_t *a, uint32_t awordlen, uint32_t *b, uint32_t *b_h,
|
|
uint32_t bwordlen, uint32_t *c)
|
|
{
|
|
int32_t flag;
|
|
uint32_t bitlen, tmpLen;
|
|
uint32_t *t1, *t2;
|
|
uint32_t ret;
|
|
|
|
flag = uint32_bignumcmp(a, awordlen, b, bwordlen);
|
|
|
|
if (flag < 0) {
|
|
awordlen = get_valid_words(a, awordlen);
|
|
uint32_copy(c, a, awordlen);
|
|
uint32_clear(c + awordlen, bwordlen - awordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
} else if (0 == flag) {
|
|
uint32_clear(c, bwordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_set_operand_width(bwordlen << 5);
|
|
t1 = (uint32_t *)(PKE_A(1, g_oper_step));
|
|
t2 = (uint32_t *)(PKE_B(2, g_oper_step));
|
|
|
|
bitlen = get_valid_bits(b, bwordlen) & 0x1F;
|
|
|
|
/* get t2 = a high part mod b */
|
|
if (bitlen) {
|
|
tmpLen = awordlen - bwordlen + 1;
|
|
uint32_copy(t2, a + bwordlen - 1, tmpLen);
|
|
big_div2n(t2, tmpLen, bitlen);
|
|
|
|
if (tmpLen < bwordlen) {
|
|
uint32_clear(t2 + tmpLen, bwordlen - tmpLen);
|
|
} else if (uint32_bignumcmp(t2, bwordlen, b, bwordlen) >= 0) {
|
|
ret = pke_sub(t2, b, t2, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
tmpLen = awordlen - bwordlen;
|
|
|
|
if (uint32_bignumcmp(a + bwordlen, tmpLen, b, bwordlen) >= 0) {
|
|
ret = pke_sub(a + bwordlen, b, t2, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
uint32_copy(t2, a + bwordlen, tmpLen);
|
|
uint32_clear(t2 + tmpLen, bwordlen - tmpLen);
|
|
}
|
|
}
|
|
|
|
/* set the pre-calculated mont parameters */
|
|
if (NULL == b_h) {
|
|
ret = pke_pre_calc_mont(b, get_valid_bits(b, bwordlen), NULL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
pke_load_pre_calc_mont(b_h, bwordlen);
|
|
}
|
|
|
|
/* get t1 = 1000...000 mod b */
|
|
uint32_clear(t1, bwordlen);
|
|
|
|
if (bitlen) {
|
|
t1[bwordlen - 1] = 1 << (bitlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_sub(t1, b, t1, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* get t2 = a_high * 1000..000 mod b */
|
|
ret = pke_modmul_internal(b, t1, t2, t2, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* get t1 = a low part mod b */
|
|
if (bitlen) {
|
|
uint32_copy(t1, a, bwordlen);
|
|
t1[bwordlen - 1] &= ((1 << (bitlen)) - 1);
|
|
|
|
if (uint32_bignumcmp(t1, bwordlen, b, bwordlen) >= 0) {
|
|
ret = pke_sub(t1, b, t1, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
if (uint32_bignumcmp(a, bwordlen, b, bwordlen) >= 0) {
|
|
ret = pke_sub(a, b, t1, bwordlen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
t1 = a;
|
|
}
|
|
}
|
|
|
|
return pke_modadd(b, t1, t2, c, bwordlen);
|
|
}
|
|
|
|
/* function: set modulus and pre-calculated mont parameters H(R^2 mod modulus)
|
|
* and n0' for hardware operation parameters: modulus --------------------
|
|
* input, modulus modulus_h ------------------ input, R^2 mod modulus bitlen
|
|
* --------------------- input, bit length of modulus return:
|
|
* PKE_SUCCESS(success), other(error) caution:
|
|
* 1. modulus must be odd
|
|
* 2. bitlen must not be bigger than OPERAND_MAX_BIT_LEN
|
|
*/
|
|
uint32_t pke_set_modulus_and_pre_mont(uint32_t *modulus, uint32_t *modulus_h,
|
|
uint32_t bitlen)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(bitlen);
|
|
uint32_t ret;
|
|
|
|
if (NULL != modulus_h) {
|
|
pke_set_operand_width(bitlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), modulus, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_pre_calc_mont(modulus_h, wordlen);
|
|
} else {
|
|
ret = pke_pre_calc_mont(modulus, bitlen, NULL);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/********************************** ECCp functions
|
|
* *************************************/
|
|
|
|
/* function: ECCP curve shamir point mul(Q = [k1]P1 + [k2]P2)
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* k1 ------------------------- input, scalar k1
|
|
* P1x ------------------------ input, x coordinate of point P1
|
|
* P1y ------------------------ input, y coordinate of point P1
|
|
* k2 ------------------------- input, scalar k2
|
|
* P2x ------------------------ input, x coordinate of point P2
|
|
* P2y ------------------------ input, y coordinate of point P2
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure k1,k2 in [1,n-1], n is order of ECCP curve
|
|
* 2. please make sure input point P1,P2 is on the curve
|
|
* 3. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
* 4. the output may be invalid(return PKE_NO_MODINV), even if input are all
|
|
* valid, it is suggested to call eccp_pointMul_Shamir_safe()
|
|
*/
|
|
uint32_t eccp_pointMul_Shamir(eccp_curve_t *curve, uint32_t *k1, uint32_t *P1x,
|
|
uint32_t *P1y, uint32_t *k2, uint32_t *P2x,
|
|
uint32_t *P2y, uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
/* set ecc_p, ecc_p_h, etc. */
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), P1x, wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(2, g_oper_step)), P1y, wordlen);
|
|
*((uint32_t *)(PKE_A(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_A(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(5, g_oper_step)), P2x, wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(6, g_oper_step)), P2y, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(4, g_oper_step)), curve->eccp_a,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_A(4, g_oper_step)), k1, wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_A(5, g_oper_step)), k2, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(5, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(6, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(5, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PMULF);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(5, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(6, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(4, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(4, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(5, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), Qx, wordlen);
|
|
|
|
if (Qy != NULL) {
|
|
pke_read_operand((uint32_t *)(PKE_A(2, g_oper_step)), Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: ECCP curve shamir point mul(Q = [k1]P1 + [k2]P2)
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* k1 ------------------------- input, scalar k1
|
|
* P1x ------------------------ input, x coordinate of point P1
|
|
* P1y ------------------------ input, y coordinate of point P1
|
|
* k2 ------------------------- input, scalar k2
|
|
* P2x ------------------------ input, x coordinate of point P2
|
|
* P2y ------------------------ input, y coordinate of point P2
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure k1,k2 in [1,n-1], n is order of ECCP curve
|
|
* 2. please make sure input point P1,P2 is on the curve
|
|
* 3. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_pointMul_Shamir_safe(eccp_curve_t *curve, uint32_t *k1,
|
|
uint32_t *P1x, uint32_t *P1y, uint32_t *k2,
|
|
uint32_t *P2x, uint32_t *P2y, uint32_t *Qx,
|
|
uint32_t *Qy)
|
|
{
|
|
uint32_t x[ECCP_MAX_WORD_LEN], y[ECCP_MAX_WORD_LEN];
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = eccp_pointMul_Shamir(curve, k1, P1x, P1y, k2, P2x, P2y, Qx, Qy);
|
|
|
|
if (PKE_NO_MODINV == ret) {
|
|
ret = eccp_pointMul(curve, k1, P1x, P1y, x, y);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = eccp_pointMul(curve, k2, P2x, P2y,
|
|
(uint32_t *)(PKE_A(1, g_oper_step)),
|
|
(uint32_t *)(PKE_A(2, g_oper_step)));
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = eccp_pointAdd(curve, (uint32_t *)(PKE_A(1, g_oper_step)),
|
|
(uint32_t *)(PKE_A(2, g_oper_step)), x, y, Qx, Qy);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)x, wordlen << 2);
|
|
get_rand_fast((uint8_t *)y, wordlen << 2);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* function: ECCP curve point mul(Q = [k]G, here G is the curve base point)
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* k ------------------------- input, scalar k1
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure k in [1,n-1], n is order of ECCP curve
|
|
* 2. the input point is base point, and please make sure
|
|
* curve->eccp_half_Gx and curve->eccp_half_Gy both are not NULL!
|
|
* 3. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_pointMul_base(eccp_curve_t *curve, uint32_t *k, uint32_t *Qx,
|
|
uint32_t *Qy)
|
|
{
|
|
uint32_t nwordlen = GET_WORD_LEN(curve->eccp_n_bitLen);
|
|
uint32_t *k1;
|
|
uint32_t *k2;
|
|
uint32_t tmpbitlen, tmpwordlen;
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(curve->eccp_p_bitLen);
|
|
k1 = (uint32_t *)(PKE_A(4, g_oper_step));
|
|
k2 = (uint32_t *)(PKE_A(5, g_oper_step));
|
|
|
|
/* k2: low half part */
|
|
tmpbitlen = (curve->eccp_n_bitLen) / 2;
|
|
tmpwordlen = GET_WORD_LEN(tmpbitlen);
|
|
uint32_copy(k2, k, tmpwordlen);
|
|
uint32_clear(k2 + tmpwordlen, nwordlen - tmpwordlen);
|
|
tmpbitlen = tmpbitlen & 0x1F;
|
|
|
|
if (tmpbitlen) {
|
|
k2[tmpwordlen - 1] &= (1 << tmpbitlen) - 1;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* k1: high half part */
|
|
if (tmpbitlen) {
|
|
uint32_copy(k1, k + tmpwordlen - 1, nwordlen - tmpwordlen + 1);
|
|
uint32_clear(k1 + nwordlen - tmpwordlen + 1, tmpwordlen - 1);
|
|
big_div2n(k1, nwordlen - tmpwordlen + 1, tmpbitlen);
|
|
} else {
|
|
uint32_copy(k1, k + tmpwordlen, nwordlen - tmpwordlen);
|
|
uint32_clear(k1 + nwordlen - tmpwordlen, tmpwordlen);
|
|
}
|
|
|
|
tmpbitlen = curve->eccp_n_bitLen - (curve->eccp_n_bitLen) / 2;
|
|
tmpwordlen = GET_WORD_LEN(tmpbitlen);
|
|
tmpbitlen = tmpbitlen & 0x1F;
|
|
|
|
if (tmpbitlen) {
|
|
k1[tmpwordlen - 1] &= (1 << tmpbitlen) - 1;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = eccp_pointMul_Shamir(curve, k1, curve->eccp_half_Gx,
|
|
curve->eccp_half_Gy, k2, curve->eccp_Gx,
|
|
curve->eccp_Gy, Qx, Qy);
|
|
|
|
if (PKE_NO_MODINV == ret) {
|
|
ret = eccp_pointMul(curve, k, curve->eccp_Gx, curve->eccp_Gy, Qx, Qy);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* function: ECCP curve point mul(random point), Q=[k]P
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* k -------------------------- input, scalar
|
|
* Px ------------------------- input, x coordinate of point P
|
|
* Py ------------------------- input, y coordinate of point P
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure k in [1,n-1], n is order of ECCP curve
|
|
* 2. please make sure input point P is on the curve
|
|
* 3. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
* 4. even if the input point P is valid, the output may be infinite point,
|
|
* in this case it will return error.
|
|
*/
|
|
uint32_t eccp_pointMul(eccp_curve_t *curve, uint32_t *k, uint32_t *Px,
|
|
uint32_t *Py, uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), Px, wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(2, g_oper_step)), Py, wordlen);
|
|
*((uint32_t *)(PKE_A(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_A(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
pke_load_operand((uint32_t *)(PKE_B(4, g_oper_step)), curve->eccp_a,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_A(4, g_oper_step)), k, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PMUL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), Qx, wordlen);
|
|
|
|
if (NULL != Qy) {
|
|
pke_read_operand((uint32_t *)(PKE_A(2, g_oper_step)), Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: ECCP curve point add, Q=P1+P2
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* P1x ------------------------ input, x coordinate of point P1
|
|
* P1y ------------------------ input, y coordinate of point P1
|
|
* P2x ------------------------ input, x coordinate of point P2
|
|
* P2y ------------------------ input, y coordinate of point P2
|
|
* Qx ------------------------- output, x coordinate of point Q=P1+P2
|
|
* Qy ------------------------- output, y coordinate of point Q=P1+P2
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure input point P1 and P2 are both on the curve
|
|
* 2. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
* 3. even if the input point P1 and P2 is valid, the output may be infinite
|
|
* point, in this case it will return error.
|
|
*/
|
|
uint32_t eccp_pointAdd(eccp_curve_t *curve, uint32_t *P1x, uint32_t *P1y,
|
|
uint32_t *P2x, uint32_t *P2y, uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* pke_pre_calc_mont() may cover A1, so load A1(P1x) here */
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), P1x, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), P1y, wordlen);
|
|
|
|
*((uint32_t *)(PKE_B(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_B(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), P2x, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(2, g_oper_step)), P2y, wordlen);
|
|
|
|
*((uint32_t *)(PKE_A(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_A(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PADD);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(2, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), Qx, wordlen);
|
|
|
|
if (NULL != Qy) {
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(2, g_oper_step)), Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
#ifdef ECCP_POINT_DOUBLE
|
|
/* function: ECCP curve point double, Q=[2]P
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* Px ------------------------- input, x coordinate of point P
|
|
* Py ------------------------- input, y coordinate of point P
|
|
* Qx ------------------------- output, x coordinate of point Q=[2]P
|
|
* Qy ------------------------- output, y coordinate of point Q=[2]P
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure input point P is on the curve
|
|
* 2. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_pointDouble(eccp_curve_t *curve, uint32_t *Px, uint32_t *Py,
|
|
uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* pke_pre_calc_mont() may cover A1, so load A1(Px) and other paras here */
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), Px, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), Py, wordlen);
|
|
|
|
*((uint32_t *)(PKE_B(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_B(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(4, g_oper_step)), curve->eccp_a,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PDBL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(4, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), Qx, wordlen);
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(2, g_oper_step)), Qy, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/* function: check whether the input point P is on ECCP curve or not
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* Px ------------------------- input, x coordinate of point P
|
|
* Py ------------------------- input, y coordinate of point P
|
|
* return: PKE_SUCCESS(success, on the curve), other(error or not on the curve)
|
|
* caution:
|
|
* 1. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
* 2. after calculation, A1 and A2 will be changed!
|
|
*/
|
|
uint32_t eccp_pointVerify(eccp_curve_t *curve, uint32_t *Px, uint32_t *Py)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* pke_pre_calc_mont() may cover A1, so load A1(Px) and other paras here */
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(1, g_oper_step)), Px, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), Py, wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(4, g_oper_step)), curve->eccp_a,
|
|
wordlen);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(4, g_oper_step)), curve->eccp_b,
|
|
wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PVER);
|
|
|
|
if (0 != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(4, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(4, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: get ECCP public key from private key(the key pair could be used in
|
|
* SM2/ECDSA/ECDH, etc.) parameters: curve ---------------------- input,
|
|
* eccp_curve_t curve struct pointer prikey --------------------- input, private
|
|
* key, big-endian pubkey --------------------- output, public key, big-endian
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_get_pubkey_from_prikey(eccp_curve_t *curve, uint8_t *prikey,
|
|
uint8_t *pubkey)
|
|
{
|
|
uint32_t nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
|
|
uint32_t nwordlen = GET_WORD_LEN(curve->eccp_n_bitLen);
|
|
uint32_t pbytelen = GET_BYTE_LEN(curve->eccp_p_bitLen);
|
|
uint32_t k[ECCP_MAX_WORD_LEN];
|
|
uint32_t *x;
|
|
uint32_t *y;
|
|
uint32_t ret;
|
|
#ifdef SUPPORT_SM2
|
|
uint32_t sm2p256v1_n[8] = {0x39D54123, 0x53BBF409, 0x21C6052B, 0x7203DF6B,
|
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE};
|
|
#endif
|
|
|
|
pke_set_operand_width(curve->eccp_p_bitLen);
|
|
x = (uint32_t *)(PKE_A(1, g_oper_step));
|
|
y = (uint32_t *)(PKE_A(2, g_oper_step));
|
|
|
|
/* clear if curve->eccp_n_bitLen is not a multiple of 32 */
|
|
k[nwordlen - 1] = 0;
|
|
reverse_byte_array(prikey, (uint8_t *)k, nByteLen);
|
|
|
|
/* make sure k in [1, n-1] */
|
|
if (uint32_bignum_check_zero(k, nwordlen)) {
|
|
return PKE_ZERO_ALL;
|
|
} else if (uint32_bignumcmp(k, nwordlen, curve->eccp_n, nwordlen) >= 0) {
|
|
return PKE_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#ifdef SUPPORT_SM2
|
|
|
|
/*sm2p256v1_n sm2_curve->eccp_n[0] - 1 */
|
|
|
|
if ((k[0] == sm2p256v1_n[0] - 1) &&
|
|
(0 == uint32_bignumcmp(k + 1, nwordlen - 1, sm2p256v1_n + 1,
|
|
nwordlen - 1))) {
|
|
return PKE_INTEGER_TOO_BIG;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* get pubkey */
|
|
if (curve->eccp_half_Gx && curve->eccp_half_Gy) {
|
|
ret = eccp_pointMul_base(curve, k, x, y);
|
|
} else {
|
|
ret = eccp_pointMul(curve, k, curve->eccp_Gx, curve->eccp_Gy, x, y);
|
|
}
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
reverse_byte_array((uint8_t *)x, pubkey, pbytelen);
|
|
reverse_byte_array((uint8_t *)y, pubkey + pbytelen, pbytelen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: get ECCP key pair(the key pair could be used in SM2/ECDSA/ECDH)
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* prikey --------------------- output, private key, big-endian
|
|
* pubkey --------------------- output, public key, big-endian
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_getkey(eccp_curve_t *curve, uint8_t *prikey, uint8_t *pubkey)
|
|
{
|
|
uint32_t tmpLen;
|
|
uint32_t nByteLen = GET_BYTE_LEN(curve->eccp_n_bitLen);
|
|
uint32_t ret;
|
|
|
|
ECCP_GETKEY_LOOP:
|
|
|
|
ret = get_rand(prikey, nByteLen);
|
|
|
|
if (TRNG_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* make sure k has the same bit length as n */
|
|
tmpLen = (curve->eccp_n_bitLen) & 7;
|
|
|
|
if (tmpLen) {
|
|
prikey[0] &= (1 << (tmpLen)) - 1;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = eccp_get_pubkey_from_prikey(curve, prikey, pubkey);
|
|
|
|
if (PKE_ZERO_ALL == ret || PKE_INTEGER_TOO_BIG == ret) {
|
|
goto ECCP_GETKEY_LOOP;
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/****************************** ECCp functions finished
|
|
* ********************************/
|
|
|
|
#ifdef SUPPORT_C25519
|
|
/**************************** X25519 & Ed25519 functions
|
|
* *******************************/
|
|
|
|
/* function: c25519 point mul(random point), Q=[k]P
|
|
* parameters:
|
|
* curve ---------------------- input, c25519 curve struct pointer
|
|
* k -------------------------- input, scalar
|
|
* Pu ------------------------- input, u coordinate of point P
|
|
* Qu ------------------------- output, u coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure input point P is on the curve
|
|
* 2. even if the input point P is valid, the output may be infinite point,
|
|
* in this case return error.
|
|
* 3. please make sure the curve is c25519
|
|
*/
|
|
uint32_t x25519_pointMul(mont_curve_t *curve, uint32_t *k, uint32_t *Pu,
|
|
uint32_t *Qu)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->p, curve->p_h, curve->p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)PKE_A(1, g_oper_step), Pu, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(2, g_oper_step), curve->a24, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(4, g_oper_step), k, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)PKE_A(1, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(2, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(4, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(0, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_C25519_PMUL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(4, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)PKE_A(1, g_oper_step), Qu, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: Ed25519 decode point
|
|
* parameters:
|
|
* in_y ----------------------- input, encoded Ed25519 point
|
|
* out_x ---------------------- output, x coordinate of input point
|
|
* out_y ---------------------- output, y coordinate of input point
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1.
|
|
*/
|
|
uint32_t ed25519_decode_point(edward_curve_t *curve, uint8_t in_y[32],
|
|
uint8_t out_x[32], uint8_t out_y[32])
|
|
{
|
|
uint32_t u[Ed25519_WORD_LEN];
|
|
uint32_t v[Ed25519_WORD_LEN];
|
|
uint32_t t[Ed25519_WORD_LEN] = {0};
|
|
uint32_t t2[Ed25519_WORD_LEN];
|
|
uint32_t t3[Ed25519_WORD_LEN];
|
|
uint32_t ret;
|
|
|
|
memcpy_(u, in_y, Ed25519_BYTE_LEN);
|
|
u[Ed25519_WORD_LEN - 1] &= 0x7FFFFFFF;
|
|
|
|
/* make sure y < prime p */
|
|
if (uint32_bignumcmp(u, Ed25519_WORD_LEN, curve->p, Ed25519_WORD_LEN) >=
|
|
0) {
|
|
return PKE_INVALID_INPUT;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* set pre-calculated paras */
|
|
if (NULL != curve->p_h) {
|
|
pke_load_pre_calc_mont(curve->p_h, Ed25519_WORD_LEN);
|
|
} else {
|
|
pke_pre_calc_mont(curve->p, curve->p_bitLen, NULL);
|
|
}
|
|
|
|
/* v = y^2 */
|
|
ret = pke_modmul_internal(curve->p, u, u, v, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
t[0] = 1;
|
|
/* u = y^2 - 1 */
|
|
ret = pke_modsub(curve->p, v, t, u, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* v = d*y^2 */
|
|
ret = pke_modmul_internal(curve->p, curve->d, v, v, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* v = d*y^2 + 1 */
|
|
ret = pke_modadd(curve->p, v, t, v, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = v^2 */
|
|
ret = pke_modmul_internal(curve->p, v, v, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t3 = v^3 */
|
|
ret = pke_modmul_internal(curve->p, v, t2, t3, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t = u*v^3 */
|
|
ret = pke_modmul_internal(curve->p, t3, u, t, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = v^4 */
|
|
ret = pke_modmul_internal(curve->p, t2, t2, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = v^7 */
|
|
ret = pke_modmul_internal(curve->p, t2, t3, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = u*v^7 */
|
|
ret = pke_modmul_internal(curve->p, t2, u, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t3 = (p-5)/8 */
|
|
uint32_copy(t3, curve->p, Ed25519_WORD_LEN);
|
|
t3[0] -= 5;
|
|
big_div2n(t3, Ed25519_WORD_LEN, 3);
|
|
/* t2 = (u*v^7 )^((p-5)/8) */
|
|
ret = pke_modexp(curve->p, t3, t2, t2, Ed25519_WORD_LEN, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t = x = (u*v^3)*(u*v^7 )^((p-5)/8) */
|
|
ret = pke_modmul_internal(curve->p, t2, t, t, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = x^2 */
|
|
ret = pke_modmul_internal(curve->p, t, t, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t2 = v*x^2 */
|
|
ret = pke_modmul_internal(curve->p, t2, v, t2, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* if v x^2 = u (mod p), x is a square root. */
|
|
if (0 == uint32_bignumcmp(t2, Ed25519_WORD_LEN, u, Ed25519_WORD_LEN)) {
|
|
goto result;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t3 = -u mod p */
|
|
ret = pke_sub(curve->p, u, t3, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else if (0 ==
|
|
uint32_bignumcmp(t2, Ed25519_WORD_LEN, t3, Ed25519_WORD_LEN)) {
|
|
/* v = (p-1)/4 */
|
|
uint32_copy(v, curve->p, Ed25519_WORD_LEN);
|
|
v[0] -= 1;
|
|
big_div2n(v, Ed25519_WORD_LEN, 2);
|
|
/* t2 = 2 */
|
|
uint32_clear(t2, Ed25519_WORD_LEN);
|
|
t2[0] = 2;
|
|
/* u = 2^((p-1)/4) */
|
|
ret =
|
|
pke_modexp(curve->p, v, t2, u, Ed25519_WORD_LEN, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* t = x*(2^((p-1)/4)) */
|
|
ret = pke_modmul_internal(curve->p, t, u, t, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
goto result;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_INVALID_INPUT;
|
|
|
|
result:
|
|
|
|
/* if x=0 and x is odd, decode fail */
|
|
if (uint32_bignum_check_zero(t, Ed25519_WORD_LEN) &&
|
|
(in_y[Ed25519_BYTE_LEN - 1] & 0x80)) {
|
|
return PKE_INVALID_INPUT;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/* get out_x */
|
|
if ((uint8_t)((t[0] & 1) << 7) == (in_y[Ed25519_BYTE_LEN - 1] & 0x80)) {
|
|
memcpy_(out_x, t, Ed25519_BYTE_LEN);
|
|
} else {
|
|
/* v = -x mod p */
|
|
ret = pke_sub(curve->p, t, v, Ed25519_WORD_LEN);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
memcpy_(out_x, v, Ed25519_BYTE_LEN);
|
|
}
|
|
}
|
|
|
|
/* get out_y */
|
|
memcpy_(out_y, in_y, Ed25519_BYTE_LEN);
|
|
out_y[Ed25519_BYTE_LEN - 1] &= 0x7F;
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: edwards25519 curve point mul(random point), Q=[k]P
|
|
* parameters:
|
|
* curve ---------------------- input, edwards25519 curve struct pointer
|
|
* k -------------------------- input, scalar
|
|
* Px ------------------------- input, x coordinate of point P
|
|
* Py ------------------------- input, y coordinate of point P
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure input point P is on the curve
|
|
* 2. even if the input point P is valid, the output may be neutral point
|
|
* (0, 1), it is valid
|
|
* 3. please make sure the curve is edwards25519
|
|
* 4. k could not be zero now.
|
|
*/
|
|
uint32_t ed25519_pointMul(edward_curve_t *curve, uint32_t *k, uint32_t *Px,
|
|
uint32_t *Py, uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->p, curve->p_h, curve->p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)PKE_A(1, g_oper_step), Px, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(2, g_oper_step), Py, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(3, g_oper_step), curve->d, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(4, g_oper_step), k, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)PKE_A(1, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(2, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_B(0, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(0, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_Ed25519_PMUL);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(0, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)PKE_A(1, g_oper_step), Qx, wordlen);
|
|
|
|
if (NULL != Qy) {
|
|
pke_read_operand((uint32_t *)PKE_A(2, g_oper_step), Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: edwards25519 point add, Q=P1+P2
|
|
* parameters:
|
|
* curve ---------------------- input, edwards25519 curve struct pointer
|
|
* P1x ------------------------ input, x coordinate of point P1
|
|
* P1y ------------------------ input, y coordinate of point P1
|
|
* P2x ------------------------ input, x coordinate of point P2
|
|
* P2y ------------------------ input, y coordinate of point P2
|
|
* Qx ------------------------- output, x coordinate of point Q=P1+P2
|
|
* Qy ------------------------- output, y coordinate of point Q=P1+P2
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure input point P1 and P2 are both on the curve
|
|
* 2. the output point may be neutral point (0, 1), it is valid
|
|
* 3. please make sure the curve is edwards25519
|
|
*/
|
|
uint32_t ed25519_pointAdd(edward_curve_t *curve, uint32_t *P1x, uint32_t *P1y,
|
|
uint32_t *P2x, uint32_t *P2y, uint32_t *Qx,
|
|
uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->p_bitLen);
|
|
uint32_t ret;
|
|
|
|
ret = pke_set_modulus_and_pre_mont(curve->p, curve->p_h, curve->p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)PKE_A(1, g_oper_step), P1x, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(2, g_oper_step), P1y, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_B(1, g_oper_step), P2x, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_B(2, g_oper_step), P2y, wordlen);
|
|
pke_load_operand((uint32_t *)PKE_A(3, g_oper_step), curve->d, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)PKE_A(1, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_A(2, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_B(1, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_B(2, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)PKE_B(0, g_oper_step) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_Ed25519_PADD);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(0, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(2, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)PKE_A(1, g_oper_step), Qx, wordlen);
|
|
pke_read_operand((uint32_t *)PKE_A(2, g_oper_step), Qy, wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/**************************** X25519 & Ed25519 finished
|
|
* ********************************/
|
|
#endif
|
|
|
|
#ifdef PKE_SEC
|
|
/*********************************** secfunctions
|
|
* **************************************/
|
|
|
|
/* function: pke sec init
|
|
* parameters: none
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
*/
|
|
uint32_t pke_sec_init(void)
|
|
{
|
|
uint32_t rand[4];
|
|
|
|
if (TRNG_SUCCESS != get_rand((uint8_t *)&rand, 16)) {
|
|
return PKE_STOP;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
PKE_RAND_SEED = rand[0];
|
|
|
|
PKE_RC_EN = 0;
|
|
PKE_RC_KEY = rand[1];
|
|
PKE_RC_D_NONCE = rand[2];
|
|
PKE_RC_A_NONCE = rand[3] & 0x0000003F;
|
|
PKE_RC_EN = 1;
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: pke sec uninit
|
|
* parameters: none
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
*/
|
|
uint32_t pke_sec_uninit(void)
|
|
{
|
|
PKE_RC_EN = 0;
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
/* function: mod exponent, this could be used for rsa
|
|
* encrypting,decrypting,signing,verifing. parameters: modulus
|
|
* -------------------- input, modulus exponent ------------------- input,
|
|
* exponent base ----------------------- input, base number out
|
|
* ------------------------ output, out = base^(exponent) mod modulus
|
|
* mod_wordlen ---------------- input, word length of modulus and base
|
|
* number exp_wordlen ---------------- input, word length of exponent return:
|
|
* PKE_SUCCESS(success), other(error) caution:
|
|
* 1. before calling this function, please make sure R^2 mod modulus, the
|
|
* pre-calculated mont arguments of modulus is located in the right address
|
|
* 2. modulus must be odd
|
|
* 3. please make sure exp_wordlen <= mod_wordlen <= OPERAND_MAX_WORD_LEN
|
|
*/
|
|
uint32_t pke_modexp_ladder(const uint32_t *modulus, const uint32_t *exponent,
|
|
const uint32_t *base, uint32_t *out,
|
|
uint32_t mod_wordlen, uint32_t exp_wordlen)
|
|
{
|
|
uint32_t ret;
|
|
|
|
pke_set_operand_width(mod_wordlen << 5);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), (uint32_t *)exponent,
|
|
exp_wordlen);
|
|
|
|
if ((g_oper_step / 4) > exp_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + exp_wordlen,
|
|
(g_oper_step / 4) - exp_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
mod_wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)base,
|
|
mod_wordlen);
|
|
|
|
if ((g_oper_step / 4) > mod_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret =
|
|
pke_set_micro_code_start_wait_return_code(MICROCODE_MODEXP_MGMR_LADDER);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(1, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), mod_wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, mod_wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: mod exponent, this could be used for rsa decrypting and signing.
|
|
* parameters:
|
|
* modulus -------------------- input, modulus
|
|
* exponent ------------------- input, exponent, actually private key d
|
|
* pub ------------------------ input, public key e
|
|
* base ----------------------- input, base number
|
|
* out ------------------------ output, out = base^(exponent) mod modulus
|
|
* mod_wordlen ---------------- input, word length of modulus and base
|
|
* number exp_wordlen ---------------- input, word length of exponent
|
|
* pub_wordlen ---------------- input, word length of pub
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. before calling this function, please make sure R^2 mod modulus, the
|
|
* pre-calculated mont arguments of modulus is located in the right address
|
|
* 2. modulus must be odd
|
|
* 3. please make sure exp_wordlen <= mod_wordlen <= OPERAND_MAX_WORD_LEN
|
|
* 4. please make sure pub_wordlen <= 2
|
|
* 5. please make sure value of exponent should be bigger than 1
|
|
*/
|
|
uint32_t pke_modexp_with_pub(const uint32_t *modulus, const uint32_t *exponent,
|
|
const uint32_t *pub, const uint32_t *base,
|
|
uint32_t *out, uint32_t mod_wordlen,
|
|
uint32_t exp_wordlen, uint32_t pub_wordlen)
|
|
{
|
|
uint32_t temp = get_valid_bits(exponent, exp_wordlen);
|
|
uint32_t bitlen = (temp - 1) & 31;
|
|
uint32_t ret;
|
|
|
|
exp_wordlen = GET_WORD_LEN(temp);
|
|
|
|
(void)get_rand((uint8_t *)(PKE_A(3, g_oper_step)), exp_wordlen << 2);
|
|
|
|
pke_set_operand_width(mod_wordlen << 5);
|
|
|
|
if (0 == bitlen) {
|
|
*((volatile uint32_t *)((PKE_A(3, g_oper_step)) + exp_wordlen - 1)) = 0;
|
|
} else {
|
|
*((volatile uint32_t *)((PKE_A(3, g_oper_step)) + exp_wordlen - 1)) &=
|
|
(0xFFFFFFFF >> (32 - bitlen));
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(2, g_oper_step)), (uint32_t *)pub,
|
|
pub_wordlen);
|
|
|
|
if ((g_oper_step / 4) > pub_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(2, g_oper_step)) + pub_wordlen,
|
|
(g_oper_step / 4) - pub_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(2, g_oper_step)), (uint32_t *)exponent,
|
|
exp_wordlen);
|
|
|
|
if ((g_oper_step / 4) > exp_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(2, g_oper_step)) + exp_wordlen,
|
|
(g_oper_step / 4) - exp_wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(3, g_oper_step)) + exp_wordlen,
|
|
(g_oper_step / 4) - exp_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_A(0, g_oper_step)), (uint32_t *)modulus,
|
|
mod_wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), (uint32_t *)base,
|
|
mod_wordlen);
|
|
|
|
if ((g_oper_step / 4) > mod_wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_A(0, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + mod_wordlen,
|
|
(g_oper_step / 4) - mod_wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_pre_calc_mont_N0();
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(3, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), mod_wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret =
|
|
pke_set_micro_code_start_wait_return_code(MICROCODE_MODEXP_WITH_PUBKEY);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_A(0, g_oper_step)), mod_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(2, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(3, g_oper_step)), exp_wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), mod_wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), out, mod_wordlen);
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* function: ECCP curve sec point mul, Q=[k]P, P is a random point on curve
|
|
* parameters:
|
|
* curve ---------------------- input, eccp_curve_t curve struct pointer
|
|
* k -------------------------- input, scalar
|
|
* Px ------------------------- input, x coordinate of point P
|
|
* Py ------------------------- input, y coordinate of point P
|
|
* Qx ------------------------- output, x coordinate of point Q
|
|
* Qy ------------------------- output, y coordinate of point Q
|
|
* return: PKE_SUCCESS(success), other(error)
|
|
* caution:
|
|
* 1. please make sure k in [1,n-1], n is order of ECCP curve
|
|
* 2. please make sure input point P is on the curve
|
|
* 3. please make sure bit length of the curve is not bigger than
|
|
* ECCP_MAX_BIT_LEN
|
|
*/
|
|
uint32_t eccp_pointMul_sec(eccp_curve_t *curve, uint32_t *k, uint32_t *Px,
|
|
uint32_t *Py, uint32_t *Qx, uint32_t *Qy)
|
|
{
|
|
uint32_t wordlen = GET_WORD_LEN(curve->eccp_p_bitLen);
|
|
uint32_t ret = 0;
|
|
|
|
/*for k = n-1, the hardware does not support(it return code is
|
|
PKE_NO_MODINV), so here check it. actually, now R1 = [n]G, R0 = [n-1]G, but
|
|
it can not get y coordinate of output point Q since R1 can not be
|
|
represented in affine coordinates.*/
|
|
if (k[0] == curve->eccp_n[0] - 1) {
|
|
if (0 == uint32_bignumcmp(k + 1, wordlen - 1, curve->eccp_n + 1,
|
|
wordlen - 1)) {
|
|
uint32_copy(Qx, Px, wordlen);
|
|
return pke_sub(curve->eccp_p, Py, Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
} else {
|
|
;
|
|
}
|
|
|
|
/*set ecc_p, ecc_p_h, etc.*/
|
|
ret = pke_set_modulus_and_pre_mont(curve->eccp_p, curve->eccp_p_h,
|
|
curve->eccp_p_bitLen);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(1, g_oper_step)), Px, wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(2, g_oper_step)), Py, wordlen);
|
|
*((uint32_t *)(PKE_A(3, g_oper_step))) = 1;
|
|
uint32_clear((uint32_t *)(PKE_A(3, g_oper_step)) + 1,
|
|
(g_oper_step / 4) - 1);
|
|
|
|
pke_load_operand((uint32_t *)(PKE_B(3, g_oper_step)), curve->eccp_b,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(4, g_oper_step)), curve->eccp_a,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_B(5, g_oper_step)), curve->eccp_n,
|
|
wordlen);
|
|
pke_load_operand((uint32_t *)(PKE_A(4, g_oper_step)), k, wordlen);
|
|
|
|
if ((g_oper_step / 4) > wordlen) {
|
|
uint32_clear((uint32_t *)(PKE_B(1, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(2, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(3, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_B(5, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
uint32_clear((uint32_t *)(PKE_A(4, g_oper_step)) + wordlen,
|
|
(g_oper_step / 4) - wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
ret = pke_set_micro_code_start_wait_return_code(MICROCODE_PMUL_SEC);
|
|
|
|
if (PKE_SUCCESS != ret) {
|
|
#ifdef PKE_SEC
|
|
get_rand_fast((uint8_t *)(PKE_B(1, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(2, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(3, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(4, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_B(5, g_oper_step)), wordlen << 2);
|
|
get_rand_fast((uint8_t *)(PKE_A(4, g_oper_step)), wordlen << 2);
|
|
#endif
|
|
return ret;
|
|
} else {
|
|
;
|
|
}
|
|
|
|
pke_read_operand((uint32_t *)(PKE_A(1, g_oper_step)), Qx, wordlen);
|
|
|
|
if (NULL != Qy) {
|
|
pke_read_operand((uint32_t *)(PKE_A(2, g_oper_step)), Qy, wordlen);
|
|
} else {
|
|
;
|
|
}
|
|
|
|
return PKE_SUCCESS;
|
|
}
|
|
|
|
#endif
|