Files
2025-11-07 09:57:14 +08:00

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