1e0c4386eSCy Schubert /* 2*44096ebdSEnji Cooper * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved. 3e0c4386eSCy Schubert * 4e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"); 5e0c4386eSCy Schubert * you may not use this file except in compliance with the License. 6e0c4386eSCy Schubert * You may obtain a copy of the License at 7e0c4386eSCy Schubert * https://www.openssl.org/source/license.html 8e0c4386eSCy Schubert * or in the file LICENSE in the source distribution. 9e0c4386eSCy Schubert */ 10e0c4386eSCy Schubert 11e0c4386eSCy Schubert #include "internal/nelem.h" 12e0c4386eSCy Schubert #include "testutil.h" 13e0c4386eSCy Schubert 14e0c4386eSCy Schubert #include <stdio.h> 15e0c4386eSCy Schubert #include <stdlib.h> 16e0c4386eSCy Schubert #include <string.h> 17e0c4386eSCy Schubert #include <ctype.h> 18e0c4386eSCy Schubert 19e0c4386eSCy Schubert #define NUM_REPEATS "1000000" 20e0c4386eSCy Schubert 21e0c4386eSCy Schubert static ossl_intmax_t num_repeats; 22e0c4386eSCy Schubert static int print_mode = 0; 23e0c4386eSCy Schubert 24e0c4386eSCy Schubert #ifndef OPENSSL_NO_EC 25e0c4386eSCy Schubert # include <openssl/ec.h> 26e0c4386eSCy Schubert # include <openssl/err.h> 27e0c4386eSCy Schubert # include <openssl/obj_mac.h> 28e0c4386eSCy Schubert # include <openssl/objects.h> 29e0c4386eSCy Schubert # include <openssl/rand.h> 30e0c4386eSCy Schubert # include <openssl/bn.h> 31e0c4386eSCy Schubert # include <openssl/opensslconf.h> 32e0c4386eSCy Schubert 33e0c4386eSCy Schubert static const char *kP256DefaultResult = 34e0c4386eSCy Schubert "A1E24B223B8E81BC1FFF99BAFB909EDB895FACDE7D6DA5EF5E7B3255FB378E0F"; 35e0c4386eSCy Schubert 36e0c4386eSCy Schubert /* 37e0c4386eSCy Schubert * Perform a deterministic walk on the curve, by starting from |point| and 38e0c4386eSCy Schubert * using the X-coordinate of the previous point as the next scalar for 39e0c4386eSCy Schubert * point multiplication. 40e0c4386eSCy Schubert * Returns the X-coordinate of the end result or NULL on error. 41e0c4386eSCy Schubert */ 42e0c4386eSCy Schubert static BIGNUM *walk_curve(const EC_GROUP *group, EC_POINT *point, 43e0c4386eSCy Schubert ossl_intmax_t num) 44e0c4386eSCy Schubert { 45e0c4386eSCy Schubert BIGNUM *scalar = NULL; 46e0c4386eSCy Schubert ossl_intmax_t i; 47e0c4386eSCy Schubert 48e0c4386eSCy Schubert if (!TEST_ptr(scalar = BN_new()) 49e0c4386eSCy Schubert || !TEST_true(EC_POINT_get_affine_coordinates(group, point, scalar, 50e0c4386eSCy Schubert NULL, NULL))) 51e0c4386eSCy Schubert goto err; 52e0c4386eSCy Schubert 53e0c4386eSCy Schubert for (i = 0; i < num; i++) { 54e0c4386eSCy Schubert if (!TEST_true(EC_POINT_mul(group, point, NULL, point, scalar, NULL)) 55e0c4386eSCy Schubert || !TEST_true(EC_POINT_get_affine_coordinates(group, point, 56e0c4386eSCy Schubert scalar, 57e0c4386eSCy Schubert NULL, NULL))) 58e0c4386eSCy Schubert goto err; 59e0c4386eSCy Schubert } 60e0c4386eSCy Schubert return scalar; 61e0c4386eSCy Schubert 62e0c4386eSCy Schubert err: 63e0c4386eSCy Schubert BN_free(scalar); 64e0c4386eSCy Schubert return NULL; 65e0c4386eSCy Schubert } 66e0c4386eSCy Schubert 67e0c4386eSCy Schubert static int test_curve(void) 68e0c4386eSCy Schubert { 69e0c4386eSCy Schubert EC_GROUP *group = NULL; 70e0c4386eSCy Schubert EC_POINT *point = NULL; 71e0c4386eSCy Schubert BIGNUM *result = NULL, *expected_result = NULL; 72e0c4386eSCy Schubert int ret = 0; 73e0c4386eSCy Schubert 74e0c4386eSCy Schubert /* 75e0c4386eSCy Schubert * We currently hard-code P-256, though adaptation to other curves. 76e0c4386eSCy Schubert * would be straightforward. 77e0c4386eSCy Schubert */ 78e0c4386eSCy Schubert if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) 79e0c4386eSCy Schubert || !TEST_ptr(point = EC_POINT_dup(EC_GROUP_get0_generator(group), 80e0c4386eSCy Schubert group)) 81e0c4386eSCy Schubert || !TEST_ptr(result = walk_curve(group, point, num_repeats))) 82*44096ebdSEnji Cooper goto err; 83e0c4386eSCy Schubert 84e0c4386eSCy Schubert if (print_mode) { 85e0c4386eSCy Schubert BN_print(bio_out, result); 86e0c4386eSCy Schubert BIO_printf(bio_out, "\n"); 87e0c4386eSCy Schubert ret = 1; 88e0c4386eSCy Schubert } else { 89e0c4386eSCy Schubert if (!TEST_true(BN_hex2bn(&expected_result, kP256DefaultResult)) 90e0c4386eSCy Schubert || !TEST_ptr(expected_result) 91e0c4386eSCy Schubert || !TEST_BN_eq(result, expected_result)) 92e0c4386eSCy Schubert goto err; 93e0c4386eSCy Schubert ret = 1; 94e0c4386eSCy Schubert } 95e0c4386eSCy Schubert 96e0c4386eSCy Schubert err: 97e0c4386eSCy Schubert EC_GROUP_free(group); 98e0c4386eSCy Schubert EC_POINT_free(point); 99e0c4386eSCy Schubert BN_free(result); 100e0c4386eSCy Schubert BN_free(expected_result); 101e0c4386eSCy Schubert return ret; 102e0c4386eSCy Schubert } 103e0c4386eSCy Schubert #endif 104e0c4386eSCy Schubert 105e0c4386eSCy Schubert typedef enum OPTION_choice { 106e0c4386eSCy Schubert OPT_ERR = -1, 107e0c4386eSCy Schubert OPT_EOF = 0, 108e0c4386eSCy Schubert OPT_NUM_REPEATS, 109e0c4386eSCy Schubert OPT_TEST_ENUM 110e0c4386eSCy Schubert } OPTION_CHOICE; 111e0c4386eSCy Schubert 112e0c4386eSCy Schubert const OPTIONS *test_get_options(void) 113e0c4386eSCy Schubert { 114e0c4386eSCy Schubert static const OPTIONS test_options[] = { 115e0c4386eSCy Schubert OPT_TEST_OPTIONS_DEFAULT_USAGE, 116e0c4386eSCy Schubert { "num", OPT_NUM_REPEATS, 'M', "Number of repeats" }, 117e0c4386eSCy Schubert { NULL } 118e0c4386eSCy Schubert }; 119e0c4386eSCy Schubert return test_options; 120e0c4386eSCy Schubert } 121e0c4386eSCy Schubert 122e0c4386eSCy Schubert /* 123e0c4386eSCy Schubert * Stress test the curve. If the '-num' argument is given, runs the loop 124e0c4386eSCy Schubert * |num| times and prints the resulting X-coordinate. Otherwise runs the test 125e0c4386eSCy Schubert * the default number of times and compares against the expected result. 126e0c4386eSCy Schubert */ 127e0c4386eSCy Schubert int setup_tests(void) 128e0c4386eSCy Schubert { 129e0c4386eSCy Schubert OPTION_CHOICE o; 130e0c4386eSCy Schubert 131e0c4386eSCy Schubert if (!opt_intmax(NUM_REPEATS, &num_repeats)) { 132e0c4386eSCy Schubert TEST_error("Cannot parse " NUM_REPEATS); 133e0c4386eSCy Schubert return 0; 134e0c4386eSCy Schubert } 135e0c4386eSCy Schubert 136e0c4386eSCy Schubert while ((o = opt_next()) != OPT_EOF) { 137e0c4386eSCy Schubert switch (o) { 138e0c4386eSCy Schubert case OPT_NUM_REPEATS: 139e0c4386eSCy Schubert if (!opt_intmax(opt_arg(), &num_repeats) 140e0c4386eSCy Schubert || num_repeats < 0) 141e0c4386eSCy Schubert return 0; 142e0c4386eSCy Schubert print_mode = 1; 143e0c4386eSCy Schubert break; 144e0c4386eSCy Schubert case OPT_TEST_CASES: 145e0c4386eSCy Schubert break; 146e0c4386eSCy Schubert default: 147e0c4386eSCy Schubert case OPT_ERR: 148e0c4386eSCy Schubert return 0; 149e0c4386eSCy Schubert } 150e0c4386eSCy Schubert } 151e0c4386eSCy Schubert 152e0c4386eSCy Schubert #ifndef OPENSSL_NO_EC 153e0c4386eSCy Schubert ADD_TEST(test_curve); 154e0c4386eSCy Schubert #endif 155e0c4386eSCy Schubert return 1; 156e0c4386eSCy Schubert } 157