| /****************************************************************************** |
| * @file pke.c |
| * |
| * @brief for TLSR chips |
| * |
| * @author public@telink-semi.com; |
| * @date Sep. 30, 2010 |
| * |
| * @attention |
| * |
| * Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *****************************************************************************/ |
| |
| |
| #include "pke.h" |
| #include "../../common/string.h" |
| |
| |
| |
| /** |
| * @brief get real bit length of big number a of wordLen words |
| * @param[in] a - the buffer a |
| * @param[in] wordLen - the length of a |
| * @return the real bit length of big number a of wordLen words |
| */ |
| unsigned int valid_bits_get(const unsigned int *a, unsigned int wordLen) |
| { |
| unsigned int i = 0; |
| unsigned int j = 0; |
| |
| if(0 == wordLen) |
| { |
| return 0; |
| } |
| |
| for (i = wordLen; i > 0; i--) |
| { |
| if (a[i - 1]) |
| { |
| break; |
| } |
| } |
| |
| if(0 == i) |
| { |
| return 0; |
| } |
| |
| for (j = 32; j > 0; j--) |
| { |
| if (a[i - 1] & (0x1 << (j - 1))) |
| { |
| break; |
| } |
| } |
| |
| return ((i - 1) << 5) + j; |
| } |
| /** |
| * @brief get real word length of big number a of max_words words |
| * @param[in] a - the buffer a |
| * @param[in] max_words - the length of a |
| * @return get real word length of big number a |
| */ |
| unsigned int valid_words_get(unsigned int *a, unsigned int max_words) |
| { |
| unsigned int i = 0; |
| |
| for (i = max_words; i > 0; i--) |
| { |
| if (a[i - 1]) |
| { |
| return i; |
| } |
| } |
| |
| return 0; |
| } |
| /** |
| * @brief compare big integer a and b |
| * @param[in] a - value |
| * @param[in] aWordLen - the length of a |
| * @param[in] b - value |
| * @param[in] bWordLen - the length of b |
| * @return 0:a=b, 1:a>b, -1: a<b |
| */ |
| signed int big_integer_compare(unsigned int *a, unsigned int aWordLen, unsigned int *b, unsigned int bWordLen) |
| { |
| signed int i; |
| |
| aWordLen = valid_words_get(a, aWordLen); |
| bWordLen = valid_words_get(b, bWordLen); |
| |
| if(aWordLen > bWordLen) |
| return 1; |
| if(aWordLen < bWordLen) |
| return -1; |
| |
| for(i=(aWordLen-1); i>=0; i--) |
| { |
| if(a[i] > b[i]) |
| return 1; |
| if(a[i] < b[i]) |
| return -1; |
| } |
| |
| return 0; |
| } |
| /** |
| * @brief c = a - b |
| * @param[in] a - integer a |
| * @param[in] b - integer b |
| * @param[out] c - integer c = a - b |
| * @return none |
| */ |
| void sub_u32(unsigned int *a, unsigned int *b, unsigned int *c, unsigned int wordLen) |
| { |
| unsigned int i, carry, temp; |
| |
| carry = 0; |
| for(i=0; i<wordLen; i++) |
| { |
| temp = a[i]-b[i]; |
| c[i] = temp-carry; |
| if(temp > a[i] || c[i] > temp) |
| { |
| carry = 1; |
| } |
| else |
| { |
| carry = 0; |
| } |
| } |
| } |
| /** |
| * @brief a = a/(2^n) |
| * @param[in] a - big integer a |
| * @param[in] aWordLen - word length of a |
| * @param[in] n - exponent of 2^n |
| * @return word length of a = a/(2^n) |
| * @caution: 1. make sure aWordLen is real word length of a |
| * 2. a may be 0, then aWordLen is 0, to make sure aWordLen-1 is available, so data |
| * type of aWordLen is int32_t, not uint32_t |
| */ |
| unsigned int div2n_u32(unsigned int a[], signed int aWordLen, unsigned int n) |
| { |
| signed int i; |
| unsigned int j; |
| |
| if(!aWordLen) |
| return 0; |
| |
| if(n <= 32) |
| { |
| for(i=0; i<aWordLen-1; i++) |
| { |
| a[i] >>= n; |
| a[i] |= (a[i+1]<<(32-n)); |
| } |
| a[i] >>= n; |
| |
| if(!a[i]) |
| return i; |
| return aWordLen; |
| } |
| else //general method |
| { |
| j = n>>5; |
| n &= 31; |
| for(i=0; i<aWordLen-(signed int)j-1; i++) |
| { |
| a[i] = a[i+j]>>n; |
| a[i] |= (a[i+j+1]<<(32-n)); |
| } |
| a[i] = a[i+j]>>n; |
| memset(a+aWordLen-j, 0, j<<2); |
| |
| if(!a[i]) |
| return i; |
| return aWordLen - j; |
| } |
| } |
| /** |
| * @brief get result operand from specified addr |
| * @param[in] baseaddr - the address |
| * @param[in] data - the buffer data |
| * @param[in] wordLen - the length of data |
| * @return none |
| */ |
| void pke_read_operand(unsigned int *baseaddr, unsigned int *data, unsigned int wordLen) |
| { |
| unsigned int i; |
| |
| if(baseaddr != data) |
| { |
| for (i = 0; i < wordLen; i++) |
| { |
| data[i] = baseaddr[i]; |
| } |
| } |
| } |
| /** |
| * @brief load operand to specified addr |
| * @param[in] none |
| * @param[out] none |
| * @return none |
| */ |
| void pke_load_operand(unsigned int *baseaddr, unsigned int *data, unsigned int wordLen) |
| { |
| unsigned int i; |
| |
| if(baseaddr != data) |
| { |
| for (i = 0; i < wordLen; i++) |
| { |
| baseaddr[i] = data[i]; |
| } |
| for (i = wordLen; i < 9; i++) |
| { |
| baseaddr[i] = 0x00000000; |
| } |
| } |
| } |
| /** |
| * @brief This function is to complete the calculation of the corresponding function of the PKE module. |
| * @param[in] none |
| * @param[out] none |
| * @return 0 - normal stop. |
| * 1 - received a termination request(CTRL.STOP is high) |
| * 2 - no valid modulo inverse |
| * 3 - point is not on the curve(CTRL.CMD:PVER) |
| * 4 - invalid microcode |
| */ |
| unsigned char pke_opr_cal(pke_microcode_e addr, pke_exe_cfg_e cfg) |
| { |
| pke_set_microcode(addr); |
| |
| if(0x00 != cfg) |
| pke_set_exe_cfg(cfg); |
| |
| pke_clr_irq_status(); |
| |
| pke_opr_start(); |
| |
| while(!pke_get_irq_status()); //0(in progress) 1(done)) |
| |
| return (pke_check_rt_code()); |
| } |
| /** |
| * @brief load the pre-calculated mont parameters H(R^2 mod modulus) and |
| * n1( - modulus ^(-1) mod 2^w ) |
| * @param[in] H - R^2 mod modulus |
| * @param[in] n1 - modulus ^(-1) mod 2^w, here w is 32 actually |
| * @param[in] wordLen - word length of modulus or H |
| * @return: none |
| */ |
| void pke_load_pre_calc_mont(unsigned int *H, unsigned int *n1, unsigned int wordLen) |
| { |
| pke_set_operand_width(wordLen<<5); |
| |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), H, wordLen); |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), n1, 1); |
| } |
| /** |
| * @brief calc h(R^2 mod modulus) and n1( - modulus ^(-1) mod 2^w ) for modmul, pointMul. etc. |
| * here w is bit width of word, i,e. 32. |
| * @param[in] modulus - input, modulus |
| * @param[in] wordLen - input, word length of modulus or H |
| * @param[out] PKE_A3 - R^2 mod modulus |
| * @param[out] PKE_B4 - modulus ^(-1) mod 2^w, here w is 32 actually |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_calc_pre_mont(const unsigned int *modulus, unsigned int wordLen) |
| { |
| unsigned char ret; |
| |
| pke_set_operand_width(wordLen<<5); |
| |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), (unsigned int *)modulus, wordLen); //B3 modulus |
| |
| ret = pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| |
| return ret; |
| } |
| /** |
| * @brief ECCP curve point del point, Q=2P |
| * @param[in] curve - ECCP_CURVE struct pointer |
| * @param[in] Px - x coordinate of point P |
| * @param[in] Py - y coordinate of point P |
| * @param[out] Qx - x coordinate of point Q |
| * @param[out] Qy - y coordinate of point Q |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_eccp_point_del(eccp_curve_t *curve, unsigned int *k, unsigned int *Px, unsigned int *Py, |
| unsigned int *Qx, unsigned int *Qy) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->eccp_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->eccp_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_a_ram(0), Px, wordLen); //A0 Px |
| pke_load_operand((unsigned int *)reg_pke_a_ram(1), Py, wordLen); //A1 Py |
| pke_load_operand((unsigned int *)reg_pke_a_ram(5), curve->eccp_a, wordLen); //A5 a |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->eccp_p, wordLen); //B3 p |
| |
| if((0 != curve->eccp_p_h) && (0 != curve->eccp_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->eccp_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->eccp_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| |
| ret = pke_opr_cal(PKE_MICROCODE_PDBL, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(0), Qx, wordLen); |
| if(Qy != 0) |
| { |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qy, wordLen); |
| } |
| |
| return ret; |
| } |
| /** |
| * @brief ECCP curve point add, Q=P1+P2 |
| * @param[in] eccp_curve - ECCP_CURVE struct pointer |
| * @param[in] P1x - x coordinate of point P1 |
| * @param[in] P1y - y coordinate of point P1 |
| * @param[in] P2x - x coordinate of point P2 |
| * @param[in] P2y - y coordinate of point P2 |
| * @param[out] Qx - x coordinate of point Q=P1+P2 |
| * @param[out] Qy - y coordinate of point Q=P1+P2 |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_eccp_point_add(eccp_curve_t *curve, unsigned int *P1x, unsigned int *P1y, unsigned int *P2x, unsigned int *P2y, |
| unsigned int *Qx, unsigned int *Qy) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->eccp_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->eccp_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), P1x, wordLen); //B0 P1x |
| pke_load_operand((unsigned int *)reg_pke_b_ram(1), P1y, wordLen); //B1 P1y |
| pke_load_operand((unsigned int *)reg_pke_a_ram(0), P2x, wordLen); //A0 P2x |
| pke_load_operand((unsigned int *)reg_pke_a_ram(1), P2y, wordLen); //A1 P2y |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->eccp_p, wordLen); //B3 p |
| |
| if((0 != curve->eccp_p_h) && (0 != curve->eccp_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->eccp_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->eccp_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| ret = pke_opr_cal(PKE_MICROCODE_PADD, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(0), Qx, wordLen); |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qy, wordLen); |
| |
| return ret; |
| } |
| /** |
| * @brief check whether the input point P is on ECCP curve or not |
| * @param[in] curve - ECCP_CURVE struct pointer |
| * @param[in] Px - x coordinate of point P |
| * @param[in] Py - y coordinate of point P |
| * @return PKE_SUCCESS(success, on the curve), other(error or not on the curve) |
| */ |
| unsigned char pke_eccp_point_verify(eccp_curve_t *curve, unsigned int *Px, unsigned int *Py) |
| { |
| signed int ret; |
| unsigned int wordLen = (curve->eccp_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->eccp_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), Px, wordLen); //B0 Px |
| pke_load_operand((unsigned int *)reg_pke_b_ram(1), Py, wordLen); //B1 Py |
| pke_load_operand((unsigned int *)reg_pke_a_ram(5), curve->eccp_a, wordLen); //A5 a |
| pke_load_operand((unsigned int *)reg_pke_a_ram(4), curve->eccp_b, wordLen); //A4 b |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->eccp_p, wordLen); //B3 p |
| |
| if((0 != curve->eccp_p_h) && (0 != curve->eccp_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->eccp_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->eccp_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| ret = pke_opr_cal(PKE_MICROCODE_PVER, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| return PKE_SUCCESS; |
| } |
| /** |
| * @brief ECCP curve point mul(random point), Q=[k]P |
| * @param[in] curve - ECCP_CURVE struct pointer |
| * @param[in] k - scalar |
| * @param[in] Px - x coordinate of point P |
| * @param[in] Py - y coordinate of point P |
| * @param[out] Qx - x coordinate of point Q |
| * @param[out] Qy - y coordinate of point Q |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_eccp_point_mul(eccp_curve_t *curve, unsigned int *k, unsigned int *Px, unsigned int *Py, |
| unsigned int *Qx, unsigned int *Qy) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->eccp_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->eccp_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), Px, wordLen); //B0 Px |
| pke_load_operand((unsigned int *)reg_pke_b_ram(1), Py, wordLen); //B1 Py |
| pke_load_operand((unsigned int *)reg_pke_a_ram(5), curve->eccp_a, wordLen); //A5 a |
| pke_load_operand((unsigned int *)reg_pke_a_ram(4), k, wordLen); //A4 k |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->eccp_p, wordLen); //B3 p |
| |
| if((0 != curve->eccp_p_h) && (0 != curve->eccp_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->eccp_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->eccp_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| |
| ret = pke_opr_cal(PKE_MICROCODE_PMUL, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(0), Qx, wordLen); |
| if(Qy != 0) |
| { |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qy, wordLen); |
| } |
| |
| return ret; |
| } |
| /** |
| * @brief out = a*b mod modulus |
| * @param[in] modulus - modulus |
| * @param[in] a - integer a |
| * @param[in] b - integer b |
| * @param[in] wordLen - word length of modulus, a, b |
| * @param[out] out - out = a*b mod modulus |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_mod_mul(const unsigned int *modulus, const unsigned int *a, const unsigned int *b, |
| unsigned int *out, unsigned int wordLen) |
| { |
| unsigned char ret; |
| |
| pke_set_operand_width(wordLen<<5); |
| |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(3)), (unsigned int *)modulus, wordLen); //B3 modulus |
| pke_load_operand((unsigned int *)(reg_pke_a_ram(0)), (unsigned int *)a, wordLen); //A0 a |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(0)), (unsigned int *)b, wordLen); //B0 b |
| |
| ret = pke_opr_cal(PKE_MICROCODE_MODMUL, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)(reg_pke_a_ram(0)), out, wordLen); //A0 result |
| |
| return PKE_SUCCESS; |
| } |
| /** |
| * @brief ainv = a^(-1) mod modulus |
| * @param[in] modulus - modulus |
| * @param[in] a - integer a |
| * @param[in] ainv - ainv = a^(-1) mod modulus |
| * @param[in] modWordLen - word length of modulus, ainv |
| * @param[in] aWordLen - word length of integer a |
| * @return: PKE_SUCCESS(success), other(inverse not exists or error) |
| */ |
| unsigned char pke_mod_inv(const unsigned int *modulus, const unsigned int *a, unsigned int *ainv, unsigned int modWordLen, |
| unsigned int aWordLen) |
| { |
| unsigned char ret; |
| |
| pke_set_operand_width(modWordLen<<5); |
| |
| |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(3)), (unsigned int *)modulus, modWordLen); //B3 modulus |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(0)), (unsigned int *)a, aWordLen); //B0 a |
| |
| ret = pke_opr_cal(PKE_MICROCODE_MODINV, 0x00); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)(reg_pke_a_ram(0)), (unsigned int *)ainv, modWordLen); //A0 ainv |
| |
| return PKE_SUCCESS; |
| } |
| /** |
| * @brief out = (a+b) mod modulus |
| * @param[in] modulus - modulus |
| * @param[in] a - integer a |
| * @param[in] b - integer b |
| * @param[in] wordLen - word length of modulus, a, b |
| * @param[out] out - out = a+b mod modulus |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_mod_add(const unsigned int *modulus, const unsigned int *a, const unsigned int *b, |
| unsigned int *out, unsigned int wordLen) |
| { |
| unsigned char ret; |
| |
| pke_set_operand_width(wordLen<<5); |
| |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(3)), (unsigned int *)modulus, wordLen); //B3 modulus |
| pke_load_operand((unsigned int *)(reg_pke_a_ram(0)), (unsigned int *)a, wordLen); //A0 a |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(0)), (unsigned int *)b, wordLen); //B0 b |
| |
| ret = pke_opr_cal(PKE_MICROCODE_MODADD, 0x00); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)(reg_pke_a_ram(0)), out, wordLen); //A0 result |
| |
| return PKE_SUCCESS; |
| } |
| /** |
| * @brief out = (a-b) mod modulus |
| * @param[in] modulus - input, modulus |
| * @param[in] a - input, integer a |
| * @param[in] b - input, integer b |
| * @param[in] wordLen - input, word length of modulus, a, b |
| * @param[out] out - output, out = a-b mod modulus |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_mod_sub(const unsigned int *modulus, const unsigned int *a, const unsigned int *b, |
| unsigned int *out, unsigned int wordLen) |
| { |
| unsigned char ret; |
| |
| pke_set_operand_width(wordLen<<5); |
| |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(3)), (unsigned int *)modulus, wordLen); //B3 modulus |
| pke_load_operand((unsigned int *)(reg_pke_a_ram(0)), (unsigned int *)a, wordLen); //A0 a |
| pke_load_operand((unsigned int *)(reg_pke_b_ram(0)), (unsigned int *)b, wordLen); //B0 b |
| |
| ret = pke_opr_cal(PKE_MICROCODE_MODSUB, 0x00); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)(reg_pke_a_ram(0)), out, wordLen); //A0 result |
| |
| return PKE_SUCCESS; |
| } |
| /** |
| * @brief c25519 point mul(random point), Q=[k]P |
| * @param[in] curve - c25519 curve struct pointer |
| * @param[in] k - scalar |
| * @param[in] Pu - u coordinate of point P |
| * @param[out] Qu - u coordinate of point Q |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_x25519_point_mul(mont_curve_t *curve, unsigned int *k, unsigned int *Pu, unsigned int *Qu) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->mont_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->mont_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_a_ram(0), Pu, wordLen); //A0 Pu |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), curve->mont_a24, wordLen); //B0 a24 |
| pke_load_operand((unsigned int *)reg_pke_a_ram(4), k, wordLen); //A4 k |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->mont_p, wordLen); //B3 p |
| |
| if((NULL != curve->mont_p_h) && (NULL != curve->mont_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->mont_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->mont_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| |
| ret = pke_opr_cal(PKE_MICROCODE_C25519_PMUL, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qu, wordLen); |
| |
| return ret; |
| } |
| /** |
| * @brief edwards25519 curve point mul(random point), Q=[k]P |
| * @param[in] curve - edwards25519 curve struct pointer |
| * @param[in] k - scalar |
| * @param[in] Px - x coordinate of point P |
| * @param[in] Py - y coordinate of point P |
| * @param[out] Qx - x coordinate of point Q |
| * @param[out] Qy - y coordinate of point Q |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_ed25519_point_mul(edward_curve_t *curve, unsigned int *k, unsigned int *Px, unsigned int *Py, |
| unsigned int *Qx, unsigned int *Qy) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->edward_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->edward_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_a_ram(1), Px, wordLen); //A1 Px |
| pke_load_operand((unsigned int *)reg_pke_a_ram(2), Py, wordLen); //A2 Py |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), curve->edward_d, wordLen); //B0 d |
| pke_load_operand((unsigned int *)reg_pke_a_ram(0), k, wordLen); //A0 k |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->edward_p, wordLen); //B3 p |
| |
| if((0 != curve->edward_p_h) && (0 != curve->edward_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->edward_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->edward_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| |
| ret = pke_opr_cal(PKE_MICROCODE_Ed25519_PMUL, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qx, wordLen); |
| if(Qy != 0) |
| { |
| pke_read_operand((unsigned int *)reg_pke_a_ram(2), Qy, wordLen); |
| } |
| |
| return ret; |
| } |
| /** |
| * @brief edwards25519 point add, Q=P1+P2 |
| * @param[in] curve - edwards25519 curve struct pointer |
| * @param[in] k - scalar |
| * @param[in] P1x - x coordinate of point P1 |
| * @param[in] P1y - y coordinate of point P1 |
| * @param[in] P2x - x coordinate of point P2 |
| * @param[in] P2y - y coordinate of point P2 |
| * @param[out] Qx - x coordinate of point Q=P1+P2 |
| * @param[out] Qy - y coordinate of point Q=P1+P2 |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_ed25519_point_add(edward_curve_t *curve, unsigned int *P1x, unsigned int *P1y, unsigned int *P2x, unsigned int *P2y, |
| unsigned int *Qx, unsigned int *Qy) |
| { |
| unsigned char ret; |
| unsigned int wordLen = (curve->edward_p_bitLen + 31)>>5; |
| |
| pke_set_operand_width(curve->edward_p_bitLen); |
| |
| pke_load_operand((unsigned int *)reg_pke_a_ram(1), P1x, wordLen); //A1 P1x |
| pke_load_operand((unsigned int *)reg_pke_a_ram(2), P1y, wordLen); //A2 P1y |
| pke_load_operand((unsigned int *)reg_pke_b_ram(1), P2x, wordLen); //B1 P2x |
| pke_load_operand((unsigned int *)reg_pke_b_ram(2), P2y, wordLen); //B2 P2y |
| pke_load_operand((unsigned int *)reg_pke_b_ram(0), curve->edward_d, wordLen); //B0 d |
| pke_load_operand((unsigned int *)reg_pke_b_ram(3), curve->edward_p, wordLen); //B3 p |
| |
| if((0 != curve->edward_p_h) && (0 != curve->edward_p_n1)) |
| { |
| pke_load_operand((unsigned int *)reg_pke_a_ram(3), curve->edward_p_h, wordLen); //A3 p_h |
| pke_load_operand((unsigned int *)reg_pke_b_ram(4), curve->edward_p_n1, 1); //B4 p_n1 |
| } |
| else |
| { |
| pke_opr_cal(PKE_MICROCODE_CAL_PRE_MON, 0x00); |
| } |
| |
| ret = pke_opr_cal(PKE_MICROCODE_Ed25519_PADD, PKE_EXE_CFG_ALL_NON_MONT); |
| if(ret) |
| { |
| return ret; |
| } |
| |
| pke_read_operand((unsigned int *)reg_pke_a_ram(1), Qx, wordLen); |
| pke_read_operand((unsigned int *)reg_pke_a_ram(2), Qy, wordLen); |
| |
| return ret; |
| } |
| /** |
| * @brief c = a mod b |
| * @param[in] modulus - modulus |
| * @param[in] a - integer a |
| * @param[in] b - integer b |
| * @param[in] aWordLen - word length of a |
| * @param[in] bWordLen - word length of b |
| * @return PKE_SUCCESS(success), other(error) |
| */ |
| unsigned char pke_mod(unsigned int *a, unsigned int aWordLen, unsigned int *b, unsigned int *b_h, unsigned int *b_n1, |
| unsigned int bWordLen, unsigned int *c) |
| { |
| signed int ret; |
| unsigned int bitLen, tmpLen; |
| unsigned int *a_high, *a_low, *p; |
| |
| ret = big_integer_compare(a, aWordLen, b, bWordLen); |
| if(ret < 0) |
| { |
| aWordLen = valid_words_get(a, aWordLen); |
| memcpy(c, a, aWordLen<<2); |
| memset(c+aWordLen, 0, (bWordLen-aWordLen)<<2); |
| |
| return PKE_SUCCESS; |
| } |
| else if(0 == ret) |
| { |
| memset(c, 0, bWordLen<<2); |
| |
| return PKE_SUCCESS; |
| } |
| |
| bitLen = valid_bits_get(b, bWordLen) & 0x1F; |
| pke_set_operand_width(bWordLen<<5); |
| p = (unsigned int *)reg_pke_a_ram(1); |
| |
| //get a_high mod b |
| a_high = c; |
| if(bitLen) |
| { |
| tmpLen = aWordLen-bWordLen+1; |
| memcpy(p, a+bWordLen-1, tmpLen<<2); |
| div2n_u32(p, tmpLen, bitLen); |
| if(tmpLen < bWordLen) |
| { |
| memset(p+tmpLen, 0, (bWordLen-tmpLen)<<2); |
| } |
| |
| if(big_integer_compare(p, bWordLen, b, bWordLen) >= 0) |
| { |
| sub_u32(p, b, a_high, bWordLen); |
| } |
| else |
| { |
| memcpy(a_high, p, bWordLen<<2); |
| } |
| } |
| else |
| { |
| tmpLen = aWordLen - bWordLen; |
| if(big_integer_compare(a+bWordLen, tmpLen, b, bWordLen) > 0) |
| { |
| sub_u32(a+bWordLen, b, a_high, bWordLen); |
| } |
| else |
| { |
| memcpy(a_high, a+bWordLen, tmpLen<<2); |
| memset(a_high+tmpLen, 0, (bWordLen-tmpLen)<<2); |
| } |
| } |
| |
| if(0 == b_h && 0 == b_n1) |
| { |
| ret = pke_calc_pre_mont(b, bWordLen); |
| if(PKE_SUCCESS != ret) |
| { |
| return ret; |
| } |
| } |
| else |
| { |
| pke_load_pre_calc_mont(b_h, b_n1, bWordLen); |
| } |
| |
| //get 1000...000 mod b |
| memset(p, 0, bWordLen<<2); |
| if(bitLen) |
| { |
| p[bWordLen-1] = 1<<(bitLen); |
| } |
| sub_u32(p, b, (unsigned int *)reg_pke_b_ram(1), bWordLen); |
| |
| |
| //get a_high * 1000..000 mod b |
| pke_set_exe_cfg(PKE_EXE_CFG_ALL_NON_MONT); |
| pke_calc_pre_mont(b, bWordLen); |
| ret = pke_mod_mul(b, (unsigned int *)reg_pke_b_ram(1), a_high, (unsigned int *)reg_pke_b_ram(1), bWordLen); |
| if(PKE_SUCCESS != ret) |
| { |
| return ret; |
| } |
| |
| //get a_low mod b |
| if(bitLen) |
| { |
| a_low = c; |
| memcpy(p, a, bWordLen<<2); |
| p[bWordLen-1] &= ((1<<(bitLen))-1); |
| if(big_integer_compare(p, bWordLen, b, bWordLen) >= 0) |
| { |
| sub_u32(p, b, a_low, bWordLen); |
| } |
| else |
| { |
| memcpy(a_low, p, bWordLen<<2); |
| } |
| } |
| else |
| { |
| if(big_integer_compare(a, bWordLen, b, bWordLen) >= 0) |
| { |
| a_low = c; |
| sub_u32(a, b, a_low, bWordLen); |
| } |
| else |
| { |
| a_low = a; |
| } |
| } |
| |
| return pke_mod_add(b, a_low, (unsigned int *)reg_pke_b_ram(1), c, bWordLen); |
| } |
| |
| |
| |
| |
| |