diff options
| author | auth12 <[email protected]> | 2020-07-22 08:34:12 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-22 08:34:12 -0700 |
| commit | 5015ddb9b1eee748efc24056e46f81888c975f7a (patch) | |
| tree | a810f6ee90f8bfe0e934fdd9142198e6b3862957 /wolfcrypt/src/port/nxp | |
| download | wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.tar.xz wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.zip | |
Initial commit
Diffstat (limited to 'wolfcrypt/src/port/nxp')
| -rw-r--r-- | wolfcrypt/src/port/nxp/ksdk_port.c | 1731 |
1 files changed, 1731 insertions, 0 deletions
diff --git a/wolfcrypt/src/port/nxp/ksdk_port.c b/wolfcrypt/src/port/nxp/ksdk_port.c new file mode 100644 index 0000000..a5cc737 --- /dev/null +++ b/wolfcrypt/src/port/nxp/ksdk_port.c @@ -0,0 +1,1731 @@ +/* ksdk_port.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + +/* If FREESCALE_LTC_TFM or FREESCALE_LTC_ECC */ +#if defined(FREESCALE_LTC_TFM) || defined(FREESCALE_LTC_ECC) + +#include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h> +#include <wolfssl/wolfcrypt/random.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/logging.h> +#include <stdint.h> + +#define ERROR_OUT(res) { ret = (res); goto done; } + + +int ksdk_port_init(void) +{ +#if defined(FREESCALE_LTC_TFM) + LTC_Init(LTC0); +#endif + + return 0; +} + +/* Reverse array in memory (in place) */ +static void ltc_reverse_array(uint8_t *src, size_t src_len) +{ + unsigned int i; + + for (i = 0; i < src_len / 2; i++) { + uint8_t tmp; + + tmp = src[i]; + src[i] = src[src_len - 1 - i]; + src[src_len - 1 - i] = tmp; + } +} + + +#ifndef WOLFSSL_SP_MATH +/* same as mp_to_unsigned_bin() with mp_reverse() skipped */ +static int mp_to_unsigned_lsb_bin(mp_int *a, unsigned char *b) +{ + int res; + mp_int t; + + res = mp_init_copy(&t, a); + if (res == MP_OKAY) { + res = mp_to_unsigned_bin_at_pos(0, &t, b); + if (res >= 0) + res = 0; + #ifndef USE_FAST_MATH + mp_clear(&t); + #endif + } + + return res; +} +#endif + +static int ltc_get_lsb_bin_from_mp_int(uint8_t *dst, mp_int *A, uint16_t *psz) +{ + int res; + uint16_t sz; + + sz = mp_unsigned_bin_size(A); +#ifndef WOLFSSL_SP_MATH + res = mp_to_unsigned_lsb_bin(A, dst); /* result is lsbyte at lowest addr as required by LTC */ +#else + res = mp_to_unsigned_bin(A, dst); + if (res == MP_OKAY) { + ltc_reverse_array(dst, sz); + } +#endif + *psz = sz; + return res; +} + +/* LTC TFM */ +#if defined(FREESCALE_LTC_TFM) + + +/* these function are used by wolfSSL upper layers (like RSA) */ + +/* c = a * b */ +int mp_mul(mp_int *A, mp_int *B, mp_int *C) +{ + int res = MP_OKAY; + int szA, szB; + szA = mp_unsigned_bin_size(A); + szB = mp_unsigned_bin_size(B); + + /* if unsigned mul can fit into LTC PKHA let's use it, otherwise call software mul */ + if ((szA <= LTC_MAX_INT_BYTES / 2) && (szB <= LTC_MAX_INT_BYTES / 2)) { + int neg = 0; + +#ifndef WOLFSSL_SP_MATH + neg = (A->sign == B->sign) ? MP_ZPOS : MP_NEG; +#endif + + /* unsigned multiply */ + uint8_t *ptrA = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrB = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrC = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + + if (ptrA && ptrB && ptrC) { + uint16_t sizeA, sizeB; + + res = ltc_get_lsb_bin_from_mp_int(ptrA, A, &sizeA); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrB, B, &sizeB); + if (res == MP_OKAY) { + XMEMSET(ptrC, 0xFF, LTC_MAX_INT_BYTES); + + LTC_PKHA_ModMul(LTC_BASE, ptrA, sizeA, ptrB, sizeB, ptrC, LTC_MAX_INT_BYTES, ptrB, &sizeB, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + + ltc_reverse_array(ptrB, sizeB); + res = mp_read_unsigned_bin(C, ptrB, sizeB); + } + } + +#ifndef WOLFSSL_SP_MATH + /* fix sign */ + C->sign = neg; +#endif + if (ptrA) { + XFREE(ptrA, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrB) { + XFREE(ptrB, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrC) { + XFREE(ptrC, NULL, DYNAMIC_TYPE_BIGINT); + } + } + else { +#ifdef WOLFSSL_SP_MATH + res = sp_mul(A, B, C); +#else + res = wolfcrypt_mp_mul(A, B, C); +#endif + } + return res; +} + +/* c = a mod b, 0 <= c < b */ +int mp_mod(mp_int *a, mp_int *b, mp_int *c) +{ + int res = MP_OKAY; +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + int szA, szB; + szA = mp_unsigned_bin_size(a); + szB = mp_unsigned_bin_size(b); + if ((szA <= LTC_MAX_INT_BYTES) && (szB <= LTC_MAX_INT_BYTES)) + { +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + int neg = 0; + uint8_t *ptrA = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrB = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrC = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + +#ifndef WOLFSSL_SP_MATH + /* get sign for the result */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; +#endif + + /* get remainder of unsigned a divided by unsigned b */ + if (ptrA && ptrB && ptrC) { + uint16_t sizeA, sizeB, sizeC; + + res = ltc_get_lsb_bin_from_mp_int(ptrA, a, &sizeA); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrB, b, &sizeB); + if (res == MP_OKAY) { + if (kStatus_Success == + LTC_PKHA_ModRed(LTC_BASE, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC, kLTC_PKHA_IntegerArith)) + { + ltc_reverse_array(ptrC, sizeC); + res = mp_read_unsigned_bin(c, ptrC, sizeC); + } + else { + res = MP_VAL; + } + } + } + else { + res = MP_MEM; + } + +#ifndef WOLFSSL_SP_MATH + /* fix sign */ + c->sign = neg; +#endif + + if (ptrA) { + XFREE(ptrA, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrB) { + XFREE(ptrB, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrC) { + XFREE(ptrC, NULL, DYNAMIC_TYPE_BIGINT); + } +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + } + else { + res = wolfcrypt_mp_mod(a, b, c); + } +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + return res; +} + +/* c = 1/a (mod b) for odd b only */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c) +{ + int res = MP_OKAY; +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + int szA, szB; + szA = mp_unsigned_bin_size(a); + szB = mp_unsigned_bin_size(b); + if ((szA <= LTC_MAX_INT_BYTES) && (szB <= LTC_MAX_INT_BYTES)) { +#endif + uint8_t *ptrA = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrB = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrC = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + + if (ptrA && ptrB && ptrC) { + uint16_t sizeA, sizeB, sizeC; + + res = ltc_get_lsb_bin_from_mp_int(ptrA, a, &sizeA); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrB, b, &sizeB); + if (res == MP_OKAY) { + if (kStatus_Success == + LTC_PKHA_ModInv(LTC_BASE, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC, kLTC_PKHA_IntegerArith)) + { + ltc_reverse_array(ptrC, sizeC); + res = mp_read_unsigned_bin(c, ptrC, sizeC); + } + else { + res = MP_VAL; + } + } + } + else { + res = MP_MEM; + } + +#ifndef WOLFSSL_SP_MATH + c->sign = a->sign; +#endif + if (ptrA) { + XFREE(ptrA, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrB) { + XFREE(ptrB, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrC) { + XFREE(ptrC, NULL, DYNAMIC_TYPE_BIGINT); + } +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + } + else { + res = wolfcrypt_mp_invmod(a, b, c); + } +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + return res; +} + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + int res = MP_OKAY; +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + int szA, szB, szC; + szA = mp_unsigned_bin_size(a); + szB = mp_unsigned_bin_size(b); + szC = mp_unsigned_bin_size(c); + if ((szA <= LTC_MAX_INT_BYTES) && (szB <= LTC_MAX_INT_BYTES) && (szC <= LTC_MAX_INT_BYTES)) { +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + mp_int t; + + uint8_t *ptrA = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, NULL, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrB = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, NULL, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrC = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, NULL, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrD = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, NULL, DYNAMIC_TYPE_BIGINT); + + /* if A or B is negative, subtract abs(A) or abs(B) from modulus to get positive integer representation of the + * same number */ + res = mp_init(&t); +#ifndef WOLFSSL_SP_MATH + if (a->sign) { + if (res == MP_OKAY) + res = mp_add(a, c, &t); + if (res == MP_OKAY) + res = mp_copy(&t, a); + } + if (b->sign) { + if (res == MP_OKAY) + res = mp_add(b, c, &t); + if (res == MP_OKAY) + res = mp_copy(&t, b); + } +#endif + + if (res == MP_OKAY && ptrA && ptrB && ptrC && ptrD) { + uint16_t sizeA, sizeB, sizeC, sizeD; + + res = ltc_get_lsb_bin_from_mp_int(ptrA, a, &sizeA); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrB, b, &sizeB); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrC, c, &sizeC); + + /* (A*B)mod C = ((A mod C) * (B mod C)) mod C */ + if (res == MP_OKAY && LTC_PKHA_CompareBigNum(ptrA, sizeA, ptrC, sizeC) >= 0) { + if (kStatus_Success != + LTC_PKHA_ModRed(LTC_BASE, ptrA, sizeA, ptrC, sizeC, ptrA, &sizeA, kLTC_PKHA_IntegerArith)) + { + res = MP_VAL; + } + } + if (res == MP_OKAY && (LTC_PKHA_CompareBigNum(ptrB, sizeB, ptrC, sizeC) >= 0)) + { + if (kStatus_Success != + LTC_PKHA_ModRed(LTC_BASE, ptrB, sizeB, ptrC, sizeC, ptrB, &sizeB, kLTC_PKHA_IntegerArith)) + { + res = MP_VAL; + } + } + + if (res == MP_OKAY) { + if (kStatus_Success != LTC_PKHA_ModMul(LTC_BASE, ptrA, sizeA, ptrB, sizeB, ptrC, sizeC, ptrD, &sizeD, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized)) + { + res = MP_VAL; + } + } + + if (res == MP_OKAY) { + ltc_reverse_array(ptrD, sizeD); + res = mp_read_unsigned_bin(d, ptrD, sizeD); + } + } + else { + res = MP_MEM; + } + + if (ptrA) { + XFREE(ptrA, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrB) { + XFREE(ptrB, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrC) { + XFREE(ptrC, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrD) { + XFREE(ptrD, NULL, DYNAMIC_TYPE_BIGINT); + } + #ifndef USE_FAST_MATH + mp_clear(&t); + #endif +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + } + else { + res = wolfcrypt_mp_mulmod(a, b, c, d); + } +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + return res; +} + +/* Y = G^X mod P */ +int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) +{ + int res = MP_OKAY; +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + int szA, szB, szC; + mp_int tmp; + + /* if G cannot fit into LTC_PKHA, reduce it */ + szA = mp_unsigned_bin_size(G); + if (szA > LTC_MAX_INT_BYTES) { + res = mp_init(&tmp); + if (res != MP_OKAY) + return res; + if ((res = mp_mod(G, P, &tmp)) != MP_OKAY) { + return res; + } + G = &tmp; + szA = mp_unsigned_bin_size(G); + } + + szB = mp_unsigned_bin_size(X); + szC = mp_unsigned_bin_size(P); + + if ((szA <= LTC_MAX_INT_BYTES) && (szB <= LTC_MAX_INT_BYTES) && (szC <= LTC_MAX_INT_BYTES)) { +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + mp_int t; + + uint16_t sizeG, sizeX, sizeP; + uint8_t *ptrG = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrX = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + uint8_t *ptrP = (uint8_t *)XMALLOC(LTC_MAX_INT_BYTES, 0, DYNAMIC_TYPE_BIGINT); + + /* if G is negative, add modulus to convert to positive number for LTC */ + res = mp_init(&t); +#ifndef WOLFSSL_SP_MATH + if (G->sign) { + if (res == MP_OKAY) + res = mp_add(G, P, &t); + if (res == MP_OKAY) + res = mp_copy(&t, G); + } +#endif + + if (res == MP_OKAY && ptrG && ptrX && ptrP) { + res = ltc_get_lsb_bin_from_mp_int(ptrG, G, &sizeG); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrX, X, &sizeX); + if (res == MP_OKAY) + res = ltc_get_lsb_bin_from_mp_int(ptrP, P, &sizeP); + + /* if number if greater that modulo, we must first reduce due to LTC requirement on modular exponentiaton */ + /* it needs number less than modulus. */ + /* we can take advantage of modular arithmetic rule that: A^B mod C = ( (A mod C)^B ) mod C + and so we do first (A mod N) : LTC does not give size requirement on A versus N, + and then the modular exponentiation. + */ + /* if G >= P then */ + if (res == MP_OKAY && LTC_PKHA_CompareBigNum(ptrG, sizeG, ptrP, sizeP) >= 0) { + res = (int)LTC_PKHA_ModRed(LTC_BASE, ptrG, sizeG, ptrP, sizeP, ptrG, &sizeG, kLTC_PKHA_IntegerArith); + + if (res != kStatus_Success) { + res = MP_VAL; + } + } + + if (res == MP_OKAY) { + res = (int)LTC_PKHA_ModExp(LTC_BASE, ptrG, sizeG, ptrP, sizeP, ptrX, sizeX, ptrP, &sizeP, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + + if (res != kStatus_Success) { + res = MP_VAL; + } + else { + ltc_reverse_array(ptrP, sizeP); + res = mp_read_unsigned_bin(Y, ptrP, sizeP); + } + } + } + else { + res = MP_MEM; + } + + if (ptrG) { + XFREE(ptrG, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrX) { + XFREE(ptrX, NULL, DYNAMIC_TYPE_BIGINT); + } + if (ptrP) { + XFREE(ptrP, NULL, DYNAMIC_TYPE_BIGINT); + } + #ifndef USE_FAST_MATH + mp_clear(&t); + #endif +#if defined(FREESCALE_LTC_TFM_RSA_4096_ENABLE) + } + else { + res = wolfcrypt_mp_exptmod(G, X, P, Y); + } + +#ifndef USE_FAST_MATH + if (szA > LTC_MAX_INT_BYTES) + mp_clear(&tmp); +#endif +#endif /* FREESCALE_LTC_TFM_RSA_4096_ENABLE */ + return res; +} + +#endif /* FREESCALE_LTC_TFM */ + + +/* ECC */ +#if defined(HAVE_ECC) && defined(FREESCALE_LTC_ECC) + +/* convert from mp_int to LTC integer, as array of bytes of size sz. + * if mp_int has less bytes than sz, add zero bytes at most significant byte positions. + * This is when for example modulus is 32 bytes (P-256 curve) + * and mp_int has only 31 bytes, we add leading zeros + * so that result array has 32 bytes, same as modulus (sz). + */ +static int ltc_get_from_mp_int(uint8_t *dst, mp_int *a, int sz) +{ + int res; + int szbin; + int offset; + + /* check how many bytes are in the mp_int */ + szbin = mp_unsigned_bin_size(a); + + /* compute offset from dst */ + offset = sz - szbin; + if (offset < 0) + offset = 0; + if (offset > sz) + offset = sz; + + /* add leading zeroes */ + if (offset) + XMEMSET(dst, 0, offset); + + /* convert mp_int to array of bytes */ + res = mp_to_unsigned_bin(a, dst + offset); + + if (res == MP_OKAY) { + /* reverse array for LTC direct use */ + ltc_reverse_array(dst, sz); + } + + return res; +} + +/* ECC specs in lsbyte at lowest address format for direct use by LTC PKHA driver functions */ +#if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES) +#define ECC192 +#endif +#if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) +#define ECC224 +#endif +#if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) +#define ECC256 +#endif +#if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) +#define ECC384 +#endif + +/* P-256 */ +#ifdef ECC256 +static const uint8_t ltc_ecc256_modulus[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc256_r2modn[32] = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00}; +static const uint8_t ltc_ecc256_aCurveParam[32] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc256_bCurveParam[32] = { + 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, 0xF6, 0xB0, 0x53, + 0xCC, 0xB0, 0x06, 0x1D, 0x65, 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, + 0xEB, 0xB3, 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A}; +#endif + +#ifdef ECC192 +static const uint8_t ltc_ecc192_modulus[24] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc192_r2modn[24] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t ltc_ecc192_aCurveParam[24] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc192_bCurveParam[24] = { + 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, 0x49, 0x30, 0x24, 0x72, + 0xAB, 0xE9, 0xA7, 0x0F, 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64}; +#endif + +#ifdef ECC224 +static const uint8_t ltc_ecc224_modulus[28] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc224_r2modn[28] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t ltc_ecc224_aCurveParam[28] = { + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static const uint8_t ltc_ecc224_bCurveParam[28] = { + 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, 0xBA, 0xD8, + 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, 0x56, 0x32, 0x41, 0xF5, + 0xAB, 0xB3, 0x04, 0x0C, 0x85, 0x0A, 0x05, 0xB4}; +#endif + +#ifdef ECC384 +static const uint8_t ltc_ecc384_modulus[48] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const uint8_t ltc_ecc384_r2modn[48] = { + 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t ltc_ecc384_aCurveParam[48] = { + 0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const uint8_t ltc_ecc384_bCurveParam[48] = { + 0xef, 0x2a, 0xec, 0xd3, 0xed, 0xc8, 0x85, 0x2a, 0x9d, 0xd1, 0x2e, 0x8a, + 0x8d, 0x39, 0x56, 0xc6, 0x5a, 0x87, 0x13, 0x50, 0x8f, 0x08, 0x14, 0x03, + 0x12, 0x41, 0x81, 0xfe, 0x6e, 0x9c, 0x1d, 0x18, 0x19, 0x2d, 0xf8, 0xe3, + 0x6b, 0x05, 0x8e, 0x98, 0xe4, 0xe7, 0x3e, 0xe2, 0xa7, 0x2f, 0x31, 0xb3}; +#endif + +static int ltc_get_ecc_specs(const uint8_t **modulus, const uint8_t **r2modn, + const uint8_t **aCurveParam, const uint8_t **bCurveParam, int size) +{ + switch(size) { + case 32: + *modulus = ltc_ecc256_modulus; + *r2modn = ltc_ecc256_r2modn; + *aCurveParam = ltc_ecc256_aCurveParam; + *bCurveParam = ltc_ecc256_bCurveParam; + break; +#ifdef ECC224 + case 28: + *modulus = ltc_ecc224_modulus; + *r2modn = ltc_ecc224_r2modn; + *aCurveParam = ltc_ecc224_aCurveParam; + *bCurveParam = ltc_ecc224_bCurveParam; + break; +#endif +#ifdef ECC192 + case 24: + *modulus = ltc_ecc192_modulus; + *r2modn = ltc_ecc192_r2modn; + *aCurveParam = ltc_ecc192_aCurveParam; + *bCurveParam = ltc_ecc192_bCurveParam; + break; +#endif +#ifdef HAVE_ECC384 + case 48: + *modulus = ltc_ecc384_modulus; + *r2modn = ltc_ecc384_r2modn; + *aCurveParam = ltc_ecc384_aCurveParam; + *bCurveParam = ltc_ecc384_bCurveParam; + break; +#endif + default: + return -1; + } + return 0; +} + +/** + Perform a point multiplication (timing resistant) + k The scalar to multiply by + G The base point + R [out] Destination for kG + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +int wc_ecc_mulmod_ex(mp_int *k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int *modulus, int map, void* heap) +{ + ltc_pkha_ecc_point_t B; + uint8_t size; + int szModulus; + int szkbin; + bool point_of_infinity; + status_t status; + int res; + + (void)a; + (void)heap; + + uint8_t Gxbin[LTC_MAX_ECC_BITS / 8]; + uint8_t Gybin[LTC_MAX_ECC_BITS / 8]; + uint8_t kbin[LTC_MAX_INT_BYTES]; + + const uint8_t *modbin; + const uint8_t *aCurveParam; + const uint8_t *bCurveParam; + const uint8_t *r2modn; + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + szModulus = mp_unsigned_bin_size(modulus); + szkbin = mp_unsigned_bin_size(k); + + res = ltc_get_from_mp_int(kbin, k, szkbin); + if (res == MP_OKAY) + res = ltc_get_from_mp_int(Gxbin, G->x, szModulus); + if (res == MP_OKAY) + res = ltc_get_from_mp_int(Gybin, G->y, szModulus); + + if (res != MP_OKAY) + return res; + + size = szModulus; + /* find LTC friendly parameters for the selected curve */ + if (0 != ltc_get_ecc_specs(&modbin, &r2modn, &aCurveParam, &bCurveParam, size)) { + return ECC_BAD_ARG_E; + } + + B.X = &Gxbin[0]; + B.Y = &Gybin[0]; + + status = LTC_PKHA_ECC_PointMul(LTC_BASE, &B, kbin, szkbin, modbin, r2modn, aCurveParam, bCurveParam, size, + kLTC_PKHA_TimingEqualized, kLTC_PKHA_IntegerArith, &B, &point_of_infinity); + if (status != kStatus_Success) { + return MP_VAL; + } + + ltc_reverse_array(Gxbin, size); + ltc_reverse_array(Gybin, size); + res = mp_read_unsigned_bin(R->x, Gxbin, size); + if (res == MP_OKAY) { + res = mp_read_unsigned_bin(R->y, Gybin, size); + /* if k is negative, we compute the multiplication with abs(-k) + * with result (x, y) and modify the result to (x, -y) + */ +#ifndef WOLFSSL_SP_MATH + R->y->sign = k->sign; +#endif + } + if (res == MP_OKAY) + res = mp_set(R->z, 1); + + return res; +} + +int wc_ecc_point_add(ecc_point *mG, ecc_point *mQ, ecc_point *mR, mp_int *m) +{ + int res; + ltc_pkha_ecc_point_t A, B; + int size; + status_t status; + + uint8_t Gxbin[LTC_MAX_ECC_BITS / 8]; + uint8_t Gybin[LTC_MAX_ECC_BITS / 8]; + uint8_t Qxbin[LTC_MAX_ECC_BITS / 8]; + uint8_t Qybin[LTC_MAX_ECC_BITS / 8]; + const uint8_t *modbin; + const uint8_t *aCurveParam; + const uint8_t *bCurveParam; + const uint8_t *r2modn; + + size = mp_unsigned_bin_size(m); + + /* find LTC friendly parameters for the selected curve */ + if (ltc_get_ecc_specs(&modbin, &r2modn, &aCurveParam, &bCurveParam, size) != 0) { + res = ECC_BAD_ARG_E; + } + else { + res = ltc_get_from_mp_int(Gxbin, mG->x, size); + if (res == MP_OKAY) + res = ltc_get_from_mp_int(Gybin, mG->y, size); + if (res == MP_OKAY) + res = ltc_get_from_mp_int(Qxbin, mQ->x, size); + if (res == MP_OKAY) + res = ltc_get_from_mp_int(Qybin, mQ->y, size); + + if (res != MP_OKAY) + return res; + + A.X = Gxbin; + A.Y = Gybin; + + B.X = Qxbin; + B.Y = Qybin; + + status = LTC_PKHA_ECC_PointAdd(LTC_BASE, &A, &B, modbin, r2modn, aCurveParam, bCurveParam, size, + kLTC_PKHA_IntegerArith, &A); + if (status != kStatus_Success) { + res = MP_VAL; + } + else { + ltc_reverse_array(Gxbin, size); + ltc_reverse_array(Gybin, size); + res = mp_read_unsigned_bin(mR->x, Gxbin, size); + if (res == MP_OKAY) + res = mp_read_unsigned_bin(mR->y, Gybin, size); + if (res == MP_OKAY) + res = mp_set(mR->z, 1); + } + } + return res; +} + +#if defined(HAVE_ED25519) || defined(HAVE_CURVE25519) +/* Weierstrass parameters of prime 2^255 - 19 */ +static const uint8_t curve25519_modbin[32] = { + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; +/* precomputed R2modN for the curve25519 */ +static const uint8_t r2mod[32] = { + 0xa4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* invThree = ModInv(3,curve25519_modbin) in LSB first */ +static const uint8_t invThree[32] = { + 0x49, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; + +/* + * + * finds square root in finite field when modulus congruent to 5 modulo 8 + * this is fixed to curve25519 modulus 2^255 - 19 which is congruent to 5 modulo 8 + * + * This function solves equation: res^2 = a mod (2^255 - 19) + * +p = prime +p % 8 must be 5 + +v = ModularArithmetic.powmod(2*a, (p-5)/8, p) +i = (2*a*v**2) % p +r1 = 1*a*v*(i - 1) % p +r2 = -1*a*v*(i - 1) % p +puts "Gy=0x#{r2.to_s(16)}" + */ +status_t LTC_PKHA_Prime25519SquareRootMod(const uint8_t *A, size_t sizeA, + uint8_t *res, size_t *szRes, int sign) +{ + status_t status; + const uint8_t curve25519_param[] = { + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f}; + uint8_t twoA[sizeof(curve25519_modbin)] = {0}; + uint8_t V[sizeof(curve25519_modbin)] = {0}; + uint8_t I[sizeof(curve25519_modbin)] = {0}; + uint8_t VV[sizeof(curve25519_modbin)] = {0}; + uint16_t szTwoA = 0; + uint16_t szV = 0; + uint16_t szVV = 0; + uint16_t szI = 0; + uint16_t szRes16 = 0; + uint8_t one = 1; + + /* twoA = 2*A % p */ + status = LTC_PKHA_ModAdd(LTC_BASE, A, sizeA, A, sizeA, curve25519_modbin, + sizeof(curve25519_modbin), twoA, &szTwoA, kLTC_PKHA_IntegerArith); + + /* V = ModularArithmetic.powmod(twoA, (p-5)/8, p) */ + if (status == kStatus_Success) { + status = + LTC_PKHA_ModExp(LTC_BASE, twoA, szTwoA, curve25519_modbin, + sizeof(curve25519_modbin), curve25519_param, + sizeof(curve25519_param), V, &szV, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* VV = V*V % p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, V, szV, V, szV, curve25519_modbin, + sizeof(curve25519_modbin), VV, &szVV, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + + /* I = twoA * VV = 2*A*V*V % p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, twoA, szTwoA, VV, szVV, + curve25519_modbin, sizeof(curve25519_modbin), I, &szI, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* I = I - 1 */ + XMEMSET(VV, 0xff, sizeof(VV)); /* just temp for maximum integer - for non-modular subtract */ + if (0 <= LTC_PKHA_CompareBigNum(I, szI, &one, sizeof(one))) { + if (status == kStatus_Success) { + status = LTC_PKHA_ModSub1(LTC_BASE, I, szI, &one, sizeof(one), + VV, sizeof(VV), I, &szI); + } + } + else { + if (status == kStatus_Success) { + status = LTC_PKHA_ModSub1(LTC_BASE, curve25519_modbin, + sizeof(curve25519_modbin), &one, sizeof(one), VV, sizeof(VV), I, + &szI); + } + } + + /* res = a*v mod p */ + status = LTC_PKHA_ModMul(LTC_BASE, A, sizeA, V, szV, curve25519_modbin, + sizeof(curve25519_modbin), res, &szRes16, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + + /* res = res * (i-1) mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, res, szRes16, I, szI, + curve25519_modbin, sizeof(curve25519_modbin), res, &szRes16, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* if X mod 2 != X_0 then we need the -X + * + * X mod 2 get from LSB bit0 + */ + if ((status == kStatus_Success) && + ((bool)sign != (bool)(res[0] & 0x01u))) + { + status = LTC_PKHA_ModSub1(LTC_BASE, curve25519_modbin, + sizeof(curve25519_modbin), res, szRes16, VV, sizeof(VV), res, + &szRes16); /* -a = p - a */ + } + + if (status == kStatus_Success) { + *szRes = szRes16; + } + + return status; +} +#endif /* HAVE_ED25519 || HAVE_CURVE25519 */ + + +#ifdef HAVE_CURVE25519 + +/* for LTC we need Weierstrass format of curve25519 parameters + * these two are base point X and Y. + * in LSB first format (native for LTC) + */ +static const ECPoint ecBasePoint = { + {0x5a, 0x24, 0xad, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a}, + {0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29, 0xb2, 0x61, 0x7c, + 0x6d, 0x7e, 0x4d, 0x3d, 0x92, 0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, + 0x1e, 0xe0, 0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20}, +}; + +const ECPoint *wc_curve25519_GetBasePoint(void) +{ + return &ecBasePoint; +} + +static const uint8_t curve25519_aCurveParam[CURVE25519_KEYSIZE] = { + 0x44, 0xa1, 0x14, 0x49, 0x98, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x2a}; + +static const uint8_t curve_bCurveParam[CURVE25519_KEYSIZE] = { + 0x64, 0xc8, 0x10, 0x77, 0x9c, 0x5e, 0x0b, 0x26, 0xb4, 0x97, 0xd0, + 0x5e, 0x42, 0x7b, 0x09, 0xed, + 0x25, 0xb4, 0x97, 0xd0, 0x5e, 0x42, 0x7b, 0x09, 0xed, 0x25, 0xb4, + 0x97, 0xd0, 0x5e, 0x42, 0x7b}; + +/* transform a point on Montgomery curve to a point on Weierstrass curve */ +status_t LTC_PKHA_Curve25519ToWeierstrass( + const ltc_pkha_ecc_point_t *ltcPointIn,ltc_pkha_ecc_point_t *ltcPointOut) +{ + /* offset X point (in Montgomery) so that it becomes Weierstrass */ + const uint8_t offset[] = { + 0x51, 0x24, 0xad, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a}; + uint16_t sizeRes = 0; + status_t status; + status = LTC_PKHA_ModAdd(LTC_BASE, ltcPointIn->X, CURVE25519_KEYSIZE, + offset, sizeof(offset), curve25519_modbin, CURVE25519_KEYSIZE, + ltcPointOut->X, &sizeRes, kLTC_PKHA_IntegerArith); + + if (status == kStatus_Success) { + if (ltcPointOut->Y != ltcPointIn->Y) { + XMEMCPY(ltcPointOut->Y, ltcPointIn->Y, CURVE25519_KEYSIZE); + } + } + + return status; +} + +/* transform a point on Weierstrass curve to a point on Montgomery curve */ +status_t LTC_PKHA_WeierstrassToCurve25519( + const ltc_pkha_ecc_point_t *ltcPointIn, ltc_pkha_ecc_point_t *ltcPointOut) +{ + status_t status; + uint16_t resultSize = 0; + const uint8_t three = 0x03; + + status = LTC_PKHA_ModMul(LTC_BASE, &three, sizeof(three), ltcPointIn->X, + CURVE25519_KEYSIZE, curve25519_modbin, CURVE25519_KEYSIZE, + ltcPointOut->X, &resultSize, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + + if (status == kStatus_Success) { + const uint8_t A[] = {0x06, 0x6d, 0x07}; + if (LTC_PKHA_CompareBigNum(ltcPointOut->X, resultSize, A, sizeof(A))) { + status = LTC_PKHA_ModSub1(LTC_BASE, ltcPointOut->X, resultSize, A, + sizeof(A), curve25519_modbin, CURVE25519_KEYSIZE, + ltcPointOut->X, &resultSize); + } + else { + status = LTC_PKHA_ModSub2(LTC_BASE, ltcPointOut->X, resultSize, A, + sizeof(A), curve25519_modbin, CURVE25519_KEYSIZE, + ltcPointOut->X, &resultSize); + } + } + + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, invThree, CURVE25519_KEYSIZE, + ltcPointOut->X, resultSize, curve25519_modbin, CURVE25519_KEYSIZE, + ltcPointOut->X, &resultSize, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + + if (status == kStatus_Success) { + if (ltcPointOut->Y != ltcPointIn->Y) { + XMEMCPY(ltcPointOut->Y, ltcPointIn->Y, CURVE25519_KEYSIZE); + } + } + + return status; +} + +/* Y = square root (X^3 + 486662*X^2 + X) */ +status_t LTC_PKHA_Curve25519ComputeY(ltc_pkha_ecc_point_t *ltcPoint) +{ + uint8_t three = 3; + const uint8_t A[] = {0x06, 0x6d, 0x07}; + uint8_t U[CURVE25519_KEYSIZE] = {0}; + uint8_t X2[CURVE25519_KEYSIZE] = {0}; + uint16_t sizeU = 0; + uint16_t sizeX2 = 0; + size_t szRes = 0; + status_t status; + + /* X^3 */ + status = LTC_PKHA_ModExp(LTC_BASE, ltcPoint->X, CURVE25519_KEYSIZE, + curve25519_modbin, CURVE25519_KEYSIZE, &three, 1, U, &sizeU, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + + /* X^2 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, ltcPoint->X, CURVE25519_KEYSIZE, + ltcPoint->X, CURVE25519_KEYSIZE, curve25519_modbin, + CURVE25519_KEYSIZE, X2, &sizeX2, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + + /* 486662*X^2 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, A, sizeof(A), X2, sizeX2, + curve25519_modbin, CURVE25519_KEYSIZE, X2, &sizeX2, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* X^3 + 486662*X^2 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, U, sizeU, X2, sizeX2, + curve25519_modbin, CURVE25519_KEYSIZE, U, &sizeU, + kLTC_PKHA_IntegerArith); + } + + /* U = X^3 + 486662*X^2 + X */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, U, sizeU, ltcPoint->X, + CURVE25519_KEYSIZE, curve25519_modbin, CURVE25519_KEYSIZE, U, + &sizeU, kLTC_PKHA_IntegerArith); + } + + /* Y = modular square root of U (U is Y^2) */ + if (status == kStatus_Success) { + status = LTC_PKHA_Prime25519SquareRootMod(U, sizeU, ltcPoint->Y, + &szRes, 1); + } + + return status; +} + +/* Q = n*P */ +/* if type is set, the input point p is in Montgomery curve coordinates, + so there is a map to Weierstrass curve */ +/* q output point is always in Montgomery curve coordinates */ +int wc_curve25519(ECPoint *q, byte *n, const ECPoint *p, fsl_ltc_ecc_coordinate_system_t type) +{ + status_t status; + ltc_pkha_ecc_point_t ltcPoint; + ltc_pkha_ecc_point_t ltcPointOut; + ECPoint pIn = {{0}}; + + XMEMCPY(&pIn, p, sizeof(*p)); + ltcPoint.X = &pIn.point[0]; + ltcPoint.Y = &pIn.pointY[0]; + + /* if input point P is on Curve25519 Montgomery curve, transform + it to Weierstrass equivalent */ + if (type == kLTC_Curve25519) { + LTC_PKHA_Curve25519ToWeierstrass(<cPoint, <cPoint); + } + + ltcPointOut.X = &q->point[0]; + ltcPointOut.Y = &q->pointY[0]; + /* curve25519_modbin, r2mod, curve25519_aCurveParam, curve25519_bCurveParam + * are Weierstrass equivalent with Curve25519 */ + status = LTC_PKHA_ECC_PointMul(LTC_BASE, <cPoint, n, CURVE25519_KEYSIZE, + curve25519_modbin, r2mod, curve25519_aCurveParam, + curve25519_bCurveParam, CURVE25519_KEYSIZE, kLTC_PKHA_TimingEqualized, + kLTC_PKHA_IntegerArith, <cPointOut, NULL); + + /* now need to map from Weierstrass form to Montgomery form */ + if (status == kStatus_Success) { + status = LTC_PKHA_WeierstrassToCurve25519(<cPointOut, <cPointOut); + } + + return (status == kStatus_Success) ? 0 : IS_POINT_E; +} + +#endif /* HAVE_CURVE25519 */ + + +#ifdef HAVE_ED25519 +/* a and d are Edwards curve parameters -1 and -121665/121666 prime is 2^255 - 19. + * + * https://en.wikipedia.org/wiki/Montgomery_curve#Equivalence_with_Edward_curves + */ + +/* d parameter of ed25519 */ +static const uint8_t d_coefEd25519[] = { + 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, + 0x41, 0x4d, 0x0a, 0x70, 0x00, 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, + 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52}; + +/* Montgomery curve parameter A for a Montgomery curve equivalent with ed25519 */ +static const uint8_t A_coefEd25519[] = { + 0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* Montgomery curve parameter B for a Montgomery curve equivalent with ed25519 */ +static const uint8_t B_coefEd25519[] = { + 0xe5, 0x92, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; + +/* these are pre-computed constants used in computations */ + +/* = 3*B */ +static const uint8_t threeB_coefEd25519[] = { + 0xd5, 0xb8, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; + +/* = -A */ +static const uint8_t minus_A_coefEd25519[] = { + 0xe7, 0x92, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; + +/* = 1/B */ +static const uint8_t invB_coefEd25519[] = { +0xc4, 0xa1, 0x29, 0x7b, 0x8d, 0x2c, 0x85, 0x22, 0xd5, 0x89, 0xaf, + 0xaf, 0x6c, 0xfd, 0xe3, 0xff, 0xd9, 0x85, 0x21, 0xa2, 0xe1, 0x2f, + 0xce, 0x1c, 0x63, 0x00, 0x24, 0x75, 0xc4, 0x24, 0x7f, 0x6b}; + +/* = 1/(3*B) */ +static const uint8_t A_mul_invThreeB_coefEd25519[] = { + 0xb9, 0x3e, 0xe4, 0xad, 0xa1, 0x37, 0xa7, 0x93, 0x1c, 0xa4, 0x35, + 0xe0, 0x0c, 0x57, 0xbd, 0xaa, 0x6e, 0x51, 0x94, 0x3e, 0x14, 0xe0, + 0xcb, 0xec, 0xbd, 0xff, 0xe7, 0xb1, 0x27, 0x92, 0x00, 0x63}; + +/* Weierstrass curve parameter a for a Weierstrass curve equivalent with ed25519 */ +static const uint8_t a_coefEd25519[] = { + 0x2d, 0x17, 0xbc, 0xf8, 0x8e, 0xe1, 0x71, 0xac, 0xf7, 0x2a, 0xa5, + 0x0c, 0x5d, 0xb6, 0xb8, 0x6b, 0xd6, 0x3d, 0x7b, 0x61, 0x0d, 0xe1, + 0x97, 0x31, 0xe6, 0xbe, 0xb9, 0xa5, 0xd3, 0xac, 0x4e, 0x5d}; + +/* Weierstrass curve parameter b for a Weierstrass curve equivalent with ed25519 */ +static const uint8_t b_coefEd25519[] = { + 0xa4, 0xb2, 0x64, 0xf3, 0xc1, 0xeb, 0x04, 0x90, 0x32, 0xbc, 0x9f, + 0x6b, 0x97, 0x31, 0x48, 0xf5, 0xd5, 0x80, 0x57, 0x10, 0x06, 0xdb, + 0x0d, 0x55, 0xe0, 0xb3, 0xd0, 0xcf, 0x9b, 0xb2, 0x11, 0x1d}; + +/* Ed25519 basepoint B mapped to Weierstrass equivalent */ +static uint8_t Wx_Ed25519[ED25519_KEY_SIZE] = { + 0x35, 0xef, 0x5a, 0x02, 0x9b, 0xc8, 0x55, 0xca, 0x9a, 0x7c, 0x61, + 0x0d, 0xdf, 0x3f, 0xc1, 0xa9, 0x18, 0x06, 0xc2, 0xf1, 0x02, 0x8f, + 0x0b, 0xf0, 0x39, 0x03, 0x2c, 0xd0, 0x0f, 0xdd, 0x78, 0x2a}; +static uint8_t Wy_Ed25519[ED25519_KEY_SIZE] = { + 0x14, 0x1d, 0x2c, 0xf6, 0xf3, 0x30, 0x78, 0x9b, 0x65, 0x31, 0x71, + 0x80, 0x61, 0xd0, 0x6f, 0xcf, 0x23, 0x83, 0x79, 0x63, 0xa5, 0x3b, + 0x48, 0xbe, 0x2e, 0xa2, 0x1d, 0xc7, 0xa5, 0x44, 0xc6, 0x29}; + +static const ltc_pkha_ecc_point_t basepointEd25519 = { + Wx_Ed25519, Wy_Ed25519, +}; + +const ltc_pkha_ecc_point_t *LTC_PKHA_Ed25519_BasePoint(void) +{ + return &basepointEd25519; +} + +/* input point is on Weierstrass curve, typeOut determines the coordinates + system of output point (either Weierstrass or Ed25519) */ +status_t LTC_PKHA_Ed25519_PointMul(const ltc_pkha_ecc_point_t *ltcPointIn, + const uint8_t *N, + size_t sizeN, + ltc_pkha_ecc_point_t *ltcPointOut, + fsl_ltc_ecc_coordinate_system_t typeOut) +{ + uint16_t szN = (uint16_t)sizeN; + status_t status; + /* input on W, output in W, W parameters of ECC curve are Ed25519 curve + parameters mapped to Weierstrass curve */ + status = LTC_PKHA_ECC_PointMul(LTC_BASE, ltcPointIn, N, szN, + curve25519_modbin, r2mod, a_coefEd25519, b_coefEd25519, + ED25519_KEY_SIZE, kLTC_PKHA_TimingEqualized, kLTC_PKHA_IntegerArith, + ltcPointOut, NULL); + + /* Weierstrass coordinates to Ed25519 coordinates */ + if ((status == kStatus_Success) && (typeOut == kLTC_Ed25519)) { + status = LTC_PKHA_WeierstrassToEd25519(ltcPointOut, ltcPointOut); + } + return status; +} + +status_t LTC_PKHA_Ed25519ToWeierstrass(const ltc_pkha_ecc_point_t *ltcPointIn, + ltc_pkha_ecc_point_t *ltcPointOut) +{ + status_t status; + uint8_t Mx[ED25519_KEY_SIZE] = {0}; + uint8_t My[ED25519_KEY_SIZE] = {0}; + uint8_t temp[ED25519_KEY_SIZE] = {0}; + uint8_t temp2[ED25519_KEY_SIZE] = {0}; + const uint8_t max[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const uint8_t *Ex; + const uint8_t *Ey; + uint8_t *Gx; + uint8_t *Gy; + uint16_t szMx = 0; + uint16_t szGx = 0; + uint16_t szMy = 0; + uint16_t szGy = 0; + uint16_t szTemp = 0; + uint16_t szTemp2 = 0; + uint8_t one = 1; + + Ex = ltcPointIn->X; + Ey = ltcPointIn->Y; + Gx = ltcPointOut->X; + Gy = ltcPointOut->Y; + /* # (Ex, Ey) on Ed (a_ed, d) to (x, y) on M (A,B) + Mx = (1 + Ey) * ModularArithmetic.invert(1 - Ey, prime) % prime + My = (1 + Ey) * ModularArithmetic.invert((1 - Ey)*Ex, prime) % prime */ + + /* Gx = ((Mx * ModularArithmetic.invert(B, prime)) + + (A * ModularArithmetic.invert(3*B, prime))) % prime + Gy = (My * ModularArithmetic.invert(B, prime)) % prime */ + + /* temp = 1 + Ey */ + status = LTC_PKHA_ModAdd(LTC_BASE, Ey, ED25519_KEY_SIZE, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), temp, &szTemp, + kLTC_PKHA_IntegerArith); + + /* temp2 = 1 - Ey = 1 + (p - Ey) */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModSub1(LTC_BASE, curve25519_modbin, + sizeof(curve25519_modbin), Ey, ED25519_KEY_SIZE, max, sizeof(max), + temp2, &szTemp2); + } + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, temp2, szTemp2, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), temp2, &szTemp2, + kLTC_PKHA_IntegerArith); + } + + /* Mx = ModInv(temp2,prime) */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModInv(LTC_BASE, temp2, szTemp2, curve25519_modbin, + sizeof(curve25519_modbin), Mx, &szMx, kLTC_PKHA_IntegerArith); + } + + /* Mx = Mx * temp */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, Mx, szMx, temp, szTemp, + curve25519_modbin, ED25519_KEY_SIZE, Mx, &szMx, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* My = temp2 * Ex */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, Ex, ED25519_KEY_SIZE, temp2, + szTemp2, curve25519_modbin, ED25519_KEY_SIZE, My, &szMy, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* My = ModInv(My, prime) */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModInv(LTC_BASE, My, szMy, curve25519_modbin, + sizeof(curve25519_modbin), My, &szMy, kLTC_PKHA_IntegerArith); + } + /* My = My * temp */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, My, szMy, temp, szTemp, + curve25519_modbin, ED25519_KEY_SIZE, My, &szMy, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* Gx = Mx * invB_coefEd25519 + A_mul_invThreeB_coefEd25519 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, Mx, szMx, invB_coefEd25519, + sizeof(invB_coefEd25519), curve25519_modbin, ED25519_KEY_SIZE, Gx, + &szGx, kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, Gx, szGx, + A_mul_invThreeB_coefEd25519, sizeof(A_mul_invThreeB_coefEd25519), + curve25519_modbin, sizeof(curve25519_modbin), Gx, &szGx, + kLTC_PKHA_IntegerArith); + } + + /* Gy = My * invB_coefEd25519 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, My, szMy, invB_coefEd25519, + sizeof(invB_coefEd25519), curve25519_modbin, ED25519_KEY_SIZE, Gy, + &szGy, kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + return status; +} + +/* +# (Gx, Gy) on W to (Ex, Ey) on E +My = (B*Gy) % prime +Mx = ((3*B*Gx-A)*ModularArithmetic.invert(3, prime)) % prime +Ex = Mx*ModularArithmetic.invert(My, prime) % prime +Ey = (Mx - 1)*ModularArithmetic.invert(Mx + 1, prime) % prime +*/ +status_t LTC_PKHA_WeierstrassToEd25519(const ltc_pkha_ecc_point_t *ltcPointIn, + ltc_pkha_ecc_point_t *ltcPointOut) +{ + status_t status; + uint8_t Mx[ED25519_KEY_SIZE] = {0}; + uint8_t My[ED25519_KEY_SIZE] = {0}; + uint8_t temp[ED25519_KEY_SIZE] = {0}; + const uint8_t *Gx; + const uint8_t *Gy; + uint8_t *Ex; + uint8_t *Ey; + uint16_t szMx = 0; + uint16_t szEx = 0; + uint16_t szMy = 0; + uint16_t szEy = 0; + uint16_t szTemp = 0; + uint8_t one = 1; + + Gx = ltcPointIn->X; + Gy = ltcPointIn->Y; + Ex = ltcPointOut->X; + Ey = ltcPointOut->Y; + + /* My = (B*Gy) % prime */ + status = LTC_PKHA_ModMul(LTC_BASE, B_coefEd25519, sizeof(B_coefEd25519), + Gy, ED25519_KEY_SIZE, curve25519_modbin, ED25519_KEY_SIZE, My, &szMy, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + + /* temp = 3*B*Gx mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, threeB_coefEd25519, + sizeof(threeB_coefEd25519), Gx, ED25519_KEY_SIZE, curve25519_modbin, + ED25519_KEY_SIZE, temp, &szTemp, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + /* temp = (temp - A) mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, temp, szTemp, minus_A_coefEd25519, + sizeof(minus_A_coefEd25519), curve25519_modbin, + sizeof(curve25519_modbin), temp, &szTemp, kLTC_PKHA_IntegerArith); + } + /* Mx = (temp/3) mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, temp, szTemp, invThree, + sizeof(invThree), curve25519_modbin, sizeof(curve25519_modbin), Mx, + &szMx, kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + /* temp = 1/My mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModInv(LTC_BASE, My, szMy, curve25519_modbin, + sizeof(curve25519_modbin), temp, &szTemp, kLTC_PKHA_IntegerArith); + } + /* Ex = Mx * temp mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, temp, szTemp, Mx, szMx, + curve25519_modbin, sizeof(curve25519_modbin), Ex, &szEx, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + /* temp = Mx + 1 mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, Mx, szMx, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), temp, &szTemp, + kLTC_PKHA_IntegerArith); + } + /* temp = 1/temp mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModInv(LTC_BASE, temp, szTemp, curve25519_modbin, + sizeof(curve25519_modbin), temp, &szTemp, kLTC_PKHA_IntegerArith); + } + /* Mx = (Mx - 1) mod p */ + if (status == kStatus_Success) { + if (LTC_PKHA_CompareBigNum(Mx, szMx, &one, sizeof(one)) >= 0) { + status = LTC_PKHA_ModSub1(LTC_BASE, Mx, szMx, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), Mx, &szMx); + } + else { + /* Mx is zero, so it is modulus, thus we do modulus - 1 */ + XMEMCPY(Mx, curve25519_modbin, sizeof(curve25519_modbin)); + Mx[0]--; + } + } + /* Ey = Mx * temp mod p */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, temp, szTemp, Mx, szMx, + curve25519_modbin, sizeof(curve25519_modbin), Ey, &szEy, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + return status; +} + +status_t LTC_PKHA_Ed25519_PointDecompress(const uint8_t *pubkey, + size_t pubKeySize, ltc_pkha_ecc_point_t *ltcPointOut) +{ + status_t status; + const uint8_t one = 1; + + /* pubkey contains the Y coordinate and a sign of X + */ + + /* x^2 = ((y^2 - 1) / (d*y^2 +1)) mod p */ + + /* decode Y from pubkey */ + XMEMCPY(ltcPointOut->Y, pubkey, pubKeySize); + ltcPointOut->Y[pubKeySize - 1] &= ~0x80u; + int sign = (int)(bool)(pubkey[pubKeySize - 1] & 0x80u); + + uint8_t U[ED25519_KEY_SIZE] = {0}; + uint8_t V[ED25519_KEY_SIZE] = {0}; + uint8_t *X = ltcPointOut->X; + uint8_t *Y = ltcPointOut->Y; + uint16_t szU = 0; + uint16_t szV = 0; + size_t szRes = 0; + + /* decode X from pubkey */ + + /* U = y * y mod p */ + status = LTC_PKHA_ModMul(LTC_BASE, Y, ED25519_KEY_SIZE, Y, + ED25519_KEY_SIZE, curve25519_modbin, ED25519_KEY_SIZE, U, &szU, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + XMEMCPY(V, U, szU); + szV = szU; + + /* U = U - 1 = y^2 - 1 */ + if (status == kStatus_Success) { + if (LTC_PKHA_CompareBigNum(U, szU, &one, sizeof(one)) >= 0) { + status = LTC_PKHA_ModSub1(LTC_BASE, U, szU, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), U, &szU); + } + else { + /* U is zero, so it is modulus, thus we do modulus - 1 */ + XMEMCPY(U, curve25519_modbin, sizeof(curve25519_modbin)); + U[0]--; + } + } + + /* V = d*y*y + 1 */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, V, szV, d_coefEd25519, + ED25519_KEY_SIZE, curve25519_modbin, ED25519_KEY_SIZE, V, &szV, + kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, + kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized); + } + + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, V, szV, &one, sizeof(one), + curve25519_modbin, sizeof(curve25519_modbin), V, &szV, + kLTC_PKHA_IntegerArith); + } + + /* U = U / V (mod p) */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModInv(LTC_BASE, V, szV, curve25519_modbin, + sizeof(curve25519_modbin), V, &szV, kLTC_PKHA_IntegerArith); + } + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, V, szV, U, szU, curve25519_modbin, + ED25519_KEY_SIZE, U, &szU, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + + /* get square root */ + if (status == kStatus_Success) { + status = LTC_PKHA_Prime25519SquareRootMod(U, szU, X, &szRes, sign); + } + + return status; +} + +/* LSByte first of Ed25519 parameter l = 2^252 + 27742317777372353535851937790883648493 */ +static const uint8_t l_coefEdDSA[] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + +/* +Input: + s[0]+256*s[1]+...+256^63*s[63] = s + +Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. +*/ +status_t LTC_PKHA_sc_reduce(uint8_t *a) +{ + uint16_t szA = 0; + return LTC_PKHA_ModRed(LTC_BASE, a, 64, l_coefEdDSA, sizeof(l_coefEdDSA), + a, &szA, kLTC_PKHA_IntegerArith); +} + +/* +Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + +Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l + where l = 2^252 + 27742317777372353535851937790883648493. +*/ +status_t LTC_PKHA_sc_muladd(uint8_t *s, const uint8_t *a, + const uint8_t *b, const uint8_t *c) +{ + uint16_t szS = 0; + uint16_t szB = 0; + uint8_t tempB[32] = {0}; + status_t status; + + /* Assume only b can be larger than modulus. It is called durind + * wc_ed25519_sign_msg() where hram (=a) and nonce(=c) + * have been reduced by LTC_PKHA_sc_reduce() + * Thus reducing b only. + */ + status = LTC_PKHA_ModRed(LTC_BASE, b, 32, l_coefEdDSA, sizeof(l_coefEdDSA), + tempB, &szB, kLTC_PKHA_IntegerArith); + + if (status == kStatus_Success) { + status = LTC_PKHA_ModMul(LTC_BASE, a, 32, tempB, szB, l_coefEdDSA, + sizeof(l_coefEdDSA), s, &szS, kLTC_PKHA_IntegerArith, + kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, + kLTC_PKHA_TimingEqualized); + } + + if (status == kStatus_Success) { + status = LTC_PKHA_ModAdd(LTC_BASE, s, szS, c, 32, l_coefEdDSA, 32, s, + &szS, kLTC_PKHA_IntegerArith); + } + + return status; +} + +/* +r = a * A + b * B +where A is public key point, B is basepoint +where a = a[0]+256*a[1]+...+256^31 a[31]. +and b = b[0]+256*b[1]+...+256^31 b[31]. +B is the Ed25519 base point (x,4/5) with x positive. +*/ +status_t LTC_PKHA_SignatureForVerify(uint8_t *rcheck, const unsigned char *a, + const unsigned char *b, ed25519_key *key) +{ + /* To verify a signature on a message M, first split the signature + into two 32-octet halves. Decode the first half as a point R, + and the second half as an integer s, in the range 0 <= s < q. If + the decoding fails, the signature is invalid. */ + + /* Check the group equation 8s B = 8 R + 8k A. */ + + /* + Uses a fast single-signature verification SB = R + H(R,A,M)A becomes + SB - H(R,A,M)A saving decompression of R + */ + uint8_t X0[ED25519_PUB_KEY_SIZE] = {0}; + uint8_t X1[ED25519_PUB_KEY_SIZE] = {0}; + uint8_t Y0[ED25519_PUB_KEY_SIZE] = {0}; + uint8_t Y1[ED25519_PUB_KEY_SIZE] = {0}; + const uint8_t max[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + ltc_pkha_ecc_point_t ltc0; + ltc_pkha_ecc_point_t ltc1; + ltc_pkha_ecc_point_t pubKey; + status_t status; + + /* The equality for the negative of a point P, in affine coordinates, + is -P = -(x,y) = (x, -y) */ + uint16_t szY = 32; + + ltc0.X = X0; + ltc1.X = X1; + ltc0.Y = Y0; + ltc1.Y = Y1; + pubKey.X = key->pointX; + pubKey.Y = key->pointY; + + /* ltc0 = b*B */ + status = LTC_PKHA_Ed25519_PointMul(LTC_PKHA_Ed25519_BasePoint(), b, + ED25519_KEY_SIZE, <c0, kLTC_Weierstrass /* result in W */); + + /* ltc1 = a*A */ + if (status == kStatus_Success) { + status = LTC_PKHA_Ed25519ToWeierstrass(&pubKey, <c1); + } + if (status == kStatus_Success) { + status = LTC_PKHA_Ed25519_PointMul(<c1, a, ED25519_KEY_SIZE, <c1, + kLTC_Weierstrass /* result in W */); + } + + /* R = b*B - a*A */ + if (status == kStatus_Success) { + status = LTC_PKHA_ModSub1(LTC_BASE, curve25519_modbin, + sizeof(curve25519_modbin), ltc1.Y, szY, max, sizeof(max), ltc1.Y, + &szY); + } + if (status == kStatus_Success) { + status = LTC_PKHA_ECC_PointAdd(LTC_BASE, <c0, <c1, + curve25519_modbin, r2mod, a_coefEd25519, b_coefEd25519, + ED25519_KEY_SIZE, kLTC_PKHA_IntegerArith, <c0); + } + /* map to Ed25519 */ + if (status == kStatus_Success) { + status = LTC_PKHA_WeierstrassToEd25519(<c0, <c0); + } + if (((uint32_t)ltc0.X[0]) & 0x01u) { + ltc0.Y[ED25519_KEY_SIZE - 1] |= 0x80u; + } + + XMEMCPY(rcheck, ltc0.Y, ED25519_KEY_SIZE); + return status; +} + +status_t LTC_PKHA_Ed25519_Compress(const ltc_pkha_ecc_point_t *ltcPointIn, + uint8_t *p) +{ + /* compress */ + /* get sign of X per https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02 + * To form the encoding of the point, copy the least + significant bit of the x-coordinate to the most significant bit of + the final octet + */ + XMEMCPY(p, ltcPointIn->Y, ED25519_KEY_SIZE); + if (((uint32_t)ltcPointIn->X[0]) & 0x01u) { + p[ED25519_KEY_SIZE - 1] |= 0x80u; + } + return kStatus_Success; +} + +#endif /* HAVE_ED25519 */ +#endif /* FREESCALE_LTC_ECC */ + + +#undef ERROR_OUT + +#endif /* FREESCALE_LTC_TFM || FREESCALE_LTC_ECC */ |