From 24f4224fcb3007adafb56f833ee1ae213d71cbba Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Tue, 23 Jun 2026 00:07:13 +0800 Subject: [PATCH] Add P-384 --- CMakeLists.txt | 13 +- include/gmssl/secp384r1.h | 109 ++++++ include/gmssl/version.h | 2 +- src/secp384r1.c | 741 ++++++++++++++++++++++++++++++++++++++ tests/secp384r1test.c | 293 +++++++++++++++ 5 files changed, 1156 insertions(+), 2 deletions(-) create mode 100644 include/gmssl/secp384r1.h create mode 100644 src/secp384r1.c create mode 100644 tests/secp384r1test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 00972875..79109c84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,7 @@ option(ENABLE_SM9 "Enable SM9" ON) option(ENABLE_CMS "Enable CMS" ON) option(ENABLE_SECP256R1 "Enable ECDH/ECDSA on curve secp256r1" ON) +option(ENABLE_SECP384R1 "Enable curve secp384r1" ON) option(ENABLE_LMS "Enable LMS/HSS signature" ON) option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON) @@ -516,6 +517,16 @@ if (ENABLE_SECP256R1) list(APPEND tests bn secp256r1 secp256r1_key ecdsa) endif() +if (ENABLE_SECP384R1) + message(STATUS "ENABLE_SECP384R1 is ON") + add_definitions(-DENABLE_SECP384R1) + if (NOT ENABLE_SECP256R1) + list(APPEND src src/bn.c) + endif() + list(APPEND src src/secp384r1.c) + list(APPEND tests secp384r1) +endif() + if (ENABLE_LMS) message(STATUS "ENABLE_LMS is ON") @@ -931,7 +942,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.3.0-dev.1161") +set(CPACK_PACKAGE_VERSION "3.3.0-dev.1162") set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md) set(CPACK_NSIS_MODIFY_PATH ON) include(CPack) diff --git a/include/gmssl/secp384r1.h b/include/gmssl/secp384r1.h new file mode 100644 index 00000000..d7671eae --- /dev/null +++ b/include/gmssl/secp384r1.h @@ -0,0 +1,109 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + + +#ifndef GMSSL_SECP384R1_H +#define GMSSL_SECP384R1_H + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +// p = 2^384 - 2^128 - 2^96 + 2^32 - 1 +// = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF +// a = -3 +// b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef +// x = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7 +// y = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f +// n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 +// h = 1 + + +typedef uint32_t secp384r1_t[12]; + +#define SECP384R1_K (sizeof(secp384r1_t)/sizeof(uint32_t)) + +extern const secp384r1_t SECP384R1_P; +extern const secp384r1_t SECP384R1_B; +extern const secp384r1_t SECP384R1_N; +extern const uint32_t SECP384R1_U_P[13]; +extern const uint32_t SECP384R1_U_N[13]; + +int secp384r1_is_zero(const secp384r1_t a); +int secp384r1_is_one(const secp384r1_t a); +int secp384r1_cmp(const secp384r1_t a, const secp384r1_t b); +int secp384r1_set_zero(secp384r1_t r); +int secp384r1_set_one(secp384r1_t r); +int secp384r1_copy(secp384r1_t r, const secp384r1_t a); +int secp384r1_to_48bytes(const secp384r1_t a, uint8_t out[48]); +int secp384r1_from_48bytes(secp384r1_t r, const uint8_t in[48]); +int secp384r1_print(FILE *fp, int fmt, int ind, const char *label, const secp384r1_t a); + +int secp384r1_modp_add(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modp_dbl(secp384r1_t r, const secp384r1_t a); +int secp384r1_modp_tri(secp384r1_t r, const secp384r1_t a); +int secp384r1_modp_sub(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modp_neg(secp384r1_t r, const secp384r1_t a); +int secp384r1_modp_haf(secp384r1_t r, const secp384r1_t a); +int secp384r1_modp_mul(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modp_sqr(secp384r1_t r, const secp384r1_t a); +int secp384r1_modp_exp(secp384r1_t r, const secp384r1_t a, const secp384r1_t e); +int secp384r1_modp_inv(secp384r1_t r, const secp384r1_t a); + +int secp384r1_modn(secp384r1_t r, const secp384r1_t a); +int secp384r1_modn_add(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modn_dbl(secp384r1_t r, const secp384r1_t a); +int secp384r1_modn_tri(secp384r1_t r, const secp384r1_t a); +int secp384r1_modn_sub(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modn_neg(secp384r1_t r, const secp384r1_t a); +int secp384r1_modn_mul(secp384r1_t r, const secp384r1_t a, const secp384r1_t b); +int secp384r1_modn_sqr(secp384r1_t r, const secp384r1_t a); +int secp384r1_modn_exp(secp384r1_t r, const secp384r1_t a, const secp384r1_t e); +int secp384r1_modn_inv(secp384r1_t r, const secp384r1_t a); + + +typedef struct { + secp384r1_t X; + secp384r1_t Y; + secp384r1_t Z; +} SECP384R1_POINT; + +const SECP384R1_POINT *secp384r1_generator(void); +#define SECP384R1_POINT_G (*secp384r1_generator()) + +int secp384r1_point_set_infinity(SECP384R1_POINT *R); +int secp384r1_point_is_at_infinity(const SECP384R1_POINT *P); +int secp384r1_point_is_on_curve(const SECP384R1_POINT *P); +int secp384r1_point_equ(const SECP384R1_POINT *P, const SECP384R1_POINT *Q); +int secp384r1_point_set_xy(SECP384R1_POINT *R, const secp384r1_t x, const secp384r1_t y); +int secp384r1_point_get_xy(const SECP384R1_POINT *P, secp384r1_t x, secp384r1_t y); +int secp384r1_point_copy(SECP384R1_POINT *R, const SECP384R1_POINT *P); +int secp384r1_point_dbl(SECP384R1_POINT *R, const SECP384R1_POINT *P); +int secp384r1_point_add(SECP384R1_POINT *R, const SECP384R1_POINT *P, const SECP384R1_POINT *Q); +int secp384r1_point_neg(SECP384R1_POINT *R, const SECP384R1_POINT *P); +int secp384r1_point_sub(SECP384R1_POINT *R, const SECP384R1_POINT *P, const SECP384R1_POINT *Q); +int secp384r1_point_mul(SECP384R1_POINT *R, const secp384r1_t k, const SECP384R1_POINT *P); +int secp384r1_point_mul_generator(SECP384R1_POINT *R, const secp384r1_t k); +int secp384r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP384R1_POINT *P); +int secp384r1_point_to_uncompressed_octets(const SECP384R1_POINT *P, uint8_t octets[97]); +int secp384r1_point_from_uncompressed_octets(SECP384R1_POINT *P, const uint8_t octets[97]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/version.h b/include/gmssl/version.h index 3f37d62c..830677c7 100644 --- a/include/gmssl/version.h +++ b/include/gmssl/version.h @@ -18,7 +18,7 @@ extern "C" { #define GMSSL_VERSION_NUM 30300 -#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1161" +#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1162" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/src/secp384r1.c b/src/secp384r1.c new file mode 100644 index 00000000..fd28de02 --- /dev/null +++ b/src/secp384r1.c @@ -0,0 +1,741 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +const secp384r1_t SECP384R1_P = { + 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, + 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, +}; + +const secp384r1_t SECP384R1_B = { + 0xd3ec2aef, 0x2a85c8ed, 0x8a2ed19d, 0xc656398d, + 0x5013875a, 0x0314088f, 0xfe814112, 0x181d9c6e, + 0xe3f82d19, 0x988e056b, 0xe23ee7e4, 0xb3312fa7, +}; + +const secp384r1_t SECP384R1_N = { + 0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, + 0xf4372ddf, 0xc7634d81, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, +}; + +const uint32_t SECP384R1_U_P[13] = { + 0x00000001, 0xffffffff, 0xffffffff, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, +}; + +const uint32_t SECP384R1_U_N[13] = { + 0x333ad68d, 0x1313e695, 0xb74f5885, 0xa7e5f24d, + 0x0bc8d220, 0x389cb27e, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, +}; + +int secp384r1_is_zero(const secp384r1_t a) { + return bn_is_zero(a, SECP384R1_K); +} + +int secp384r1_is_one(const secp384r1_t a) { + return bn_is_one(a, SECP384R1_K); +} + +int secp384r1_cmp(const secp384r1_t a, const secp384r1_t b) { + return bn_cmp(a, b, SECP384R1_K); +} + +int secp384r1_set_zero(secp384r1_t r) { + bn_set_word(r, 0, SECP384R1_K); + return 1; +} + +int secp384r1_set_one(secp384r1_t r) { + bn_set_word(r, 1, SECP384R1_K); + return 1; +} + +int secp384r1_copy(secp384r1_t r, const secp384r1_t a) { + bn_copy(r, a, SECP384R1_K); + return 1; +} + +int secp384r1_to_48bytes(const secp384r1_t a, uint8_t out[48]) { + bn_to_bytes(a, SECP384R1_K, out); + return 1; +} + +int secp384r1_from_48bytes(secp384r1_t r, const uint8_t in[48]) { + bn_from_bytes(r, SECP384R1_K, in); + return 1; +} + +int secp384r1_print(FILE *fp, int fmt, int ind, const char *label, const secp384r1_t a) { + uint8_t bytes[48]; + if (secp384r1_to_48bytes(a, bytes) != 1) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, label, bytes, 48); + return 1; +} + +int secp384r1_modp_add(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + bn_mod_add(r, a, b, SECP384R1_P, SECP384R1_K); + return 1; +} + +int secp384r1_modp_dbl(secp384r1_t r, const secp384r1_t a) { + bn_mod_add(r, a, a, SECP384R1_P, SECP384R1_K); + return 1; +} + +int secp384r1_modp_tri(secp384r1_t r, const secp384r1_t a) { + secp384r1_t tmp; + + bn_mod_add(tmp, a, a, SECP384R1_P, SECP384R1_K); + bn_mod_add(r, tmp, a, SECP384R1_P, SECP384R1_K); + return 1; +} + +int secp384r1_modp_sub(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + bn_mod_sub(r, a, b, SECP384R1_P, SECP384R1_K); + return 1; +} + +int secp384r1_modp_neg(secp384r1_t r, const secp384r1_t a) { + if (secp384r1_is_zero(a)) { + secp384r1_set_zero(r); + } else { + bn_mod_neg(r, a, SECP384R1_P, SECP384R1_K); + } + return 1; +} + +int secp384r1_modp_haf(secp384r1_t r, const secp384r1_t a) { + int c = 0; + if (a[0] & 1) { + c = bn_add(r, a, SECP384R1_P, SECP384R1_K); + } else { + bn_copy(r, a, SECP384R1_K); + } + + r[0] = (r[0] >> 1) | ((r[1] & 1) << 31); + r[1] = (r[1] >> 1) | ((r[2] & 1) << 31); + r[2] = (r[2] >> 1) | ((r[3] & 1) << 31); + r[3] = (r[3] >> 1) | ((r[4] & 1) << 31); + r[4] = (r[4] >> 1) | ((r[5] & 1) << 31); + r[5] = (r[5] >> 1) | ((r[6] & 1) << 31); + r[6] = (r[6] >> 1) | ((r[7] & 1) << 31); + r[7] = (r[7] >> 1) | ((r[8] & 1) << 31); + r[8] = (r[8] >> 1) | ((r[9] & 1) << 31); + r[9] = (r[9] >> 1) | ((r[10] & 1) << 31); + r[10] = (r[10] >> 1) | ((r[11] & 1) << 31); + r[11] = (r[11] >> 1) | ((c & 1) << 31); + return 1; +} + +int secp384r1_modp_mul(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + uint32_t tmp[6*12 + 4]; + bn_barrett_mod_mul(r, a, b, SECP384R1_P, SECP384R1_U_P, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modp_sqr(secp384r1_t r, const secp384r1_t a) { + uint32_t tmp[6*12 + 4]; + bn_barrett_mod_mul(r, a, a, SECP384R1_P, SECP384R1_U_P, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modp_exp(secp384r1_t r, const secp384r1_t a, const secp384r1_t e) { + uint32_t tmp[7*12 + 4]; + bn_barrett_mod_exp(r, a, e, SECP384R1_P, SECP384R1_U_P, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modp_inv(secp384r1_t r, const secp384r1_t a) { + uint32_t tmp[8*12 + 4]; + + if (secp384r1_is_zero(a)) { + error_print(); + return -1; + } + bn_barrett_mod_inv(r, a, SECP384R1_P, SECP384R1_U_P, tmp, SECP384R1_K); + return 1; +} + + +int secp384r1_modn(secp384r1_t r, const secp384r1_t a) { + if (bn_cmp(a, SECP384R1_N, SECP384R1_K) >= 0) { + bn_sub(r, a, SECP384R1_N, SECP384R1_K); + } else { + bn_copy(r, a, SECP384R1_K); + } + return 1; +} + +int secp384r1_modn_add(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + bn_mod_add(r, a, b, SECP384R1_N, SECP384R1_K); + return 1; +} + +int secp384r1_modn_dbl(secp384r1_t r, const secp384r1_t a) { + bn_mod_add(r, a, a, SECP384R1_N, SECP384R1_K); + return 1; +} + +int secp384r1_modn_tri(secp384r1_t r, const secp384r1_t a) { + secp384r1_t tmp; + bn_mod_add(tmp, a, a, SECP384R1_N, SECP384R1_K); + bn_mod_add(r, tmp, a, SECP384R1_N, SECP384R1_K); + return 1; +} + +int secp384r1_modn_sub(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + bn_mod_sub(r, a, b, SECP384R1_N, SECP384R1_K); + return 1; +} + +int secp384r1_modn_neg(secp384r1_t r, const secp384r1_t a) { + if (secp384r1_is_zero(a)) { + secp384r1_set_zero(r); + } else { + bn_mod_neg(r, a, SECP384R1_N, SECP384R1_K); + } + return 1; +} + +int secp384r1_modn_mul(secp384r1_t r, const secp384r1_t a, const secp384r1_t b) { + uint32_t tmp[6*12 + 4]; + bn_barrett_mod_mul(r, a, b, SECP384R1_N, SECP384R1_U_N, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modn_sqr(secp384r1_t r, const secp384r1_t a) { + uint32_t tmp[6*12 + 4]; + bn_barrett_mod_mul(r, a, a, SECP384R1_N, SECP384R1_U_N, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modn_exp(secp384r1_t r, const secp384r1_t a, const secp384r1_t e) { + uint32_t tmp[7*12 + 4]; + bn_barrett_mod_exp(r, a, e, SECP384R1_N, SECP384R1_U_N, tmp, SECP384R1_K); + return 1; +} + +int secp384r1_modn_inv(secp384r1_t r, const secp384r1_t a) { + uint32_t tmp[8*12 + 4]; + + if (secp384r1_is_zero(a)) { + error_print(); + return -1; + } + bn_barrett_mod_inv(r, a, SECP384R1_N, SECP384R1_U_N, tmp, SECP384R1_K); + return 1; +} + + +static const SECP384R1_POINT secp384r1_generator_point = { + { 0x72760ab7, 0x3a545e38, 0xbf55296c, 0x5502f25d, + 0x82542a38, 0x59f741e0, 0x8ba79b98, 0x6e1d3b62, + 0xf320ad74, 0x8eb1c71e, 0xbe8b0537, 0xaa87ca22, }, + { 0x90ea0e5f, 0x7a431d7c, 0x1d7e819d, 0x0a60b1ce, + 0xb5f0b8c0, 0xe9da3113, 0x289a147c, 0xf8f41dbd, + 0x9292dc29, 0x5d9e98bf, 0x96262c6f, 0x3617de4a, }, + { 1,0,0,0,0,0,0,0,0,0,0,0, }, +}; + +const SECP384R1_POINT *secp384r1_generator(void) +{ + return &secp384r1_generator_point; +} + +int secp384r1_point_set_infinity(SECP384R1_POINT *R) +{ + if (secp384r1_set_one(R->X) != 1 + || secp384r1_set_one(R->Y) != 1 + || secp384r1_set_zero(R->Z) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_is_at_infinity(const SECP384R1_POINT *P) +{ + if (secp384r1_is_zero(P->Z)) { + return 1; + } + return 0; +} + +int secp384r1_point_is_on_curve(const SECP384R1_POINT *P) +{ + secp384r1_t t0; + secp384r1_t t1; + secp384r1_t t2; + + if (secp384r1_point_is_at_infinity(P)) { + return 1; + } + + // check Y^2 + 3 * X * Z^4 == X^3 + b * Z^6 + + // t0 = Y^2 + if (secp384r1_modp_sqr(t0, P->Y) != 1) goto err; + + // t1 = Z^2 + if (secp384r1_modp_sqr(t1, P->Z) != 1) goto err; + + // t2 = Z^4 + if (secp384r1_modp_sqr(t2, t1) != 1) goto err; + + // t1 = Z^6 + if (secp384r1_modp_mul(t1, t1, t2) != 1) goto err; + + // t1 = b * Z^6 + if (secp384r1_modp_mul(t1, t1, SECP384R1_B) != 1) goto err; + + // t2 = X * Z^4 + if (secp384r1_modp_mul(t2, t2, P->X) != 1) goto err; + + // t0 = Y^2 + 3 * X * Z^4 + if (secp384r1_modp_add(t0, t0, t2) != 1 + || secp384r1_modp_add(t0, t0, t2) != 1 + || secp384r1_modp_add(t0, t0, t2) != 1) goto err; + + // t2 = X^2 + if (secp384r1_modp_sqr(t2, P->X) != 1) goto err; + + // t2 = X^3 + if (secp384r1_modp_mul(t2, t2, P->X) != 1) goto err; + + // t1 = b * Z^6 + X^3 + if (secp384r1_modp_add(t1, t1, t2) != 1) goto err; + + if (secp384r1_cmp(t0, t1) != 0) { + return 0; + } + return 1; +err: + error_print(); + return -1; +} + +int secp384r1_point_copy(SECP384R1_POINT *R, const SECP384R1_POINT *P) +{ + if (secp384r1_copy(R->X, P->X) != 1 + || secp384r1_copy(R->Y, P->Y) != 1 + || secp384r1_copy(R->Z, P->Z) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_set_xy(SECP384R1_POINT *R, const secp384r1_t x, const secp384r1_t y) +{ + if (secp384r1_cmp(x, SECP384R1_P) >= 0) { + error_print(); + return -1; + } + if (secp384r1_cmp(y, SECP384R1_P) >= 0) { + error_print(); + return -1; + } + if (secp384r1_copy(R->X, x) != 1 + || secp384r1_copy(R->Y, y) != 1 + || secp384r1_set_one(R->Z) != 1) { + error_print(); + return -1; + } + + + if (secp384r1_point_is_on_curve(R) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_get_xy(const SECP384R1_POINT *P, secp384r1_t x, secp384r1_t y) +{ + secp384r1_t Z_inv; + + if (secp384r1_point_is_at_infinity(P)) { + error_print(); + return -1; + } + if (secp384r1_modp_inv(Z_inv, P->Z) != 1 + || secp384r1_modp_mul(y, P->Y, Z_inv) != 1 + || secp384r1_modp_sqr(Z_inv, Z_inv) != 1 + || secp384r1_modp_mul(x, P->X, Z_inv) != 1 + || secp384r1_modp_mul(y, y, Z_inv) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_dbl(SECP384R1_POINT *R, const SECP384R1_POINT *P) +{ + /* + secp384r1_t T_0; + secp384r1_t T_1; + secp384r1_t T_2; + secp384r1_t T_3; + secp384r1_t T_4; + + if (secp384r1_point_is_at_infinity(P)) { + secp384r1_point_set_infinity(R); + return; + } + + secp384r1_modp_sqr(T_0, P->X); + secp384r1_modp_tri(T_0, T_0); + secp384r1_modp_sqr(T_1, T_0); + secp384r1_modp_sqr(T_2, P->Y); + secp384r1_modp_mul(T_3, P->X, T_2); + secp384r1_modp_dbl(T_3, T_3); + secp384r1_modp_dbl(T_3, T_3); + secp384r1_modp_dbl(T_4, T_3); + secp384r1_modp_sub(T_1, T_1, T_4); + secp384r1_modp_sub(T_3, T_3, T_1); + secp384r1_modp_mul(T_0, T_0, T_3); + secp384r1_modp_dbl(T_2, T_2); + secp384r1_modp_sqr(T_2, T_2); + secp384r1_modp_dbl(T_2, T_2); + secp384r1_modp_sub(T_0, T_0, T_2); + secp384r1_modp_mul(T_2, P->Y, P->Z); + secp384r1_modp_dbl(T_2, T_2); + + secp384r1_copy(R->X, T_1); + secp384r1_copy(R->Y, T_0); + secp384r1_copy(R->Z, T_2); + */ + + const uint32_t *X1 = P->X; + const uint32_t *Y1 = P->Y; + const uint32_t *Z1 = P->Z; + uint32_t *X3 = R->X; + uint32_t *Y3 = R->Y; + uint32_t *Z3 = R->Z; + secp384r1_t S; + secp384r1_t M; + secp384r1_t Zsqr; + secp384r1_t tmp0; + + if (secp384r1_point_is_at_infinity(P)) { + return secp384r1_point_set_infinity(R); + } + + // 1. S = 2Y + if (secp384r1_modp_dbl(S, Y1) != 1) goto err; + + // 2. Zsqr = Z^2 + if (secp384r1_modp_sqr(Zsqr, Z1) != 1) goto err; + + // 3. S = S^2 = 4Y^2 + if (secp384r1_modp_sqr(S, S) != 1) goto err; + + // 4. Z = Z*Y + if (secp384r1_modp_mul(Z3, Z1, Y1) != 1) goto err; + + // 5. Z = 2*Z = 2*Y*Z ===> Z3 + if (secp384r1_modp_dbl(Z3, Z3) != 1) goto err; + + // 6. M = X + Zsqr = X + Z^2 + if (secp384r1_modp_add(M, X1, Zsqr) != 1) goto err; + + // 7. Zsqr = X - Zsqr = X - Z^2 + if (secp384r1_modp_sub(Zsqr, X1, Zsqr) != 1) goto err; + + // 8. Y = S^2 = 16Y^4 + if (secp384r1_modp_sqr(Y3, S) != 1) goto err; + + // 9. Y = Y/2 = 8Y^4 + if (secp384r1_modp_haf(Y3, Y3) != 1) goto err; + + // 10. M = M * Zsqr = (X + Z^2)*(X - Z^2) = X^2 - Z^4 + if (secp384r1_modp_mul(M, M, Zsqr) != 1) goto err; + + // 11. M = 3M = 3X^2 - 3Z^4 + if (secp384r1_modp_tri(M, M) != 1) goto err; + + // 12. S = S * X = 4X*Y^2 + if (secp384r1_modp_mul(S, S, X1) != 1) goto err; + + // 13. tmp0 = 2 * S = 8X*Y^2 + if (secp384r1_modp_dbl(tmp0, S) != 1) goto err; + + // 14. X = M^2 = (3X^2 - 3Z^4)^2 + if (secp384r1_modp_sqr(X3, M) != 1) goto err; + + // 15. X = X - tmp0 = (3X^2 - 3Z^4)^2 - 8X*Y^2 ===> X3 + if (secp384r1_modp_sub(X3, X3, tmp0) != 1) goto err; + + // 16. S = S - X3 = 4X*Y^2 - X3 + if (secp384r1_modp_sub(S, S, X3) != 1) goto err; + + // 17. S = S * M = (3X^2 - 3Z^4)*(4X*Y^2 - X3) + if (secp384r1_modp_mul(S, S, M) != 1) goto err; + + // 18. Y = S - Y = (3X^2 - 3Z^4)*(4X*Y^2 - X3) - 8Y^4 ===> Y3 + if (secp384r1_modp_sub(Y3, S, Y3) != 1) goto err; + + return 1; +err: + error_print(); + return -1; +} + +int secp384r1_point_add(SECP384R1_POINT *R, const SECP384R1_POINT *P, const SECP384R1_POINT *Q) +{ + secp384r1_t T_1; + secp384r1_t T_2; + secp384r1_t T_3; + secp384r1_t T_4; + secp384r1_t T_5; + secp384r1_t T_6; + secp384r1_t T_7; + secp384r1_t T_8; + + if (secp384r1_point_is_at_infinity(P)) { + return secp384r1_point_copy(R, Q); + } + if (secp384r1_point_is_at_infinity(Q)) { + return secp384r1_point_copy(R, P); + } + + if (secp384r1_modp_sqr(T_1, P->Z) != 1 // T_1 = Z_1^2 + || secp384r1_modp_sqr(T_2, Q->Z) != 1 // T_2 = Z_2^2 + || secp384r1_modp_mul(T_3, Q->X, T_1) != 1 // T_3 = X_2 * Z_1^2 + || secp384r1_modp_mul(T_4, P->X, T_2) != 1 // T_4 = X_1 * Z_2^2 + || secp384r1_modp_add(T_5, T_3, T_4) != 1 // T_5 = X_2 * Z_1^2 + X_1 * Z_2^2 = C + || secp384r1_modp_sub(T_3, T_3, T_4) != 1 // T_3 = X_2 * Z_1^2 - X_1 * Z_2^2 = B + || secp384r1_modp_mul(T_1, T_1, P->Z) != 1 // T_1 = Z_1^3 + || secp384r1_modp_mul(T_1, T_1, Q->Y) != 1 // T_1 = Y_2 * Z_1^3 + || secp384r1_modp_mul(T_2, T_2, Q->Z) != 1 // T_2 = Z_2^3 + || secp384r1_modp_mul(T_2, T_2, P->Y) != 1 // T_2 = Y_1 * Z_2^3 + || secp384r1_modp_add(T_6, T_1, T_2) != 1 // T_6 = Y_2 * Z_1^3 + Y_1 * Z_2^3 = D + || secp384r1_modp_sub(T_1, T_1, T_2) != 1) { // T_1 = Y_2 * Z_1^3 - Y_1 * Z_2^3 = A + error_print(); + return -1; + } + + if (secp384r1_is_zero(T_1) && secp384r1_is_zero(T_3)) { + return secp384r1_point_dbl(R, P); + } + + if (secp384r1_is_zero(T_3) && secp384r1_is_zero(T_6)) { + return secp384r1_point_set_infinity(R); + } + + if (secp384r1_modp_sqr(T_6, T_1) != 1 // T_6 = A^2 + || secp384r1_modp_mul(T_7, T_3, P->Z) != 1 // T_7 = B * Z_1 + || secp384r1_modp_mul(T_7, T_7, Q->Z) != 1 // T_7 = B * Z_1 * Z_2 = Z_3 + || secp384r1_modp_sqr(T_8, T_3) != 1 // T_8 = B^2 + || secp384r1_modp_mul(T_5, T_5, T_8) != 1 // T_5 = B^2 * C + || secp384r1_modp_mul(T_3, T_3, T_8) != 1 // T_3 = B^3 + || secp384r1_modp_mul(T_4, T_4, T_8) != 1 // T_4 = B^2 * X_1 * Z_2^2 + || secp384r1_modp_sub(T_6, T_6, T_5) != 1 // T_6 = A^2 - B^2 * C = X_3 + || secp384r1_modp_sub(T_4, T_4, T_6) != 1 // T_4 = B^2 * X_1 * Z_2^2 - X_3 + || secp384r1_modp_mul(T_1, T_1, T_4) != 1 // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) + || secp384r1_modp_mul(T_2, T_2, T_3) != 1 // T_2 = B^3 * Y_1 * Z_1^3 + || secp384r1_modp_sub(T_1, T_1, T_2) != 1) { // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) - B^3 * Y_1 * Z_1^3 = Y_3 + error_print(); + return -1; + } + + if (secp384r1_copy(R->X, T_6) != 1 + || secp384r1_copy(R->Y, T_1) != 1 + || secp384r1_copy(R->Z, T_7) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_neg(SECP384R1_POINT *R, const SECP384R1_POINT *P) +{ + if (secp384r1_point_is_at_infinity(P)) { + return secp384r1_point_set_infinity(R); + } + if (secp384r1_copy(R->X, P->X) != 1 + || secp384r1_modp_neg(R->Y, P->Y) != 1 + || secp384r1_copy(R->Z, P->Z) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_sub(SECP384R1_POINT *R, const SECP384R1_POINT *P, const SECP384R1_POINT *Q) +{ + SECP384R1_POINT T; + if (secp384r1_point_neg(&T, Q) != 1 + || secp384r1_point_add(R, P, &T) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_mul(SECP384R1_POINT *R, const secp384r1_t k, const SECP384R1_POINT *P) +{ + SECP384R1_POINT T; + uint32_t bits; + int nbits; + int i; + + if (secp384r1_point_set_infinity(&T) != 1) { + error_print(); + return -1; + } + + for (i = 11; i >= 0; i--) { + bits = k[i]; + nbits = 32; + while (nbits-- > 0) { + if (secp384r1_point_dbl(&T, &T) != 1) { + error_print(); + return -1; + } + if (bits & 0x80000000) { + if (secp384r1_point_add(&T, &T, P) != 1) { + error_print(); + return -1; + } + } + bits <<= 1; + } + } + + if (secp384r1_point_copy(R, &T) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_mul_generator(SECP384R1_POINT *R, const secp384r1_t k) +{ + return secp384r1_point_mul(R, k, secp384r1_generator()); +} + +int secp384r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP384R1_POINT *P) +{ + uint8_t bytes[48]; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + if (secp384r1_to_48bytes(P->X, bytes) != 1) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "X", bytes, 48); + if (secp384r1_to_48bytes(P->Y, bytes) != 1) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "Y", bytes, 48); + if (secp384r1_to_48bytes(P->Z, bytes) != 1) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "Z", bytes, 48); + return 1; +} + +int secp384r1_point_to_uncompressed_octets(const SECP384R1_POINT *P, uint8_t octets[97]) +{ + secp384r1_t x; + secp384r1_t y; + + if (secp384r1_point_get_xy(P, x, y) != 1) { + error_print(); + return -1; + } + octets[0] = 0x04; + if (secp384r1_to_48bytes(x, octets + 1) != 1 + || secp384r1_to_48bytes(y, octets + 49) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_from_uncompressed_octets(SECP384R1_POINT *P, const uint8_t octets[97]) +{ + secp384r1_t x; + secp384r1_t y; + + if (octets[0] != 0x04) { + error_print(); + return -1; + } + if (secp384r1_from_48bytes(x, octets + 1) != 1 + || secp384r1_from_48bytes(y, octets + 49) != 1) { + error_print(); + return -1; + } + + if (secp384r1_point_set_xy(P, x, y) != 1) { + error_print(); + return -1; + } + return 1; +} + +int secp384r1_point_equ(const SECP384R1_POINT *P, const SECP384R1_POINT *Q) +{ + secp384r1_t t0; + secp384r1_t t1; + secp384r1_t t2; + secp384r1_t t3; + + if (secp384r1_point_is_at_infinity(P)) { + return secp384r1_point_is_at_infinity(Q); + } + if (secp384r1_point_is_at_infinity(Q)) { + return 0; + } + + if (secp384r1_modp_sqr(t0, P->Z) != 1 // t0 = Z1^2 + || secp384r1_modp_sqr(t1, Q->Z) != 1 // t1 = Z2^2 + || secp384r1_modp_mul(t2, Q->X, t0) != 1 // t2 = X2 * Z1^2 + || secp384r1_modp_mul(t3, P->X, t1) != 1) { // t3 = X1 * Z2^2 + error_print(); + return -1; + } + if (secp384r1_cmp(t2, t3) != 0) { + return 0; + } + + if (secp384r1_modp_mul(t0, t0, P->Z) != 1 // t0 = Z1^3 + || secp384r1_modp_mul(t0, t0, Q->Y) != 1 // t0 = Y2 * Z1^3 + || secp384r1_modp_mul(t1, t1, Q->Z) != 1 // t1 = Z2^3 + || secp384r1_modp_mul(t1, t1, P->Y) != 1) { // t1 = Y1 * Z2^3 + error_print(); + return -1; + } + + return secp384r1_cmp(t0, t1) == 0; +} diff --git a/tests/secp384r1test.c b/tests/secp384r1test.c new file mode 100644 index 00000000..2ef1e156 --- /dev/null +++ b/tests/secp384r1test.c @@ -0,0 +1,293 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static const char *secp384r1_p = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"; +static const char *secp384r1_b = "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"; +static const char *secp384r1_x = "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"; +static const char *secp384r1_y = "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"; +static const char *secp384r1_n = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"; +static const char *secp384r1_2x = "08d999057ba3d2d969260045c55b97f089025959a6f434d651d207d19fb96e9e4fe0e86ebe0e64f85b96a9c75295df61"; +static const char *secp384r1_2y = "8e80f1fa5b1b3cedb7bfe8dffd6dba74b275d875bc6cc43e904e505f256ab4255ffd43e94d39e22d61501e700a940e80"; +static const char *secp384r1_3x = "077a41d4606ffa1464793c7e5fdc7d98cb9d3910202dcd06bea4f240d3566da6b408bbae5026580d02d7e5c70500c831"; +static const char *secp384r1_3y = "c995f7ca0b0c42837d0bbe9602a9fc998520b41c85115aa5f7684c0edc111eacc24abd6be4b5d298b65f28600a2f1df1"; + +static int secp384r1_from_hex(secp384r1_t r, const char *hex) +{ + uint8_t buf[48]; + size_t len; + + if (hex_to_bytes(hex, strlen(hex), buf, &len) != 1 || len != sizeof(buf)) { + error_print(); + return -1; + } + return secp384r1_from_48bytes(r, buf); +} + +static int secp384r1_check_hex(const secp384r1_t a, const char *hex) +{ + secp384r1_t v; + + if (secp384r1_from_hex(v, hex) != 1) { + error_print(); + return -1; + } + if (secp384r1_cmp(a, v) != 0) { + error_print(); + return -1; + } + return 1; +} + +static int secp384r1_check_point_xy(const SECP384R1_POINT *P, const char *xhex, const char *yhex) +{ + secp384r1_t x; + secp384r1_t y; + + if (secp384r1_point_get_xy(P, x, y) != 1) { + error_print(); + return -1; + } + if (secp384r1_check_hex(x, xhex) != 1 + || secp384r1_check_hex(y, yhex) != 1) { + error_print(); + return -1; + } + return 1; +} + +static int test_secp384r1(void) +{ + secp384r1_t a; + secp384r1_t b; + uint8_t buf[48]; + + if (secp384r1_set_zero(a) != 1 || !secp384r1_is_zero(a)) { + error_print(); + return -1; + } + if (secp384r1_to_48bytes(a, buf) != 1) { + error_print(); + return -1; + } + format_bytes(stderr, 0, 4, "0", buf, sizeof(buf)); + + if (secp384r1_set_one(b) != 1 || !secp384r1_is_one(b)) { + error_print(); + return -1; + } + if (secp384r1_to_48bytes(b, buf) != 1) { + error_print(); + return -1; + } + format_bytes(stderr, 0, 4, "1", buf, sizeof(buf)); + + if (secp384r1_cmp(a, b) >= 0) { + error_print(); + return -1; + } + if (secp384r1_check_hex(SECP384R1_P, secp384r1_p) != 1 + || secp384r1_check_hex(SECP384R1_B, secp384r1_b) != 1 + || secp384r1_check_hex(SECP384R1_N, secp384r1_n) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp384r1_modp(void) +{ + secp384r1_t x; + secp384r1_t y; + secp384r1_t r; + + if (secp384r1_from_hex(x, secp384r1_x) != 1 + || secp384r1_from_hex(y, secp384r1_y) != 1) { + error_print(); + return -1; + } + + if (secp384r1_modp_add(r, x, y) != 1 + || secp384r1_check_hex(r, "e09fa86d54b131a6ec505fde85b3899e6711591fb441b01543d172f43844e2f85f63a42bdcd3ab09b4977bb503601916") != 1) goto err; + if (secp384r1_modp_dbl(r, x) != 1 + || secp384r1_check_hex(r, "550f94457d160a6f1d638e3de6415ae8dc3a76c5174f3730b3ee83c104a85471aa05e4bc7eaa52d874a8bc6fe4ec156f") != 1) goto err; + if (secp384r1_modp_tri(r, x) != 1 + || secp384r1_check_hex(r, "ff975e683ba10fa6ac15555cd962085d4a57b227a2f6d2c90de5c5a186fc7ea9ff08d71a3dff7c44aefd1aa857622026") != 1) goto err; + if (secp384r1_modp_sub(r, x, y) != 1 + || secp384r1_check_hex(r, "746febd82864d8c831132e5f608dd14a75291da5630d871b701d10cccc6371784aa2408fa1d6a7cec01140bbe18bfc58") != 1) goto err; + if (secp384r1_modp_sub(r, y, x) != 1 + || secp384r1_check_hex(r, "8b901427d79b2737ceecd1a09f722eb58ad6e25a9cf278e48fe2ef33339c8e86b55dbf6f5e2958313feebf451e7403a7") != 1) goto err; + if (secp384r1_modp_neg(r, x) != 1 + || secp384r1_check_hex(r, "557835dd4174fac8714e38e10cdf528b91e2c49d74586467a608be1f7dabd5c6aafd0da140aad693c5aba1c88d89f548") != 1) goto err; + if (secp384r1_modp_mul(r, x, y) != 1 + || secp384r1_check_hex(r, "332e559389c970313cb29c4b55af5783821971a99c250daf84dc5d3cc441cb0a482e90de9d3ccd96b3c8c48b2ad3f025") != 1) goto err; + if (secp384r1_modp_sqr(r, x) != 1 + || secp384r1_check_hex(r, "046af925fa51ac496728217df5bc7c1fc3353aca34a380e1ffd8419fe7b13f6a92e8614fee38a288e2222412aca8b019") != 1) goto err; + if (secp384r1_modp_exp(r, x, y) != 1 + || secp384r1_check_hex(r, "e2f876012d77fd16b510933ebb40d33758751272874af587def1858002f128d8fa151410f114c9d8c8ff23f35add99fd") != 1) goto err; + if (secp384r1_modp_inv(r, x) != 1 + || secp384r1_check_hex(r, "1ce18121749aa29a393faddf4e55522af8c67dabdfa413aac45da5c5f0781147133e1c96ca2a8234440fbf89e7e96410") != 1) goto err; + if (secp384r1_modp_inv(r, y) != 1 + || secp384r1_check_hex(r, "9eee8231a5913c8aac5a8f03b92fee93f6d05a5777cb0bf87063909e7e5682f7a26736b36031e4006ecf009e5f9c8231") != 1) goto err; + + printf("%s() ok\n", __FUNCTION__); + return 1; +err: + error_print(); + return -1; +} + +static int test_secp384r1_modn(void) +{ + secp384r1_t x; + secp384r1_t y; + secp384r1_t r; + + if (secp384r1_from_hex(x, secp384r1_x) != 1 + || secp384r1_from_hex(y, secp384r1_y) != 1) { + error_print(); + return -1; + } + + if (secp384r1_modn_add(r, x, y) != 1 + || secp384r1_check_hex(r, "e09fa86d54b131a6ec505fde85b3899e6711591fb441b01543d172f43844e2f85f63a42bdcd3ab09b4977bb503601916") != 1) goto err; + if (secp384r1_modn_dbl(r, x) != 1 + || secp384r1_check_hex(r, "550f94457d160a6f1d638e3de6415ae8dc3a76c5174f3730ec8b363f1071269151ebd70935f9ab5d87bca3061826ebfb") != 1) goto err; + if (secp384r1_modn_tri(r, x) != 1 + || secp384r1_check_hex(r, "ff975e683ba10fa6ac15555cd962085d4a57b227a2f6d2c94682781f92c550c9a6eec966f54ed4c9c211013e8a9cf6b2") != 1) goto err; + if (secp384r1_modn_sub(r, x, y) != 1 + || secp384r1_check_hex(r, "746febd82864d8c831132e5f608dd14a75291da5630d871b701d10cccc6371784aa2408fa1d6a7cec01140bbe18bfc58") != 1) goto err; + if (secp384r1_modn_sub(r, y, x) != 1 + || secp384r1_check_hex(r, "8b901427d79b2737ceecd1a09f722eb58ad6e25a9cf278e457463cb527d3bc670d77cd22a6d9ffac2cdad8aeeb392d1b") != 1) goto err; + if (secp384r1_modn_neg(r, x) != 1 + || secp384r1_check_hex(r, "557835dd4174fac8714e38e10cdf528b91e2c49d745864676d6c0ba171e303a703171b54895b7e0eb297bb325a4f1ebc") != 1) goto err; + if (secp384r1_modn_mul(r, x, y) != 1 + || secp384r1_check_hex(r, "2a8e172f52ea8a3f1864714efafb6588d0ed2fc509e9b4502bdd369bdbeeb9019f58804fbe958008223ba8752ead1f2c") != 1) goto err; + if (secp384r1_modn_sqr(r, x) != 1 + || secp384r1_check_hex(r, "a067a4d6fd10d2108a2d4649446529d5501f3734e9d5075a68178b74a7fb933b79d068c4f3d6e8585115c859fd9c0bc3") != 1) goto err; + if (secp384r1_modn_exp(r, x, y) != 1 + || secp384r1_check_hex(r, "0076a61817d4c4953212e870f68b9333672b79065de7009630493b17ee66d771779850e91be0594e4f0275f876ed8b58") != 1) goto err; + if (secp384r1_modn_inv(r, x) != 1 + || secp384r1_check_hex(r, "c0345088d98aa2f119e693230bbfb7a15f02792e7267cb55b3b0da1cb38a1c5d5f05c8d102d5128f524604074c4c8846") != 1) goto err; + if (secp384r1_modn_inv(r, y) != 1 + || secp384r1_check_hex(r, "195089baf8f5f0aff5c30a6cbde5b89a548ed7f739d253a675186a655eb60fe5e7973625ab399512e7a68c6b1bc8c167") != 1) goto err; + + printf("%s() ok\n", __FUNCTION__); + return 1; +err: + error_print(); + return -1; +} + +static int test_secp384r1_mod_zero(void) +{ + secp384r1_t zero; + secp384r1_t r; + + if (secp384r1_set_zero(zero) != 1) { + error_print(); + return -1; + } + if (secp384r1_modp_neg(r, zero) != 1 || !secp384r1_is_zero(r)) { + error_print(); + return -1; + } + if (secp384r1_modn_neg(r, zero) != 1 || !secp384r1_is_zero(r)) { + error_print(); + return -1; + } + if (secp384r1_modp_inv(r, zero) != -1) { + error_print(); + return -1; + } + if (secp384r1_modn_inv(r, zero) != -1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_secp384r1_point(void) +{ + SECP384R1_POINT P; + SECP384R1_POINT Q; + SECP384R1_POINT R; + secp384r1_t k; + uint8_t octets[97]; + + if (secp384r1_point_set_xy(&P, SECP384R1_POINT_G.X, SECP384R1_POINT_G.Y) != 1 + || secp384r1_point_is_on_curve(&P) != 1) { + error_print(); + return -1; + } + + if (secp384r1_point_dbl(&Q, &P) != 1 + || secp384r1_check_point_xy(&Q, secp384r1_2x, secp384r1_2y) != 1) { + error_print(); + return -1; + } + if (secp384r1_point_add(&R, &P, &Q) != 1 + || secp384r1_check_point_xy(&R, secp384r1_3x, secp384r1_3y) != 1) { + error_print(); + return -1; + } + + if (secp384r1_set_zero(k) != 1) { + error_print(); + return -1; + } + k[0] = 3; + if (secp384r1_point_mul_generator(&R, k) != 1 + || secp384r1_check_point_xy(&R, secp384r1_3x, secp384r1_3y) != 1) { + error_print(); + return -1; + } + if (secp384r1_point_mul_generator(&R, SECP384R1_N) != 1 + || !secp384r1_point_is_at_infinity(&R)) { + error_print(); + return -1; + } + + if (secp384r1_point_to_uncompressed_octets(&P, octets) != 1 + || secp384r1_point_from_uncompressed_octets(&R, octets) != 1 + || secp384r1_point_equ(&P, &R) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +int main(void) +{ + if (test_secp384r1() != 1) goto err; + if (test_secp384r1_modp() != 1) goto err; + if (test_secp384r1_modn() != 1) goto err; + if (test_secp384r1_mod_zero() != 1) goto err; + if (test_secp384r1_point() != 1) goto err; + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return -1; +}