blob: 1b7ff58634f79eada5f2347b2df5710add0d8814 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Multi-precision integer library
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker5121ce52009-01-03 21:22:43 +00006 */
Simon Butcher15b15d12015-11-26 19:35:03 +00007
Paul Bakker5121ce52009-01-03 21:22:43 +00008/*
Simon Butcher15b15d12015-11-26 19:35:03 +00009 * The following sources were referenced in the design of this Multi-precision
10 * Integer library:
Paul Bakker5121ce52009-01-03 21:22:43 +000011 *
Simon Butcher15b15d12015-11-26 19:35:03 +000012 * [1] Handbook of Applied Cryptography - 1997
13 * Menezes, van Oorschot and Vanstone
14 *
15 * [2] Multi-Precision Math
16 * Tom St Denis
17 * https://github.com/libtom/libtommath/blob/develop/tommath.pdf
18 *
19 * [3] GNU Multi-Precision Arithmetic Library
20 * https://gmplib.org/manual/index.html
21 *
Simon Butcherf5ba0452015-12-27 23:01:55 +000022 */
Paul Bakker5121ce52009-01-03 21:22:43 +000023
Gilles Peskinedb09ef62020-06-03 01:43:33 +020024#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020026#if defined(MBEDTLS_BIGNUM_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000028#include "mbedtls/bignum.h"
Janos Follath4614b9a2022-07-21 15:34:47 +010029#include "bignum_core.h"
Chris Jones4c5819c2021-03-03 17:45:34 +000030#include "bn_mul.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050031#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000032#include "mbedtls/error.h"
Gabor Mezei22c9a6f2021-10-20 12:09:35 +020033#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000034
Dave Rodgman351c71b2021-12-06 17:50:53 +000035#include <limits.h>
Rich Evans00ab4702015-02-06 13:43:58 +000036#include <string.h>
37
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000038#include "mbedtls/platform.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020039
Gilles Peskine449bd832023-01-11 14:50:10 +010040#define MPI_VALIDATE_RET(cond) \
41 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA)
42#define MPI_VALIDATE(cond) \
43 MBEDTLS_INTERNAL_VALIDATE(cond)
Gabor Mezei66669142022-08-03 12:52:26 +020044
Dave Rodgman7d4f0192023-05-09 14:01:05 +010045/*
46 * Compare signed values in constant time
47 */
48int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
49 const mbedtls_mpi *Y,
50 unsigned *ret)
51{
Dave Rodgman1f39f032023-08-01 09:19:16 +010052 mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
Dave Rodgman7d4f0192023-05-09 14:01:05 +010053
54 MPI_VALIDATE_RET(X != NULL);
55 MPI_VALIDATE_RET(Y != NULL);
56 MPI_VALIDATE_RET(ret != NULL);
57
58 if (X->n != Y->n) {
59 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
60 }
61
62 /*
Dave Rodgmanb69239c2023-08-09 14:53:18 +010063 * Set N_is_negative to MBEDTLS_CT_FALSE if N >= 0, MBEDTLS_CT_TRUE if N < 0.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010064 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
65 */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010066 X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
67 Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010068
69 /*
70 * If the signs are different, then the positive operand is the bigger.
71 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
72 * is false if X is positive (X_is_negative == 0).
73 */
Dave Rodgman1cfc43c2023-09-19 16:18:59 +010074 different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
Dave Rodgman1f39f032023-08-01 09:19:16 +010075 result = mbedtls_ct_bool_and(different_sign, X_is_negative);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010076
Dave Rodgman32d72602023-07-31 12:28:05 +010077 /*
78 * Assuming signs are the same, compare X and Y. We switch the comparison
Dave Rodgman1a7a5622023-05-17 13:47:56 +010079 * order if they are negative so that we get the right result, regardles of
80 * sign.
Dave Rodgman7d4f0192023-05-09 14:01:05 +010081 */
Dave Rodgman7d4f0192023-05-09 14:01:05 +010082
Dave Rodgman32d72602023-07-31 12:28:05 +010083 /* This array is used to conditionally swap the pointers in const time */
Dave Rodgman1a7a5622023-05-17 13:47:56 +010084 void * const p[2] = { X->p, Y->p };
Dave Rodgman98ddc012023-08-10 12:11:31 +010085 size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
Dave Rodgman2c764842023-05-18 13:28:21 +010086 mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010087
Dave Rodgman32d72602023-07-31 12:28:05 +010088 /*
Dave Rodgman1f39f032023-08-01 09:19:16 +010089 * Store in result iff the signs are the same (i.e., iff different_sign == false). If
Dave Rodgman32d72602023-07-31 12:28:05 +010090 * the signs differ, result has already been set, so we don't change it.
91 */
Dave Rodgman1f39f032023-08-01 09:19:16 +010092 result = mbedtls_ct_bool_or(result,
93 mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
Dave Rodgman1a7a5622023-05-17 13:47:56 +010094
Dave Rodgman98ddc012023-08-10 12:11:31 +010095 *ret = mbedtls_ct_uint_if_else_0(result, 1);
Dave Rodgman7d4f0192023-05-09 14:01:05 +010096
97 return 0;
98}
99
100/*
101 * Conditionally assign X = Y, without leaking information
102 * about whether the assignment was made or not.
103 * (Leaking information about the respective sizes of X and Y is ok however.)
104 */
105#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
106/*
107 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
108 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
109 */
110__declspec(noinline)
111#endif
112int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
113 const mbedtls_mpi *Y,
114 unsigned char assign)
115{
116 int ret = 0;
117 MPI_VALIDATE_RET(X != NULL);
118 MPI_VALIDATE_RET(Y != NULL);
119
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100120 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
121
Dave Rodgman7e9af052023-09-28 17:08:16 +0100122 {
123 mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
Dave Rodgman589ccb82023-05-17 13:55:01 +0100124
Dave Rodgman7e9af052023-09-28 17:08:16 +0100125 X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100126
Dave Rodgman7e9af052023-09-28 17:08:16 +0100127 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100128
Dave Rodgman7e9af052023-09-28 17:08:16 +0100129 mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
130 for (size_t i = Y->n; i < X->n; i++) {
131 X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
132 }
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100133 }
134
135cleanup:
136 return ret;
137}
138
139/*
140 * Conditionally swap X and Y, without leaking information
141 * about whether the swap was made or not.
142 * Here it is not ok to simply swap the pointers, which would lead to
143 * different memory access patterns when X and Y are used afterwards.
144 */
145int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
146 mbedtls_mpi *Y,
147 unsigned char swap)
148{
149 int ret = 0;
150 int s;
151 MPI_VALIDATE_RET(X != NULL);
152 MPI_VALIDATE_RET(Y != NULL);
153
154 if (X == Y) {
155 return 0;
156 }
157
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100158 mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
159
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100160 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
161 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
162
163 s = X->s;
Dave Rodgman2b4486a2023-05-17 15:51:59 +0100164 X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
165 Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100166
Dave Rodgmancd2e38b2023-05-17 13:31:55 +0100167 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
Dave Rodgman7d4f0192023-05-09 14:01:05 +0100168
169cleanup:
170 return ret;
171}
172
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500173/* Implementation that should never be optimized out by the compiler */
Tom Cosgrovebc345e82023-07-25 15:17:39 +0100174#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -0500175
Paul Bakker5121ce52009-01-03 21:22:43 +0000176/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000177 * Initialize one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000178 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100179void mbedtls_mpi_init(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000180{
Gilles Peskine449bd832023-01-11 14:50:10 +0100181 MPI_VALIDATE(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000182
Paul Bakker6c591fa2011-05-05 11:49:20 +0000183 X->s = 1;
184 X->n = 0;
185 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186}
187
188/*
Paul Bakker6c591fa2011-05-05 11:49:20 +0000189 * Unallocate one MPI
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100191void mbedtls_mpi_free(mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000192{
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 if (X == NULL) {
Paul Bakker6c591fa2011-05-05 11:49:20 +0000194 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100195 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000196
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 if (X->p != NULL) {
Tom Cosgrove46259f62023-07-18 16:44:14 +0100198 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000199 }
200
Paul Bakker6c591fa2011-05-05 11:49:20 +0000201 X->s = 1;
202 X->n = 0;
203 X->p = NULL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000204}
205
206/*
207 * Enlarge to the specified number of limbs
208 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100209int mbedtls_mpi_grow(mbedtls_mpi *X, size_t nblimbs)
Paul Bakker5121ce52009-01-03 21:22:43 +0000210{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200211 mbedtls_mpi_uint *p;
Gilles Peskine449bd832023-01-11 14:50:10 +0100212 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000213
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
215 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
216 }
Paul Bakkerf9688572011-05-05 10:00:45 +0000217
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 if (X->n < nblimbs) {
219 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(nblimbs, ciL)) == NULL) {
220 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
221 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
Gilles Peskine449bd832023-01-11 14:50:10 +0100223 if (X->p != NULL) {
224 memcpy(p, X->p, X->n * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100225 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000226 }
227
Gilles Peskine053022f2023-06-29 19:26:48 +0200228 /* nblimbs fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
229 * fits, and we've checked that nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
230 X->n = (unsigned short) nblimbs;
Paul Bakker5121ce52009-01-03 21:22:43 +0000231 X->p = p;
232 }
233
Gilles Peskine449bd832023-01-11 14:50:10 +0100234 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000235}
236
237/*
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100238 * Resize down as much as possible,
239 * while keeping at least the specified number of limbs
240 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100241int mbedtls_mpi_shrink(mbedtls_mpi *X, size_t nblimbs)
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100242{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200243 mbedtls_mpi_uint *p;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100244 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100245 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000246
Gilles Peskine449bd832023-01-11 14:50:10 +0100247 if (nblimbs > MBEDTLS_MPI_MAX_LIMBS) {
248 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
249 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100250
Gilles Peskinee2f563e2020-01-20 21:17:43 +0100251 /* Actually resize up if there are currently fewer than nblimbs limbs. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100252 if (X->n <= nblimbs) {
253 return mbedtls_mpi_grow(X, nblimbs);
254 }
Gilles Peskine322752b2020-01-21 13:59:51 +0100255 /* After this point, then X->n > nblimbs and in particular X->n > 0. */
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100256
Gilles Peskine449bd832023-01-11 14:50:10 +0100257 for (i = X->n - 1; i > 0; i--) {
258 if (X->p[i] != 0) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100259 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100260 }
261 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100262 i++;
263
Gilles Peskine449bd832023-01-11 14:50:10 +0100264 if (i < nblimbs) {
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100265 i = nblimbs;
Gilles Peskine449bd832023-01-11 14:50:10 +0100266 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100267
Gilles Peskine449bd832023-01-11 14:50:10 +0100268 if ((p = (mbedtls_mpi_uint *) mbedtls_calloc(i, ciL)) == NULL) {
269 return MBEDTLS_ERR_MPI_ALLOC_FAILED;
270 }
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100271
Gilles Peskine449bd832023-01-11 14:50:10 +0100272 if (X->p != NULL) {
273 memcpy(p, X->p, i * ciL);
Tom Cosgrove46259f62023-07-18 16:44:14 +0100274 mbedtls_mpi_zeroize_and_free(X->p, X->n);
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100275 }
276
Gilles Peskine053022f2023-06-29 19:26:48 +0200277 /* i fits in n because we ensure that MBEDTLS_MPI_MAX_LIMBS
278 * fits, and we've checked that i <= nblimbs <= MBEDTLS_MPI_MAX_LIMBS. */
279 X->n = (unsigned short) i;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100280 X->p = p;
281
Gilles Peskine449bd832023-01-11 14:50:10 +0100282 return 0;
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100283}
284
Gilles Peskineed32b572021-06-02 22:17:52 +0200285/* Resize X to have exactly n limbs and set it to 0. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100286static int mbedtls_mpi_resize_clear(mbedtls_mpi *X, size_t limbs)
Gilles Peskineed32b572021-06-02 22:17:52 +0200287{
Gilles Peskine449bd832023-01-11 14:50:10 +0100288 if (limbs == 0) {
289 mbedtls_mpi_free(X);
290 return 0;
291 } else if (X->n == limbs) {
292 memset(X->p, 0, limbs * ciL);
Gilles Peskineed32b572021-06-02 22:17:52 +0200293 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100294 return 0;
295 } else {
296 mbedtls_mpi_free(X);
297 return mbedtls_mpi_grow(X, limbs);
Gilles Peskineed32b572021-06-02 22:17:52 +0200298 }
299}
300
Manuel Pégourié-Gonnard58681632013-11-21 10:39:37 +0100301/*
Gilles Peskine3da1a8f2021-06-08 23:17:42 +0200302 * Copy the contents of Y into X.
303 *
304 * This function is not constant-time. Leading zeros in Y may be removed.
305 *
306 * Ensure that X does not shrink. This is not guaranteed by the public API,
307 * but some code in the bignum module relies on this property, for example
308 * in mbedtls_mpi_exp_mod().
Paul Bakker5121ce52009-01-03 21:22:43 +0000309 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100310int mbedtls_mpi_copy(mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000311{
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100312 int ret = 0;
Paul Bakker23986e52011-04-24 08:57:21 +0000313 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100314 MPI_VALIDATE_RET(X != NULL);
315 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000316
Gilles Peskine449bd832023-01-11 14:50:10 +0100317 if (X == Y) {
318 return 0;
Manuel Pégourié-Gonnardf4999932013-08-12 17:02:59 +0200319 }
320
Gilles Peskine449bd832023-01-11 14:50:10 +0100321 if (Y->n == 0) {
322 if (X->n != 0) {
323 X->s = 1;
324 memset(X->p, 0, X->n * ciL);
325 }
326 return 0;
327 }
328
329 for (i = Y->n - 1; i > 0; i--) {
330 if (Y->p[i] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000331 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100332 }
333 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000334 i++;
335
336 X->s = Y->s;
337
Gilles Peskine449bd832023-01-11 14:50:10 +0100338 if (X->n < i) {
339 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i));
340 } else {
341 memset(X->p + i, 0, (X->n - i) * ciL);
Gilles Peskine4e4be7c2018-03-21 16:29:03 +0100342 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000343
Gilles Peskine449bd832023-01-11 14:50:10 +0100344 memcpy(X->p, Y->p, i * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000345
346cleanup:
347
Gilles Peskine449bd832023-01-11 14:50:10 +0100348 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000349}
350
351/*
352 * Swap the contents of X and Y
353 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100354void mbedtls_mpi_swap(mbedtls_mpi *X, mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000355{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200356 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100357 MPI_VALIDATE(X != NULL);
358 MPI_VALIDATE(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000359
Gilles Peskine449bd832023-01-11 14:50:10 +0100360 memcpy(&T, X, sizeof(mbedtls_mpi));
361 memcpy(X, Y, sizeof(mbedtls_mpi));
362 memcpy(Y, &T, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +0000363}
364
Gilles Peskine449bd832023-01-11 14:50:10 +0100365static inline mbedtls_mpi_uint mpi_sint_abs(mbedtls_mpi_sint z)
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100366{
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 if (z >= 0) {
368 return z;
369 }
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100370 /* Take care to handle the most negative value (-2^(biL-1)) correctly.
371 * A naive -z would have undefined behavior.
372 * Write this in a way that makes popular compilers happy (GCC, Clang,
373 * MSVC). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100374 return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
Gilles Peskineef7f4e42022-11-15 23:25:27 +0100375}
376
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100377/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
378 * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
Dave Rodgman73d85912023-09-28 17:00:50 +0100379#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100380
Paul Bakker5121ce52009-01-03 21:22:43 +0000381/*
382 * Set value from integer
383 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100384int mbedtls_mpi_lset(mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +0000385{
Janos Follath24eed8d2019-11-22 13:21:35 +0000386 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100387 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000388
Gilles Peskine449bd832023-01-11 14:50:10 +0100389 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, 1));
390 memset(X->p, 0, X->n * ciL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000391
Gilles Peskine449bd832023-01-11 14:50:10 +0100392 X->p[0] = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +0100393 X->s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +0000394
395cleanup:
396
Gilles Peskine449bd832023-01-11 14:50:10 +0100397 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000398}
399
400/*
Paul Bakker2f5947e2011-05-18 15:47:11 +0000401 * Get a specific bit
402 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100403int mbedtls_mpi_get_bit(const mbedtls_mpi *X, size_t pos)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000404{
Gilles Peskine449bd832023-01-11 14:50:10 +0100405 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000406
Gilles Peskine449bd832023-01-11 14:50:10 +0100407 if (X->n * biL <= pos) {
408 return 0;
409 }
Paul Bakker2f5947e2011-05-18 15:47:11 +0000410
Gilles Peskine449bd832023-01-11 14:50:10 +0100411 return (X->p[pos / biL] >> (pos % biL)) & 0x01;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000412}
413
414/*
415 * Set a bit to a specific value of 0 or 1
416 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100417int mbedtls_mpi_set_bit(mbedtls_mpi *X, size_t pos, unsigned char val)
Paul Bakker2f5947e2011-05-18 15:47:11 +0000418{
419 int ret = 0;
420 size_t off = pos / biL;
421 size_t idx = pos % biL;
Gilles Peskine449bd832023-01-11 14:50:10 +0100422 MPI_VALIDATE_RET(X != NULL);
Paul Bakker2f5947e2011-05-18 15:47:11 +0000423
Gilles Peskine449bd832023-01-11 14:50:10 +0100424 if (val != 0 && val != 1) {
425 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000426 }
427
Gilles Peskine449bd832023-01-11 14:50:10 +0100428 if (X->n * biL <= pos) {
429 if (val == 0) {
430 return 0;
431 }
432
433 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, off + 1));
434 }
435
436 X->p[off] &= ~((mbedtls_mpi_uint) 0x01 << idx);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200437 X->p[off] |= (mbedtls_mpi_uint) val << idx;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000438
439cleanup:
Paul Bakker9af723c2014-05-01 13:03:14 +0200440
Gilles Peskine449bd832023-01-11 14:50:10 +0100441 return ret;
Paul Bakker2f5947e2011-05-18 15:47:11 +0000442}
443
444/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200445 * Return the number of less significant zero-bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000446 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100447size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000448{
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100449 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100450 MBEDTLS_INTERNAL_VALIDATE_RET(X != NULL, 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000451
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100452#if defined(__has_builtin)
453#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
454 #define mbedtls_mpi_uint_ctz __builtin_ctz
455#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
456 #define mbedtls_mpi_uint_ctz __builtin_ctzl
457#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
458 #define mbedtls_mpi_uint_ctz __builtin_ctzll
459#endif
460#endif
461
462#if defined(mbedtls_mpi_uint_ctz)
Gilles Peskine449bd832023-01-11 14:50:10 +0100463 for (i = 0; i < X->n; i++) {
Dave Rodgman960eca92023-08-09 20:43:18 +0100464 if (X->p[i] != 0) {
465 return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
466 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100467 }
468#else
469 size_t count = 0;
470 for (i = 0; i < X->n; i++) {
471 for (size_t j = 0; j < biL; j++, count++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100472 if (((X->p[i] >> j) & 1) != 0) {
473 return count;
474 }
475 }
476 }
Dave Rodgmanfa703e32023-08-09 18:56:07 +0100477#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000478
Gilles Peskine449bd832023-01-11 14:50:10 +0100479 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000480}
481
482/*
Manuel Pégourié-Gonnardc0696c22015-06-18 16:47:17 +0200483 * Return the number of bits
Paul Bakker5121ce52009-01-03 21:22:43 +0000484 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100485size_t mbedtls_mpi_bitlen(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000486{
Gilles Peskine449bd832023-01-11 14:50:10 +0100487 return mbedtls_mpi_core_bitlen(X->p, X->n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000488}
489
490/*
491 * Return the total size in bytes
492 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100493size_t mbedtls_mpi_size(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +0000494{
Gilles Peskine449bd832023-01-11 14:50:10 +0100495 return (mbedtls_mpi_bitlen(X) + 7) >> 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000496}
497
498/*
499 * Convert an ASCII character to digit value
500 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100501static int mpi_get_digit(mbedtls_mpi_uint *d, int radix, char c)
Paul Bakker5121ce52009-01-03 21:22:43 +0000502{
503 *d = 255;
504
Gilles Peskine449bd832023-01-11 14:50:10 +0100505 if (c >= 0x30 && c <= 0x39) {
506 *d = c - 0x30;
507 }
508 if (c >= 0x41 && c <= 0x46) {
509 *d = c - 0x37;
510 }
511 if (c >= 0x61 && c <= 0x66) {
512 *d = c - 0x57;
513 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000514
Gilles Peskine449bd832023-01-11 14:50:10 +0100515 if (*d >= (mbedtls_mpi_uint) radix) {
516 return MBEDTLS_ERR_MPI_INVALID_CHARACTER;
517 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000518
Gilles Peskine449bd832023-01-11 14:50:10 +0100519 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000520}
521
522/*
523 * Import from an ASCII string
524 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100525int mbedtls_mpi_read_string(mbedtls_mpi *X, int radix, const char *s)
Paul Bakker5121ce52009-01-03 21:22:43 +0000526{
Janos Follath24eed8d2019-11-22 13:21:35 +0000527 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000528 size_t i, j, slen, n;
Gilles Peskine80f56732021-04-03 18:26:13 +0200529 int sign = 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200530 mbedtls_mpi_uint d;
531 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100532 MPI_VALIDATE_RET(X != NULL);
533 MPI_VALIDATE_RET(s != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000534
Gilles Peskine449bd832023-01-11 14:50:10 +0100535 if (radix < 2 || radix > 16) {
536 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine7cba8592021-06-08 18:32:34 +0200537 }
538
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 mbedtls_mpi_init(&T);
540
541 if (s[0] == 0) {
542 mbedtls_mpi_free(X);
543 return 0;
544 }
545
546 if (s[0] == '-') {
Gilles Peskine80f56732021-04-03 18:26:13 +0200547 ++s;
548 sign = -1;
549 }
550
Gilles Peskine449bd832023-01-11 14:50:10 +0100551 slen = strlen(s);
Paul Bakkerff60ee62010-03-16 21:09:09 +0000552
Gilles Peskine449bd832023-01-11 14:50:10 +0100553 if (radix == 16) {
Dave Rodgman68ef1d62023-05-18 20:49:03 +0100554 if (slen > SIZE_MAX >> 2) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100555 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Paul Bakker5121ce52009-01-03 21:22:43 +0000556 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000557
Gilles Peskine449bd832023-01-11 14:50:10 +0100558 n = BITS_TO_LIMBS(slen << 2);
559
560 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n));
561 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
562
563 for (i = slen, j = 0; i > 0; i--, j++) {
564 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]));
565 X->p[j / (2 * ciL)] |= d << ((j % (2 * ciL)) << 2);
566 }
567 } else {
568 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
569
570 for (i = 0; i < slen; i++) {
571 MBEDTLS_MPI_CHK(mpi_get_digit(&d, radix, s[i]));
572 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T, X, radix));
573 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, &T, d));
Paul Bakker5121ce52009-01-03 21:22:43 +0000574 }
575 }
576
Gilles Peskine449bd832023-01-11 14:50:10 +0100577 if (sign < 0 && mbedtls_mpi_bitlen(X) != 0) {
Gilles Peskine80f56732021-04-03 18:26:13 +0200578 X->s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100579 }
Gilles Peskine80f56732021-04-03 18:26:13 +0200580
Paul Bakker5121ce52009-01-03 21:22:43 +0000581cleanup:
582
Gilles Peskine449bd832023-01-11 14:50:10 +0100583 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000584
Gilles Peskine449bd832023-01-11 14:50:10 +0100585 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000586}
587
588/*
Ron Eldora16fa292018-11-20 14:07:01 +0200589 * Helper to write the digits high-order first.
Paul Bakker5121ce52009-01-03 21:22:43 +0000590 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100591static int mpi_write_hlp(mbedtls_mpi *X, int radix,
592 char **p, const size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000593{
Janos Follath24eed8d2019-11-22 13:21:35 +0000594 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200595 mbedtls_mpi_uint r;
Ron Eldora16fa292018-11-20 14:07:01 +0200596 size_t length = 0;
597 char *p_end = *p + buflen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000598
Gilles Peskine449bd832023-01-11 14:50:10 +0100599 do {
600 if (length >= buflen) {
601 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Ron Eldora16fa292018-11-20 14:07:01 +0200602 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000603
Gilles Peskine449bd832023-01-11 14:50:10 +0100604 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, radix));
605 MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(X, NULL, X, radix));
Ron Eldora16fa292018-11-20 14:07:01 +0200606 /*
607 * Write the residue in the current position, as an ASCII character.
608 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 if (r < 0xA) {
610 *(--p_end) = (char) ('0' + r);
611 } else {
612 *(--p_end) = (char) ('A' + (r - 0xA));
613 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000614
Ron Eldora16fa292018-11-20 14:07:01 +0200615 length++;
Gilles Peskine449bd832023-01-11 14:50:10 +0100616 } while (mbedtls_mpi_cmp_int(X, 0) != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +0000617
Gilles Peskine449bd832023-01-11 14:50:10 +0100618 memmove(*p, p_end, length);
Ron Eldora16fa292018-11-20 14:07:01 +0200619 *p += length;
Paul Bakker5121ce52009-01-03 21:22:43 +0000620
621cleanup:
622
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000624}
625
626/*
627 * Export into an ASCII string
628 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100629int mbedtls_mpi_write_string(const mbedtls_mpi *X, int radix,
630 char *buf, size_t buflen, size_t *olen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000631{
Paul Bakker23986e52011-04-24 08:57:21 +0000632 int ret = 0;
633 size_t n;
Paul Bakker5121ce52009-01-03 21:22:43 +0000634 char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200635 mbedtls_mpi T;
Gilles Peskine449bd832023-01-11 14:50:10 +0100636 MPI_VALIDATE_RET(X != NULL);
637 MPI_VALIDATE_RET(olen != NULL);
638 MPI_VALIDATE_RET(buflen == 0 || buf != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000639
Gilles Peskine449bd832023-01-11 14:50:10 +0100640 if (radix < 2 || radix > 16) {
641 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
642 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000643
Gilles Peskine449bd832023-01-11 14:50:10 +0100644 n = mbedtls_mpi_bitlen(X); /* Number of bits necessary to present `n`. */
645 if (radix >= 4) {
646 n >>= 1; /* Number of 4-adic digits necessary to present
Hanno Becker23cfea02019-02-04 09:45:07 +0000647 * `n`. If radix > 4, this might be a strict
648 * overapproximation of the number of
649 * radix-adic digits needed to present `n`. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100650 }
651 if (radix >= 16) {
652 n >>= 1; /* Number of hexadecimal digits necessary to
Hanno Becker23cfea02019-02-04 09:45:07 +0000653 * present `n`. */
654
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 }
Janos Follath80470622019-03-06 13:43:02 +0000656 n += 1; /* Terminating null byte */
Hanno Becker23cfea02019-02-04 09:45:07 +0000657 n += 1; /* Compensate for the divisions above, which round down `n`
658 * in case it's not even. */
659 n += 1; /* Potential '-'-sign. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100660 n += (n & 1); /* Make n even to have enough space for hexadecimal writing,
Hanno Becker23cfea02019-02-04 09:45:07 +0000661 * which always uses an even number of hex-digits. */
Paul Bakker5121ce52009-01-03 21:22:43 +0000662
Gilles Peskine449bd832023-01-11 14:50:10 +0100663 if (buflen < n) {
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100664 *olen = n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100665 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000666 }
667
Manuel Pégourié-Gonnardf79b4252015-06-02 15:41:48 +0100668 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100669 mbedtls_mpi_init(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000670
Gilles Peskine449bd832023-01-11 14:50:10 +0100671 if (X->s == -1) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000672 *p++ = '-';
Hanno Beckerc983c812019-02-01 16:41:30 +0000673 buflen--;
674 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000675
Gilles Peskine449bd832023-01-11 14:50:10 +0100676 if (radix == 16) {
Paul Bakker23986e52011-04-24 08:57:21 +0000677 int c;
678 size_t i, j, k;
Paul Bakker5121ce52009-01-03 21:22:43 +0000679
Gilles Peskine449bd832023-01-11 14:50:10 +0100680 for (i = X->n, k = 0; i > 0; i--) {
681 for (j = ciL; j > 0; j--) {
682 c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000683
Gilles Peskine449bd832023-01-11 14:50:10 +0100684 if (c == 0 && k == 0 && (i + j) != 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000685 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +0100686 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000687
Paul Bakker98fe5ea2012-10-24 11:17:48 +0000688 *(p++) = "0123456789ABCDEF" [c / 16];
Paul Bakkerd2c167e2012-10-30 07:49:19 +0000689 *(p++) = "0123456789ABCDEF" [c % 16];
Paul Bakker5121ce52009-01-03 21:22:43 +0000690 k = 1;
691 }
692 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100693 } else {
694 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T, X));
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000695
Gilles Peskine449bd832023-01-11 14:50:10 +0100696 if (T.s == -1) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000697 T.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100698 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +0000699
Gilles Peskine449bd832023-01-11 14:50:10 +0100700 MBEDTLS_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000701 }
702
703 *p++ = '\0';
Dave Rodgmane4a6f5a2023-11-04 12:20:09 +0000704 *olen = (size_t) (p - buf);
Paul Bakker5121ce52009-01-03 21:22:43 +0000705
706cleanup:
707
Gilles Peskine449bd832023-01-11 14:50:10 +0100708 mbedtls_mpi_free(&T);
Paul Bakker5121ce52009-01-03 21:22:43 +0000709
Gilles Peskine449bd832023-01-11 14:50:10 +0100710 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000711}
712
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200713#if defined(MBEDTLS_FS_IO)
Paul Bakker5121ce52009-01-03 21:22:43 +0000714/*
715 * Read X from an opened file
716 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100717int mbedtls_mpi_read_file(mbedtls_mpi *X, int radix, FILE *fin)
Paul Bakker5121ce52009-01-03 21:22:43 +0000718{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200719 mbedtls_mpi_uint d;
Paul Bakker23986e52011-04-24 08:57:21 +0000720 size_t slen;
Paul Bakker5121ce52009-01-03 21:22:43 +0000721 char *p;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000722 /*
Paul Bakkercb37aa52011-11-30 16:00:20 +0000723 * Buffer should have space for (short) label and decimal formatted MPI,
724 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000725 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100726 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
Paul Bakker5121ce52009-01-03 21:22:43 +0000727
Gilles Peskine449bd832023-01-11 14:50:10 +0100728 MPI_VALIDATE_RET(X != NULL);
729 MPI_VALIDATE_RET(fin != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000730
Gilles Peskine449bd832023-01-11 14:50:10 +0100731 if (radix < 2 || radix > 16) {
732 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
733 }
Hanno Becker73d7d792018-12-11 10:35:51 +0000734
Gilles Peskine449bd832023-01-11 14:50:10 +0100735 memset(s, 0, sizeof(s));
736 if (fgets(s, sizeof(s) - 1, fin) == NULL) {
737 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
738 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000739
Gilles Peskine449bd832023-01-11 14:50:10 +0100740 slen = strlen(s);
741 if (slen == sizeof(s) - 2) {
742 return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL;
743 }
Paul Bakkercb37aa52011-11-30 16:00:20 +0000744
Gilles Peskine449bd832023-01-11 14:50:10 +0100745 if (slen > 0 && s[slen - 1] == '\n') {
746 slen--; s[slen] = '\0';
747 }
748 if (slen > 0 && s[slen - 1] == '\r') {
749 slen--; s[slen] = '\0';
750 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000751
752 p = s + slen;
Gilles Peskine449bd832023-01-11 14:50:10 +0100753 while (p-- > s) {
754 if (mpi_get_digit(&d, radix, *p) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000755 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100756 }
757 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000758
Gilles Peskine449bd832023-01-11 14:50:10 +0100759 return mbedtls_mpi_read_string(X, radix, p + 1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000760}
761
762/*
763 * Write X into an opened file (or stdout if fout == NULL)
764 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100765int mbedtls_mpi_write_file(const char *p, const mbedtls_mpi *X, int radix, FILE *fout)
Paul Bakker5121ce52009-01-03 21:22:43 +0000766{
Janos Follath24eed8d2019-11-22 13:21:35 +0000767 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +0000768 size_t n, slen, plen;
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000769 /*
Paul Bakker5531c6d2012-09-26 19:20:46 +0000770 * Buffer should have space for (short) label and decimal formatted MPI,
771 * newline characters and '\0'
Paul Bakkerfe3256e2011-11-25 12:11:43 +0000772 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100773 char s[MBEDTLS_MPI_RW_BUFFER_SIZE];
774 MPI_VALIDATE_RET(X != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000775
Gilles Peskine449bd832023-01-11 14:50:10 +0100776 if (radix < 2 || radix > 16) {
777 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
778 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000779
Gilles Peskine449bd832023-01-11 14:50:10 +0100780 memset(s, 0, sizeof(s));
Paul Bakker5121ce52009-01-03 21:22:43 +0000781
Gilles Peskine449bd832023-01-11 14:50:10 +0100782 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(X, radix, s, sizeof(s) - 2, &n));
Paul Bakker5121ce52009-01-03 21:22:43 +0000783
Gilles Peskine449bd832023-01-11 14:50:10 +0100784 if (p == NULL) {
785 p = "";
786 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000787
Gilles Peskine449bd832023-01-11 14:50:10 +0100788 plen = strlen(p);
789 slen = strlen(s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000790 s[slen++] = '\r';
791 s[slen++] = '\n';
792
Gilles Peskine449bd832023-01-11 14:50:10 +0100793 if (fout != NULL) {
794 if (fwrite(p, 1, plen, fout) != plen ||
795 fwrite(s, 1, slen, fout) != slen) {
796 return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
797 }
798 } else {
799 mbedtls_printf("%s%s", p, s);
Paul Bakker5121ce52009-01-03 21:22:43 +0000800 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000801
802cleanup:
803
Gilles Peskine449bd832023-01-11 14:50:10 +0100804 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000805}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200806#endif /* MBEDTLS_FS_IO */
Paul Bakker5121ce52009-01-03 21:22:43 +0000807
808/*
Janos Follatha778a942019-02-13 10:28:28 +0000809 * Import X from unsigned binary data, little endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100810 *
811 * This function is guaranteed to return an MPI with exactly the necessary
812 * number of limbs (in particular, it does not skip 0s in the input).
Janos Follatha778a942019-02-13 10:28:28 +0000813 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100814int mbedtls_mpi_read_binary_le(mbedtls_mpi *X,
815 const unsigned char *buf, size_t buflen)
Janos Follatha778a942019-02-13 10:28:28 +0000816{
Janos Follath24eed8d2019-11-22 13:21:35 +0000817 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100818 const size_t limbs = CHARS_TO_LIMBS(buflen);
Janos Follatha778a942019-02-13 10:28:28 +0000819
820 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100821 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Janos Follatha778a942019-02-13 10:28:28 +0000822
Gilles Peskine449bd832023-01-11 14:50:10 +0100823 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_le(X->p, X->n, buf, buflen));
Janos Follatha778a942019-02-13 10:28:28 +0000824
825cleanup:
826
Janos Follath171a7ef2019-02-15 16:17:45 +0000827 /*
828 * This function is also used to import keys. However, wiping the buffers
829 * upon failure is not necessary because failure only can happen before any
830 * input is copied.
831 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100832 return ret;
Janos Follatha778a942019-02-13 10:28:28 +0000833}
834
835/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000836 * Import X from unsigned binary data, big endian
Przemyslaw Stekiel76960a72022-02-21 13:42:09 +0100837 *
838 * This function is guaranteed to return an MPI with exactly the necessary
839 * number of limbs (in particular, it does not skip 0s in the input).
Paul Bakker5121ce52009-01-03 21:22:43 +0000840 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100841int mbedtls_mpi_read_binary(mbedtls_mpi *X, const unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000842{
Janos Follath24eed8d2019-11-22 13:21:35 +0000843 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +0100844 const size_t limbs = CHARS_TO_LIMBS(buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000845
Gilles Peskine449bd832023-01-11 14:50:10 +0100846 MPI_VALIDATE_RET(X != NULL);
847 MPI_VALIDATE_RET(buflen == 0 || buf != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +0000848
Hanno Becker073c1992017-10-17 15:17:27 +0100849 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +0100850 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
Paul Bakker5121ce52009-01-03 21:22:43 +0000851
Gilles Peskine449bd832023-01-11 14:50:10 +0100852 MBEDTLS_MPI_CHK(mbedtls_mpi_core_read_be(X->p, X->n, buf, buflen));
Paul Bakker5121ce52009-01-03 21:22:43 +0000853
854cleanup:
855
Janos Follath171a7ef2019-02-15 16:17:45 +0000856 /*
857 * This function is also used to import keys. However, wiping the buffers
858 * upon failure is not necessary because failure only can happen before any
859 * input is copied.
860 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100861 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000862}
863
864/*
Janos Follathe344d0f2019-02-19 16:17:40 +0000865 * Export X into unsigned binary data, little endian
866 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100867int mbedtls_mpi_write_binary_le(const mbedtls_mpi *X,
868 unsigned char *buf, size_t buflen)
Janos Follathe344d0f2019-02-19 16:17:40 +0000869{
Gilles Peskine449bd832023-01-11 14:50:10 +0100870 return mbedtls_mpi_core_write_le(X->p, X->n, buf, buflen);
Janos Follathe344d0f2019-02-19 16:17:40 +0000871}
872
873/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000874 * Export X into unsigned binary data, big endian
875 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100876int mbedtls_mpi_write_binary(const mbedtls_mpi *X,
877 unsigned char *buf, size_t buflen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000878{
Gilles Peskine449bd832023-01-11 14:50:10 +0100879 return mbedtls_mpi_core_write_be(X->p, X->n, buf, buflen);
Paul Bakker5121ce52009-01-03 21:22:43 +0000880}
881
882/*
883 * Left-shift: X <<= count
884 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100885int mbedtls_mpi_shift_l(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000886{
Janos Follath24eed8d2019-11-22 13:21:35 +0000887 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Minos Galanakis0144b352023-05-02 14:02:32 +0100888 size_t i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100889 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000890
Gilles Peskine449bd832023-01-11 14:50:10 +0100891 i = mbedtls_mpi_bitlen(X) + count;
Paul Bakker5121ce52009-01-03 21:22:43 +0000892
Gilles Peskine449bd832023-01-11 14:50:10 +0100893 if (X->n * biL < i) {
894 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, BITS_TO_LIMBS(i)));
895 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000896
897 ret = 0;
898
Minos Galanakis0144b352023-05-02 14:02:32 +0100899 mbedtls_mpi_core_shift_l(X->p, X->n, count);
Paul Bakker5121ce52009-01-03 21:22:43 +0000900cleanup:
901
Gilles Peskine449bd832023-01-11 14:50:10 +0100902 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000903}
904
905/*
906 * Right-shift: X >>= count
907 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100908int mbedtls_mpi_shift_r(mbedtls_mpi *X, size_t count)
Paul Bakker5121ce52009-01-03 21:22:43 +0000909{
Gilles Peskine449bd832023-01-11 14:50:10 +0100910 MPI_VALIDATE_RET(X != NULL);
911 if (X->n != 0) {
912 mbedtls_mpi_core_shift_r(X->p, X->n, count);
913 }
914 return 0;
Gilles Peskine66414202022-09-21 15:36:16 +0200915}
916
Paul Bakker5121ce52009-01-03 21:22:43 +0000917/*
918 * Compare unsigned values
919 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100920int mbedtls_mpi_cmp_abs(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000921{
Paul Bakker23986e52011-04-24 08:57:21 +0000922 size_t i, j;
Gilles Peskine449bd832023-01-11 14:50:10 +0100923 MPI_VALIDATE_RET(X != NULL);
924 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000925
Gilles Peskine449bd832023-01-11 14:50:10 +0100926 for (i = X->n; i > 0; i--) {
927 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000928 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100929 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000930 }
931
Gilles Peskine449bd832023-01-11 14:50:10 +0100932 for (j = Y->n; j > 0; j--) {
933 if (Y->p[j - 1] != 0) {
934 break;
935 }
936 }
937
Dave Rodgmanebcd7852023-08-09 18:56:42 +0100938 /* If i == j == 0, i.e. abs(X) == abs(Y),
939 * we end up returning 0 at the end of the function. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100940
941 if (i > j) {
942 return 1;
943 }
944 if (j > i) {
945 return -1;
946 }
947
948 for (; i > 0; i--) {
949 if (X->p[i - 1] > Y->p[i - 1]) {
950 return 1;
951 }
952 if (X->p[i - 1] < Y->p[i - 1]) {
953 return -1;
954 }
955 }
956
957 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000958}
959
960/*
961 * Compare signed values
962 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100963int mbedtls_mpi_cmp_mpi(const mbedtls_mpi *X, const mbedtls_mpi *Y)
Paul Bakker5121ce52009-01-03 21:22:43 +0000964{
Paul Bakker23986e52011-04-24 08:57:21 +0000965 size_t i, j;
Gilles Peskine449bd832023-01-11 14:50:10 +0100966 MPI_VALIDATE_RET(X != NULL);
967 MPI_VALIDATE_RET(Y != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000968
Gilles Peskine449bd832023-01-11 14:50:10 +0100969 for (i = X->n; i > 0; i--) {
970 if (X->p[i - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000971 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100972 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000973 }
974
Gilles Peskine449bd832023-01-11 14:50:10 +0100975 for (j = Y->n; j > 0; j--) {
976 if (Y->p[j - 1] != 0) {
977 break;
978 }
979 }
980
981 if (i == 0 && j == 0) {
982 return 0;
983 }
984
985 if (i > j) {
986 return X->s;
987 }
988 if (j > i) {
989 return -Y->s;
990 }
991
992 if (X->s > 0 && Y->s < 0) {
993 return 1;
994 }
995 if (Y->s > 0 && X->s < 0) {
996 return -1;
997 }
998
999 for (; i > 0; i--) {
1000 if (X->p[i - 1] > Y->p[i - 1]) {
1001 return X->s;
1002 }
1003 if (X->p[i - 1] < Y->p[i - 1]) {
1004 return -X->s;
1005 }
1006 }
1007
1008 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001009}
1010
Janos Follathee6abce2019-09-05 14:47:19 +01001011/*
Paul Bakker5121ce52009-01-03 21:22:43 +00001012 * Compare signed values
1013 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001014int mbedtls_mpi_cmp_int(const mbedtls_mpi *X, mbedtls_mpi_sint z)
Paul Bakker5121ce52009-01-03 21:22:43 +00001015{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001016 mbedtls_mpi Y;
1017 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001018 MPI_VALIDATE_RET(X != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001019
Gilles Peskine449bd832023-01-11 14:50:10 +01001020 *p = mpi_sint_abs(z);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001021 Y.s = TO_SIGN(z);
Paul Bakker5121ce52009-01-03 21:22:43 +00001022 Y.n = 1;
1023 Y.p = p;
1024
Gilles Peskine449bd832023-01-11 14:50:10 +01001025 return mbedtls_mpi_cmp_mpi(X, &Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00001026}
1027
1028/*
1029 * Unsigned addition: X = |A| + |B| (HAC 14.7)
1030 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001031int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001032{
Janos Follath24eed8d2019-11-22 13:21:35 +00001033 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001034 size_t j;
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001035 mbedtls_mpi_uint *p;
1036 mbedtls_mpi_uint c;
Gilles Peskine449bd832023-01-11 14:50:10 +01001037 MPI_VALIDATE_RET(X != NULL);
1038 MPI_VALIDATE_RET(A != NULL);
1039 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001040
Gilles Peskine449bd832023-01-11 14:50:10 +01001041 if (X == B) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001042 const mbedtls_mpi *T = A; A = X; B = T;
Paul Bakker5121ce52009-01-03 21:22:43 +00001043 }
1044
Gilles Peskine449bd832023-01-11 14:50:10 +01001045 if (X != A) {
1046 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1047 }
Paul Bakker9af723c2014-05-01 13:03:14 +02001048
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001049 /*
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001050 * X must always be positive as a result of unsigned additions.
Paul Bakkerf7ca7b92009-06-20 10:31:06 +00001051 */
1052 X->s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001053
Gilles Peskine449bd832023-01-11 14:50:10 +01001054 for (j = B->n; j > 0; j--) {
1055 if (B->p[j - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001056 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001057 }
1058 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001059
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001060 /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
1061 * and B is 0 (of any size). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001062 if (j == 0) {
1063 return 0;
1064 }
Gilles Peskinedb14a9d2022-11-15 22:59:00 +01001065
Gilles Peskine449bd832023-01-11 14:50:10 +01001066 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j));
Paul Bakker5121ce52009-01-03 21:22:43 +00001067
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001068 /* j is the number of non-zero limbs of B. Add those to X. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001069
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001070 p = X->p;
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001071
Agathiyan Bragadeeshc99840a2023-07-12 11:15:46 +01001072 c = mbedtls_mpi_core_add(p, p, B->p, j);
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001073
1074 p += j;
1075
1076 /* Now propagate any carry */
Paul Bakker5121ce52009-01-03 21:22:43 +00001077
Gilles Peskine449bd832023-01-11 14:50:10 +01001078 while (c != 0) {
1079 if (j >= X->n) {
1080 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, j + 1));
Tom Cosgroveaf7d44b2022-08-24 14:05:26 +01001081 p = X->p + j;
Paul Bakker5121ce52009-01-03 21:22:43 +00001082 }
1083
Gilles Peskine449bd832023-01-11 14:50:10 +01001084 *p += c; c = (*p < c); j++; p++;
Paul Bakker5121ce52009-01-03 21:22:43 +00001085 }
1086
1087cleanup:
1088
Gilles Peskine449bd832023-01-11 14:50:10 +01001089 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001090}
1091
Paul Bakker5121ce52009-01-03 21:22:43 +00001092/*
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001093 * Unsigned subtraction: X = |A| - |B| (HAC 14.9, 14.10)
Paul Bakker5121ce52009-01-03 21:22:43 +00001094 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001095int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001096{
Janos Follath24eed8d2019-11-22 13:21:35 +00001097 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001098 size_t n;
Gilles Peskine0e5faf62020-06-08 22:50:35 +02001099 mbedtls_mpi_uint carry;
Gilles Peskine449bd832023-01-11 14:50:10 +01001100 MPI_VALIDATE_RET(X != NULL);
1101 MPI_VALIDATE_RET(A != NULL);
1102 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001103
Gilles Peskine449bd832023-01-11 14:50:10 +01001104 for (n = B->n; n > 0; n--) {
1105 if (B->p[n - 1] != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001106 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001107 }
1108 }
1109 if (n > A->n) {
Gilles Peskinec8a91772021-01-27 22:30:43 +01001110 /* B >= (2^ciL)^n > A */
1111 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1112 goto cleanup;
1113 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001114
Gilles Peskine449bd832023-01-11 14:50:10 +01001115 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, A->n));
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001116
1117 /* Set the high limbs of X to match A. Don't touch the lower limbs
1118 * because X might be aliased to B, and we must not overwrite the
1119 * significant digits of B. */
Aaron M. Uckoaf67d2c2023-01-17 11:52:22 -05001120 if (A->n > n && A != X) {
Gilles Peskine449bd832023-01-11 14:50:10 +01001121 memcpy(X->p + n, A->p + n, (A->n - n) * ciL);
1122 }
1123 if (X->n > A->n) {
1124 memset(X->p + A->n, 0, (X->n - A->n) * ciL);
1125 }
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001126
Gilles Peskine449bd832023-01-11 14:50:10 +01001127 carry = mbedtls_mpi_core_sub(X->p, A->p, B->p, n);
1128 if (carry != 0) {
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001129 /* Propagate the carry through the rest of X. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001130 carry = mbedtls_mpi_core_sub_int(X->p + n, X->p + n, carry, X->n - n);
Tom Cosgrove452c99c2022-08-25 10:07:07 +01001131
1132 /* If we have further carry/borrow, the result is negative. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001133 if (carry != 0) {
Gilles Peskine89b41302020-07-23 01:16:46 +02001134 ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1135 goto cleanup;
1136 }
Gilles Peskinec097e9e2020-06-08 21:58:22 +02001137 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001138
Gilles Peskine1acf7cb2020-07-23 01:03:22 +02001139 /* X should always be positive as a result of unsigned subtractions. */
1140 X->s = 1;
1141
Paul Bakker5121ce52009-01-03 21:22:43 +00001142cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001143 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001144}
1145
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001146/* Common function for signed addition and subtraction.
1147 * Calculate A + B * flip_B where flip_B is 1 or -1.
Paul Bakker5121ce52009-01-03 21:22:43 +00001148 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001149static int add_sub_mpi(mbedtls_mpi *X,
1150 const mbedtls_mpi *A, const mbedtls_mpi *B,
1151 int flip_B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001152{
Hanno Becker73d7d792018-12-11 10:35:51 +00001153 int ret, s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001154 MPI_VALIDATE_RET(X != NULL);
1155 MPI_VALIDATE_RET(A != NULL);
1156 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001157
Hanno Becker73d7d792018-12-11 10:35:51 +00001158 s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001159 if (A->s * B->s * flip_B < 0) {
1160 int cmp = mbedtls_mpi_cmp_abs(A, B);
1161 if (cmp >= 0) {
1162 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, A, B));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001163 /* If |A| = |B|, the result is 0 and we must set the sign bit
1164 * to +1 regardless of which of A or B was negative. Otherwise,
1165 * since |A| > |B|, the sign is the sign of A. */
1166 X->s = cmp == 0 ? 1 : s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001167 } else {
1168 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(X, B, A));
Gilles Peskine4a768dd2022-11-09 22:02:16 +01001169 /* Since |A| < |B|, the sign is the opposite of A. */
Paul Bakker5121ce52009-01-03 21:22:43 +00001170 X->s = -s;
1171 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001172 } else {
1173 MBEDTLS_MPI_CHK(mbedtls_mpi_add_abs(X, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001174 X->s = s;
1175 }
1176
1177cleanup:
1178
Gilles Peskine449bd832023-01-11 14:50:10 +01001179 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001180}
1181
1182/*
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001183 * Signed addition: X = A + B
1184 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001185int mbedtls_mpi_add_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001186{
Gilles Peskine449bd832023-01-11 14:50:10 +01001187 return add_sub_mpi(X, A, B, 1);
Gilles Peskine72ee1e32022-11-09 21:34:09 +01001188}
1189
1190/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001191 * Signed subtraction: X = A - B
Paul Bakker5121ce52009-01-03 21:22:43 +00001192 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001193int mbedtls_mpi_sub_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001194{
Gilles Peskine449bd832023-01-11 14:50:10 +01001195 return add_sub_mpi(X, A, B, -1);
Paul Bakker5121ce52009-01-03 21:22:43 +00001196}
1197
1198/*
1199 * Signed addition: X = A + b
1200 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001201int mbedtls_mpi_add_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001202{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001203 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001204 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001205 MPI_VALIDATE_RET(X != NULL);
1206 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001207
Gilles Peskine449bd832023-01-11 14:50:10 +01001208 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001209 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001210 B.n = 1;
1211 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001212
Gilles Peskine449bd832023-01-11 14:50:10 +01001213 return mbedtls_mpi_add_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001214}
1215
1216/*
Paul Bakker60b1d102013-10-29 10:02:51 +01001217 * Signed subtraction: X = A - b
Paul Bakker5121ce52009-01-03 21:22:43 +00001218 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001219int mbedtls_mpi_sub_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001220{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001221 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001222 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001223 MPI_VALIDATE_RET(X != NULL);
1224 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001225
Gilles Peskine449bd832023-01-11 14:50:10 +01001226 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001227 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001228 B.n = 1;
1229 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001230
Gilles Peskine449bd832023-01-11 14:50:10 +01001231 return mbedtls_mpi_sub_mpi(X, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001232}
1233
Paul Bakker5121ce52009-01-03 21:22:43 +00001234/*
1235 * Baseline multiplication: X = A * B (HAC 14.12)
1236 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001237int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001238{
Janos Follath24eed8d2019-11-22 13:21:35 +00001239 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Becker1772e052022-04-13 06:51:40 +01001240 size_t i, j;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001241 mbedtls_mpi TA, TB;
Hanno Beckerda763de2022-04-13 06:50:02 +01001242 int result_is_zero = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001243 MPI_VALIDATE_RET(X != NULL);
1244 MPI_VALIDATE_RET(A != NULL);
1245 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001246
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001247 mbedtls_mpi_init(&TA);
1248 mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00001249
Gilles Peskine449bd832023-01-11 14:50:10 +01001250 if (X == A) {
1251 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A)); A = &TA;
1252 }
1253 if (X == B) {
1254 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B)); B = &TB;
1255 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001256
Gilles Peskine449bd832023-01-11 14:50:10 +01001257 for (i = A->n; i > 0; i--) {
1258 if (A->p[i - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001259 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001260 }
1261 }
1262 if (i == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001263 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001264 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001265
Gilles Peskine449bd832023-01-11 14:50:10 +01001266 for (j = B->n; j > 0; j--) {
1267 if (B->p[j - 1] != 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001268 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001269 }
1270 }
1271 if (j == 0) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001272 result_is_zero = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001273 }
Hanno Beckerda763de2022-04-13 06:50:02 +01001274
Gilles Peskine449bd832023-01-11 14:50:10 +01001275 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, i + j));
1276 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, 0));
Paul Bakker5121ce52009-01-03 21:22:43 +00001277
Tom Cosgrove6af26f32022-08-24 16:40:55 +01001278 mbedtls_mpi_core_mul(X->p, A->p, i, B->p, j);
Paul Bakker5121ce52009-01-03 21:22:43 +00001279
Hanno Beckerda763de2022-04-13 06:50:02 +01001280 /* If the result is 0, we don't shortcut the operation, which reduces
1281 * but does not eliminate side channels leaking the zero-ness. We do
1282 * need to take care to set the sign bit properly since the library does
1283 * not fully support an MPI object with a value of 0 and s == -1. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001284 if (result_is_zero) {
Hanno Beckerda763de2022-04-13 06:50:02 +01001285 X->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001286 } else {
Hanno Beckerda763de2022-04-13 06:50:02 +01001287 X->s = A->s * B->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001288 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001289
1290cleanup:
1291
Gilles Peskine449bd832023-01-11 14:50:10 +01001292 mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TA);
Paul Bakker5121ce52009-01-03 21:22:43 +00001293
Gilles Peskine449bd832023-01-11 14:50:10 +01001294 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001295}
1296
1297/*
1298 * Baseline multiplication: X = A * b
1299 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001300int mbedtls_mpi_mul_int(mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001301{
Gilles Peskine449bd832023-01-11 14:50:10 +01001302 MPI_VALIDATE_RET(X != NULL);
1303 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001304
Hanno Becker35771312022-04-14 11:52:11 +01001305 size_t n = A->n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001306 while (n > 0 && A->p[n - 1] == 0) {
Hanno Becker35771312022-04-14 11:52:11 +01001307 --n;
Gilles Peskine449bd832023-01-11 14:50:10 +01001308 }
Hanno Becker35771312022-04-14 11:52:11 +01001309
Hanno Becker74a11a32022-04-06 06:27:00 +01001310 /* The general method below doesn't work if b==0. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001311 if (b == 0 || n == 0) {
1312 return mbedtls_mpi_lset(X, 0);
1313 }
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001314
Hanno Beckeraef9cc42022-04-11 06:36:29 +01001315 /* Calculate A*b as A + A*(b-1) to take advantage of mbedtls_mpi_core_mla */
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001316 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001317 /* In general, A * b requires 1 limb more than b. If
1318 * A->p[n - 1] * b / b == A->p[n - 1], then A * b fits in the same
1319 * number of limbs as A and the call to grow() is not required since
Gilles Peskinee1bba7c2021-03-10 23:44:10 +01001320 * copy() will take care of the growth if needed. However, experimentally,
1321 * making the call to grow() unconditional causes slightly fewer
Gilles Peskinecd0dbf32020-07-24 00:09:04 +02001322 * calls to calloc() in ECP code, presumably because it reuses the
1323 * same mpi for a while and this way the mpi is more likely to directly
Hanno Becker9137b9c2022-04-12 10:51:54 +01001324 * grow to its final size.
1325 *
1326 * Note that calculating A*b as 0 + A*b doesn't work as-is because
1327 * A,X can be the same. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001328 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, n + 1));
1329 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A));
1330 mbedtls_mpi_core_mla(X->p, X->n, A->p, n, b - 1);
Gilles Peskine8fd95c62020-07-23 21:58:50 +02001331
1332cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001333 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001334}
1335
1336/*
Simon Butcherf5ba0452015-12-27 23:01:55 +00001337 * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
1338 * mbedtls_mpi_uint divisor, d
Simon Butcher15b15d12015-11-26 19:35:03 +00001339 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001340static mbedtls_mpi_uint mbedtls_int_div_int(mbedtls_mpi_uint u1,
1341 mbedtls_mpi_uint u0,
1342 mbedtls_mpi_uint d,
1343 mbedtls_mpi_uint *r)
Simon Butcher15b15d12015-11-26 19:35:03 +00001344{
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001345#if defined(MBEDTLS_HAVE_UDBL)
1346 mbedtls_t_udbl dividend, quotient;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001347#else
Simon Butcher9803d072016-01-03 00:24:34 +00001348 const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001349 const mbedtls_mpi_uint uint_halfword_mask = ((mbedtls_mpi_uint) 1 << biH) - 1;
Simon Butcherf5ba0452015-12-27 23:01:55 +00001350 mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
1351 mbedtls_mpi_uint u0_msw, u0_lsw;
Simon Butcher9803d072016-01-03 00:24:34 +00001352 size_t s;
Manuel Pégourié-Gonnard16308882015-12-01 10:27:00 +01001353#endif
1354
Simon Butcher15b15d12015-11-26 19:35:03 +00001355 /*
1356 * Check for overflow
1357 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001358 if (0 == d || u1 >= d) {
1359 if (r != NULL) {
1360 *r = ~(mbedtls_mpi_uint) 0u;
1361 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001362
Gilles Peskine449bd832023-01-11 14:50:10 +01001363 return ~(mbedtls_mpi_uint) 0u;
Simon Butcher15b15d12015-11-26 19:35:03 +00001364 }
1365
1366#if defined(MBEDTLS_HAVE_UDBL)
Simon Butcher15b15d12015-11-26 19:35:03 +00001367 dividend = (mbedtls_t_udbl) u1 << biL;
1368 dividend |= (mbedtls_t_udbl) u0;
1369 quotient = dividend / d;
Gilles Peskine449bd832023-01-11 14:50:10 +01001370 if (quotient > ((mbedtls_t_udbl) 1 << biL) - 1) {
1371 quotient = ((mbedtls_t_udbl) 1 << biL) - 1;
1372 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001373
Gilles Peskine449bd832023-01-11 14:50:10 +01001374 if (r != NULL) {
1375 *r = (mbedtls_mpi_uint) (dividend - (quotient * d));
1376 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001377
1378 return (mbedtls_mpi_uint) quotient;
1379#else
Simon Butcher15b15d12015-11-26 19:35:03 +00001380
1381 /*
1382 * Algorithm D, Section 4.3.1 - The Art of Computer Programming
1383 * Vol. 2 - Seminumerical Algorithms, Knuth
1384 */
1385
1386 /*
1387 * Normalize the divisor, d, and dividend, u0, u1
1388 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001389 s = mbedtls_mpi_core_clz(d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001390 d = d << s;
1391
1392 u1 = u1 << s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001393 u1 |= (u0 >> (biL - s)) & (-(mbedtls_mpi_sint) s >> (biL - 1));
Simon Butcher15b15d12015-11-26 19:35:03 +00001394 u0 = u0 << s;
1395
1396 d1 = d >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001397 d0 = d & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001398
1399 u0_msw = u0 >> biH;
Simon Butcher9803d072016-01-03 00:24:34 +00001400 u0_lsw = u0 & uint_halfword_mask;
Simon Butcher15b15d12015-11-26 19:35:03 +00001401
1402 /*
1403 * Find the first quotient and remainder
1404 */
1405 q1 = u1 / d1;
1406 r0 = u1 - d1 * q1;
1407
Gilles Peskine449bd832023-01-11 14:50:10 +01001408 while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001409 q1 -= 1;
1410 r0 += d1;
1411
Gilles Peskine449bd832023-01-11 14:50:10 +01001412 if (r0 >= radix) {
1413 break;
1414 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001415 }
1416
Gilles Peskine449bd832023-01-11 14:50:10 +01001417 rAX = (u1 * radix) + (u0_msw - q1 * d);
Simon Butcher15b15d12015-11-26 19:35:03 +00001418 q0 = rAX / d1;
1419 r0 = rAX - q0 * d1;
1420
Gilles Peskine449bd832023-01-11 14:50:10 +01001421 while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw)) {
Simon Butcher15b15d12015-11-26 19:35:03 +00001422 q0 -= 1;
1423 r0 += d1;
1424
Gilles Peskine449bd832023-01-11 14:50:10 +01001425 if (r0 >= radix) {
1426 break;
1427 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001428 }
1429
Gilles Peskine449bd832023-01-11 14:50:10 +01001430 if (r != NULL) {
1431 *r = (rAX * radix + u0_lsw - q0 * d) >> s;
1432 }
Simon Butcher15b15d12015-11-26 19:35:03 +00001433
1434 quotient = q1 * radix + q0;
1435
1436 return quotient;
1437#endif
1438}
1439
1440/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001441 * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
Paul Bakker5121ce52009-01-03 21:22:43 +00001442 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001443int mbedtls_mpi_div_mpi(mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A,
1444 const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001445{
Janos Follath24eed8d2019-11-22 13:21:35 +00001446 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00001447 size_t i, n, t, k;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001448 mbedtls_mpi X, Y, Z, T1, T2;
Alexander Kd19a1932019-11-01 18:20:42 +03001449 mbedtls_mpi_uint TP2[3];
Gilles Peskine449bd832023-01-11 14:50:10 +01001450 MPI_VALIDATE_RET(A != NULL);
1451 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001452
Gilles Peskine449bd832023-01-11 14:50:10 +01001453 if (mbedtls_mpi_cmp_int(B, 0) == 0) {
1454 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1455 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001456
Gilles Peskine449bd832023-01-11 14:50:10 +01001457 mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
1458 mbedtls_mpi_init(&T1);
Alexander Kd19a1932019-11-01 18:20:42 +03001459 /*
1460 * Avoid dynamic memory allocations for constant-size T2.
1461 *
1462 * T2 is used for comparison only and the 3 limbs are assigned explicitly,
1463 * so nobody increase the size of the MPI and we're safe to use an on-stack
1464 * buffer.
1465 */
Alexander K35d6d462019-10-31 14:46:45 +03001466 T2.s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001467 T2.n = sizeof(TP2) / sizeof(*TP2);
Alexander Kd19a1932019-11-01 18:20:42 +03001468 T2.p = TP2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001469
Gilles Peskine449bd832023-01-11 14:50:10 +01001470 if (mbedtls_mpi_cmp_abs(A, B) < 0) {
1471 if (Q != NULL) {
1472 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(Q, 0));
1473 }
1474 if (R != NULL) {
1475 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, A));
1476 }
1477 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001478 }
1479
Gilles Peskine449bd832023-01-11 14:50:10 +01001480 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&X, A));
1481 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001482 X.s = Y.s = 1;
1483
Gilles Peskine449bd832023-01-11 14:50:10 +01001484 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&Z, A->n + 2));
1485 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Z, 0));
1486 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T1, A->n + 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001487
Gilles Peskine449bd832023-01-11 14:50:10 +01001488 k = mbedtls_mpi_bitlen(&Y) % biL;
1489 if (k < biL - 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001490 k = biL - 1 - k;
Gilles Peskine449bd832023-01-11 14:50:10 +01001491 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&X, k));
1492 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, k));
1493 } else {
1494 k = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001495 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001496
1497 n = X.n - 1;
1498 t = Y.n - 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001499 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001500
Gilles Peskine449bd832023-01-11 14:50:10 +01001501 while (mbedtls_mpi_cmp_mpi(&X, &Y) >= 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001502 Z.p[n - t]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001503 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &Y));
Paul Bakker5121ce52009-01-03 21:22:43 +00001504 }
Gilles Peskine449bd832023-01-11 14:50:10 +01001505 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, biL * (n - t)));
Paul Bakker5121ce52009-01-03 21:22:43 +00001506
Gilles Peskine449bd832023-01-11 14:50:10 +01001507 for (i = n; i > t; i--) {
1508 if (X.p[i] >= Y.p[t]) {
1509 Z.p[i - t - 1] = ~(mbedtls_mpi_uint) 0u;
1510 } else {
1511 Z.p[i - t - 1] = mbedtls_int_div_int(X.p[i], X.p[i - 1],
1512 Y.p[t], NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001513 }
1514
Gilles Peskine449bd832023-01-11 14:50:10 +01001515 T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
1516 T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
Alexander K35d6d462019-10-31 14:46:45 +03001517 T2.p[2] = X.p[i];
1518
Paul Bakker5121ce52009-01-03 21:22:43 +00001519 Z.p[i - t - 1]++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001520 do {
Paul Bakker5121ce52009-01-03 21:22:43 +00001521 Z.p[i - t - 1]--;
1522
Gilles Peskine449bd832023-01-11 14:50:10 +01001523 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&T1, 0));
1524 T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
Paul Bakker5121ce52009-01-03 21:22:43 +00001525 T1.p[1] = Y.p[t];
Gilles Peskine449bd832023-01-11 14:50:10 +01001526 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]));
1527 } while (mbedtls_mpi_cmp_mpi(&T1, &T2) > 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00001528
Gilles Peskine449bd832023-01-11 14:50:10 +01001529 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]));
1530 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1531 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001532
Gilles Peskine449bd832023-01-11 14:50:10 +01001533 if (mbedtls_mpi_cmp_int(&X, 0) < 0) {
1534 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &Y));
1535 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&T1, biL * (i - t - 1)));
1536 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&X, &X, &T1));
Paul Bakker5121ce52009-01-03 21:22:43 +00001537 Z.p[i - t - 1]--;
1538 }
1539 }
1540
Gilles Peskine449bd832023-01-11 14:50:10 +01001541 if (Q != NULL) {
1542 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(Q, &Z));
Paul Bakker5121ce52009-01-03 21:22:43 +00001543 Q->s = A->s * B->s;
1544 }
1545
Gilles Peskine449bd832023-01-11 14:50:10 +01001546 if (R != NULL) {
1547 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&X, k));
Paul Bakkerf02c5642012-11-13 10:25:21 +00001548 X.s = A->s;
Gilles Peskine449bd832023-01-11 14:50:10 +01001549 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(R, &X));
Paul Bakker5121ce52009-01-03 21:22:43 +00001550
Gilles Peskine449bd832023-01-11 14:50:10 +01001551 if (mbedtls_mpi_cmp_int(R, 0) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001552 R->s = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001553 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001554 }
1555
1556cleanup:
1557
Gilles Peskine449bd832023-01-11 14:50:10 +01001558 mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
1559 mbedtls_mpi_free(&T1);
1560 mbedtls_platform_zeroize(TP2, sizeof(TP2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001561
Gilles Peskine449bd832023-01-11 14:50:10 +01001562 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001563}
1564
1565/*
1566 * Division by int: A = Q * b + R
Paul Bakker5121ce52009-01-03 21:22:43 +00001567 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001568int mbedtls_mpi_div_int(mbedtls_mpi *Q, mbedtls_mpi *R,
1569 const mbedtls_mpi *A,
1570 mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001571{
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001572 mbedtls_mpi B;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001573 mbedtls_mpi_uint p[1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001574 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001575
Gilles Peskine449bd832023-01-11 14:50:10 +01001576 p[0] = mpi_sint_abs(b);
Dave Rodgmanf3df1052023-08-09 18:55:41 +01001577 B.s = TO_SIGN(b);
Yuto Takano36c8ddc2021-07-05 09:10:52 +01001578 B.n = 1;
1579 B.p = p;
Paul Bakker5121ce52009-01-03 21:22:43 +00001580
Gilles Peskine449bd832023-01-11 14:50:10 +01001581 return mbedtls_mpi_div_mpi(Q, R, A, &B);
Paul Bakker5121ce52009-01-03 21:22:43 +00001582}
1583
1584/*
1585 * Modulo: R = A mod B
1586 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001587int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00001588{
Janos Follath24eed8d2019-11-22 13:21:35 +00001589 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01001590 MPI_VALIDATE_RET(R != NULL);
1591 MPI_VALIDATE_RET(A != NULL);
1592 MPI_VALIDATE_RET(B != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001593
Gilles Peskine449bd832023-01-11 14:50:10 +01001594 if (mbedtls_mpi_cmp_int(B, 0) < 0) {
1595 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1596 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001597
Gilles Peskine449bd832023-01-11 14:50:10 +01001598 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(NULL, R, A, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00001599
Gilles Peskine449bd832023-01-11 14:50:10 +01001600 while (mbedtls_mpi_cmp_int(R, 0) < 0) {
1601 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(R, R, B));
1602 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001603
Gilles Peskine449bd832023-01-11 14:50:10 +01001604 while (mbedtls_mpi_cmp_mpi(R, B) >= 0) {
1605 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(R, R, B));
1606 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001607
1608cleanup:
1609
Gilles Peskine449bd832023-01-11 14:50:10 +01001610 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00001611}
1612
1613/*
1614 * Modulo: r = A mod b
1615 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001616int mbedtls_mpi_mod_int(mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b)
Paul Bakker5121ce52009-01-03 21:22:43 +00001617{
Paul Bakker23986e52011-04-24 08:57:21 +00001618 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001619 mbedtls_mpi_uint x, y, z;
Gilles Peskine449bd832023-01-11 14:50:10 +01001620 MPI_VALIDATE_RET(r != NULL);
1621 MPI_VALIDATE_RET(A != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00001622
Gilles Peskine449bd832023-01-11 14:50:10 +01001623 if (b == 0) {
1624 return MBEDTLS_ERR_MPI_DIVISION_BY_ZERO;
1625 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001626
Gilles Peskine449bd832023-01-11 14:50:10 +01001627 if (b < 0) {
1628 return MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
1629 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001630
1631 /*
1632 * handle trivial cases
1633 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001634 if (b == 1 || A->n == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001635 *r = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001636 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001637 }
1638
Gilles Peskine449bd832023-01-11 14:50:10 +01001639 if (b == 2) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001640 *r = A->p[0] & 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01001641 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001642 }
1643
1644 /*
1645 * general case
1646 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001647 for (i = A->n, y = 0; i > 0; i--) {
Paul Bakker23986e52011-04-24 08:57:21 +00001648 x = A->p[i - 1];
Gilles Peskine449bd832023-01-11 14:50:10 +01001649 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001650 z = y / b;
1651 y -= z * b;
1652
1653 x <<= biH;
Gilles Peskine449bd832023-01-11 14:50:10 +01001654 y = (y << biH) | (x >> biH);
Paul Bakker5121ce52009-01-03 21:22:43 +00001655 z = y / b;
1656 y -= z * b;
1657 }
1658
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001659 /*
1660 * If A is negative, then the current y represents a negative value.
1661 * Flipping it to the positive side.
1662 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001663 if (A->s < 0 && y != 0) {
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001664 y = b - y;
Gilles Peskine449bd832023-01-11 14:50:10 +01001665 }
Paul Bakkerce40a6d2009-06-23 19:46:08 +00001666
Paul Bakker5121ce52009-01-03 21:22:43 +00001667 *r = y;
1668
Gilles Peskine449bd832023-01-11 14:50:10 +01001669 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001670}
1671
Gilles Peskine449bd832023-01-11 14:50:10 +01001672static void mpi_montg_init(mbedtls_mpi_uint *mm, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00001673{
Gilles Peskine449bd832023-01-11 14:50:10 +01001674 *mm = mbedtls_mpi_core_montmul_init(N->p);
Paul Bakker5121ce52009-01-03 21:22:43 +00001675}
1676
Tom Cosgrove93842842022-08-05 16:59:43 +01001677/** Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
1678 *
1679 * \param[in,out] A One of the numbers to multiply.
1680 * It must have at least as many limbs as N
1681 * (A->n >= N->n), and any limbs beyond n are ignored.
1682 * On successful completion, A contains the result of
1683 * the multiplication A * B * R^-1 mod N where
1684 * R = (2^ciL)^n.
1685 * \param[in] B One of the numbers to multiply.
1686 * It must be nonzero and must not have more limbs than N
1687 * (B->n <= N->n).
Tom Cosgrove40d22942022-08-17 06:42:44 +01001688 * \param[in] N The modulus. \p N must be odd.
Tom Cosgrove93842842022-08-05 16:59:43 +01001689 * \param mm The value calculated by `mpi_montg_init(&mm, N)`.
1690 * This is -N^-1 mod 2^ciL.
1691 * \param[in,out] T A bignum for temporary storage.
1692 * It must be at least twice the limb size of N plus 1
1693 * (T->n >= 2 * N->n + 1).
1694 * Its initial content is unused and
1695 * its final content is indeterminate.
Tom Cosgrove5dd97e62022-08-30 14:31:49 +01001696 * It does not get reallocated.
Tom Cosgrove93842842022-08-05 16:59:43 +01001697 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001698static void mpi_montmul(mbedtls_mpi *A, const mbedtls_mpi *B,
1699 const mbedtls_mpi *N, mbedtls_mpi_uint mm,
1700 mbedtls_mpi *T)
Paul Bakker5121ce52009-01-03 21:22:43 +00001701{
Gilles Peskine449bd832023-01-11 14:50:10 +01001702 mbedtls_mpi_core_montmul(A->p, A->p, B->p, B->n, N->p, N->n, mm, T->p);
Paul Bakker5121ce52009-01-03 21:22:43 +00001703}
1704
1705/*
1706 * Montgomery reduction: A = A * R^-1 mod N
Gilles Peskine2a82f722020-06-04 15:00:49 +02001707 *
Tom Cosgrove93842842022-08-05 16:59:43 +01001708 * See mpi_montmul() regarding constraints and guarantees on the parameters.
Paul Bakker5121ce52009-01-03 21:22:43 +00001709 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001710static void mpi_montred(mbedtls_mpi *A, const mbedtls_mpi *N,
1711 mbedtls_mpi_uint mm, mbedtls_mpi *T)
Paul Bakker5121ce52009-01-03 21:22:43 +00001712{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001713 mbedtls_mpi_uint z = 1;
1714 mbedtls_mpi U;
Gilles Peskine053022f2023-06-29 19:26:48 +02001715 U.n = 1;
1716 U.s = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001717 U.p = &z;
1718
Gilles Peskine449bd832023-01-11 14:50:10 +01001719 mpi_montmul(A, &U, N, mm, T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001720}
1721
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001722/**
1723 * Select an MPI from a table without leaking the index.
1724 *
1725 * This is functionally equivalent to mbedtls_mpi_copy(R, T[idx]) except it
1726 * reads the entire table in order to avoid leaking the value of idx to an
1727 * attacker able to observe memory access patterns.
1728 *
1729 * \param[out] R Where to write the selected MPI.
1730 * \param[in] T The table to read from.
1731 * \param[in] T_size The number of elements in the table.
1732 * \param[in] idx The index of the element to select;
1733 * this must satisfy 0 <= idx < T_size.
1734 *
1735 * \return \c 0 on success, or a negative error code.
1736 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001737static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_t idx)
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001738{
1739 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1740
Gilles Peskine449bd832023-01-11 14:50:10 +01001741 for (size_t i = 0; i < T_size; i++) {
1742 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
Dave Rodgmanb7825ce2023-08-10 11:58:18 +01001743 (unsigned char) mbedtls_ct_uint_eq(i, idx)));
Manuel Pégourié-Gonnard92413ef2021-06-03 10:42:46 +02001744 }
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001745cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01001746 return ret;
Manuel Pégourié-Gonnard1297ef32021-03-09 11:22:20 +01001747}
1748
Paul Bakker5121ce52009-01-03 21:22:43 +00001749/*
1750 * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
1751 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001752int mbedtls_mpi_exp_mod(mbedtls_mpi *X, const mbedtls_mpi *A,
1753 const mbedtls_mpi *E, const mbedtls_mpi *N,
1754 mbedtls_mpi *prec_RR)
Paul Bakker5121ce52009-01-03 21:22:43 +00001755{
Janos Follath24eed8d2019-11-22 13:21:35 +00001756 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Janos Follath74601202022-11-21 15:54:20 +00001757 size_t window_bitsize;
Paul Bakker23986e52011-04-24 08:57:21 +00001758 size_t i, j, nblimbs;
1759 size_t bufsize, nbits;
Paul Elliott1748de12023-02-13 15:35:35 +00001760 size_t exponent_bits_in_window = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001761 mbedtls_mpi_uint ei, mm, state;
Gilles Peskine449bd832023-01-11 14:50:10 +01001762 mbedtls_mpi RR, T, W[(size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE], WW, Apos;
Paul Bakkerf6198c12012-05-16 08:02:29 +00001763 int neg;
Paul Bakker5121ce52009-01-03 21:22:43 +00001764
Gilles Peskine449bd832023-01-11 14:50:10 +01001765 MPI_VALIDATE_RET(X != NULL);
1766 MPI_VALIDATE_RET(A != NULL);
1767 MPI_VALIDATE_RET(E != NULL);
1768 MPI_VALIDATE_RET(N != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00001769
Gilles Peskine449bd832023-01-11 14:50:10 +01001770 if (mbedtls_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0) {
1771 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1772 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001773
Gilles Peskine449bd832023-01-11 14:50:10 +01001774 if (mbedtls_mpi_cmp_int(E, 0) < 0) {
1775 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1776 }
Paul Bakkerf6198c12012-05-16 08:02:29 +00001777
Gilles Peskine449bd832023-01-11 14:50:10 +01001778 if (mbedtls_mpi_bitlen(E) > MBEDTLS_MPI_MAX_BITS ||
1779 mbedtls_mpi_bitlen(N) > MBEDTLS_MPI_MAX_BITS) {
1780 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
1781 }
Chris Jones9246d042020-11-25 15:12:39 +00001782
Paul Bakkerf6198c12012-05-16 08:02:29 +00001783 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001784 * Init temps and window size
1785 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001786 mpi_montg_init(&mm, N);
1787 mbedtls_mpi_init(&RR); mbedtls_mpi_init(&T);
1788 mbedtls_mpi_init(&Apos);
1789 mbedtls_mpi_init(&WW);
1790 memset(W, 0, sizeof(W));
Paul Bakker5121ce52009-01-03 21:22:43 +00001791
Gilles Peskine449bd832023-01-11 14:50:10 +01001792 i = mbedtls_mpi_bitlen(E);
Paul Bakker5121ce52009-01-03 21:22:43 +00001793
Gilles Peskine449bd832023-01-11 14:50:10 +01001794 window_bitsize = (i > 671) ? 6 : (i > 239) ? 5 :
1795 (i > 79) ? 4 : (i > 23) ? 3 : 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00001796
Gilles Peskine449bd832023-01-11 14:50:10 +01001797#if (MBEDTLS_MPI_WINDOW_SIZE < 6)
1798 if (window_bitsize > MBEDTLS_MPI_WINDOW_SIZE) {
Janos Follath7fa11b82022-11-21 14:48:02 +00001799 window_bitsize = MBEDTLS_MPI_WINDOW_SIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +01001800 }
Peter Kolbuse6bcad32018-12-11 14:01:44 -06001801#endif
Paul Bakkerb6d5f082011-11-25 11:52:11 +00001802
Janos Follathc8d66d52022-11-22 10:47:10 +00001803 const size_t w_table_used_size = (size_t) 1 << window_bitsize;
Janos Follath06000952022-11-22 10:18:06 +00001804
Paul Bakker5121ce52009-01-03 21:22:43 +00001805 /*
Janos Follathbe54ca72022-11-21 16:14:54 +00001806 * This function is not constant-trace: its memory accesses depend on the
1807 * exponent value. To defend against timing attacks, callers (such as RSA
1808 * and DHM) should use exponent blinding. However this is not enough if the
1809 * adversary can find the exponent in a single trace, so this function
1810 * takes extra precautions against adversaries who can observe memory
1811 * access patterns.
Janos Follathf08b40e2022-11-11 15:56:38 +00001812 *
Janos Follathbe54ca72022-11-21 16:14:54 +00001813 * This function performs a series of multiplications by table elements and
1814 * squarings, and we want the prevent the adversary from finding out which
1815 * table element was used, and from distinguishing between multiplications
1816 * and squarings. Firstly, when multiplying by an element of the window
1817 * W[i], we do a constant-trace table lookup to obfuscate i. This leaves
1818 * squarings as having a different memory access patterns from other
Gilles Peskinee6cb45e2023-08-10 15:59:28 +02001819 * multiplications. So secondly, we put the accumulator in the table as
1820 * well, and also do a constant-trace table lookup to multiply by the
1821 * accumulator which is W[x_index].
Janos Follathbe54ca72022-11-21 16:14:54 +00001822 *
1823 * This way, all multiplications take the form of a lookup-and-multiply.
1824 * The number of lookup-and-multiply operations inside each iteration of
1825 * the main loop still depends on the bits of the exponent, but since the
1826 * other operations in the loop don't have an easily recognizable memory
1827 * trace, an adversary is unlikely to be able to observe the exact
1828 * patterns.
1829 *
1830 * An adversary may still be able to recover the exponent if they can
1831 * observe both memory accesses and branches. However, branch prediction
1832 * exploitation typically requires many traces of execution over the same
1833 * data, which is defeated by randomized blinding.
Janos Follath8e7d6a02022-10-04 13:27:40 +01001834 */
Janos Follathc8d66d52022-11-22 10:47:10 +00001835 const size_t x_index = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +01001836 mbedtls_mpi_init(&W[x_index]);
Janos Follath84461482022-11-21 14:31:22 +00001837
Paul Bakker5121ce52009-01-03 21:22:43 +00001838 j = N->n + 1;
Gilles Peskinee6cb45e2023-08-10 15:59:28 +02001839 /* All W[i] including the accumulator must have at least N->n limbs for
1840 * the mpi_montmul() and mpi_montred() calls later. Here we ensure that
1841 * W[1] and the accumulator W[x_index] are large enough. later we'll grow
1842 * other W[i] to the same length. They must not be shrunk midway through
1843 * this function!
Paul Bakker5121ce52009-01-03 21:22:43 +00001844 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001845 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[x_index], j));
1846 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], j));
1847 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&T, j * 2));
Paul Bakker5121ce52009-01-03 21:22:43 +00001848
1849 /*
Paul Bakker50546922012-05-19 08:40:49 +00001850 * Compensate for negative A (and correct at the end)
1851 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001852 neg = (A->s == -1);
1853 if (neg) {
1854 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Apos, A));
Paul Bakker50546922012-05-19 08:40:49 +00001855 Apos.s = 1;
1856 A = &Apos;
1857 }
1858
1859 /*
Paul Bakker5121ce52009-01-03 21:22:43 +00001860 * If 1st call, pre-compute R^2 mod N
1861 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001862 if (prec_RR == NULL || prec_RR->p == NULL) {
1863 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&RR, 1));
1864 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&RR, N->n * 2 * biL));
1865 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&RR, &RR, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00001866
Gilles Peskine449bd832023-01-11 14:50:10 +01001867 if (prec_RR != NULL) {
1868 memcpy(prec_RR, &RR, sizeof(mbedtls_mpi));
1869 }
1870 } else {
1871 memcpy(&RR, prec_RR, sizeof(mbedtls_mpi));
Paul Bakker5121ce52009-01-03 21:22:43 +00001872 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001873
1874 /*
1875 * W[1] = A * R^2 * R^-1 mod N = A * R mod N
1876 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001877 if (mbedtls_mpi_cmp_mpi(A, N) >= 0) {
1878 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&W[1], A, N));
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001879 /* This should be a no-op because W[1] is already that large before
1880 * mbedtls_mpi_mod_mpi(), but it's necessary to avoid an overflow
Tom Cosgrove93842842022-08-05 16:59:43 +01001881 * in mpi_montmul() below, so let's make sure. */
Gilles Peskine449bd832023-01-11 14:50:10 +01001882 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1], N->n + 1));
1883 } else {
1884 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[1], A));
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001885 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001886
Gilles Peskine3da1a8f2021-06-08 23:17:42 +02001887 /* Note that this is safe because W[1] always has at least N->n limbs
1888 * (it grew above and was preserved by mbedtls_mpi_copy()). */
Gilles Peskine449bd832023-01-11 14:50:10 +01001889 mpi_montmul(&W[1], &RR, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001890
1891 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01001892 * W[x_index] = R^2 * R^-1 mod N = R mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001893 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001894 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[x_index], &RR));
1895 mpi_montred(&W[x_index], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001896
Janos Follathc8d66d52022-11-22 10:47:10 +00001897
Gilles Peskine449bd832023-01-11 14:50:10 +01001898 if (window_bitsize > 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001899 /*
Janos Follath74601202022-11-21 15:54:20 +00001900 * W[i] = W[1] ^ i
1901 *
1902 * The first bit of the sliding window is always 1 and therefore we
1903 * only need to store the second half of the table.
Janos Follathc8d66d52022-11-22 10:47:10 +00001904 *
1905 * (There are two special elements in the table: W[0] for the
1906 * accumulator/result and W[1] for A in Montgomery form. Both of these
1907 * are already set at this point.)
Paul Bakker5121ce52009-01-03 21:22:43 +00001908 */
Janos Follath74601202022-11-21 15:54:20 +00001909 j = w_table_used_size / 2;
Paul Bakker5121ce52009-01-03 21:22:43 +00001910
Gilles Peskine449bd832023-01-11 14:50:10 +01001911 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[j], N->n + 1));
1912 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[j], &W[1]));
Paul Bakker5121ce52009-01-03 21:22:43 +00001913
Gilles Peskine449bd832023-01-11 14:50:10 +01001914 for (i = 0; i < window_bitsize - 1; i++) {
1915 mpi_montmul(&W[j], &W[j], N, mm, &T);
1916 }
Paul Bakker0d7702c2013-10-29 16:18:35 +01001917
Paul Bakker5121ce52009-01-03 21:22:43 +00001918 /*
1919 * W[i] = W[i - 1] * W[1]
1920 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001921 for (i = j + 1; i < w_table_used_size; i++) {
1922 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[i], N->n + 1));
1923 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&W[i], &W[i - 1]));
Paul Bakker5121ce52009-01-03 21:22:43 +00001924
Gilles Peskine449bd832023-01-11 14:50:10 +01001925 mpi_montmul(&W[i], &W[1], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001926 }
1927 }
1928
1929 nblimbs = E->n;
1930 bufsize = 0;
1931 nbits = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001932 state = 0;
1933
Gilles Peskine449bd832023-01-11 14:50:10 +01001934 while (1) {
1935 if (bufsize == 0) {
1936 if (nblimbs == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001937 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01001938 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001939
Paul Bakker0d7702c2013-10-29 16:18:35 +01001940 nblimbs--;
1941
Gilles Peskine449bd832023-01-11 14:50:10 +01001942 bufsize = sizeof(mbedtls_mpi_uint) << 3;
Paul Bakker5121ce52009-01-03 21:22:43 +00001943 }
1944
1945 bufsize--;
1946
1947 ei = (E->p[nblimbs] >> bufsize) & 1;
1948
1949 /*
1950 * skip leading 0s
1951 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001952 if (ei == 0 && state == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001953 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01001954 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001955
Gilles Peskine449bd832023-01-11 14:50:10 +01001956 if (ei == 0 && state == 1) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001957 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01001958 * out of window, square W[x_index]
Paul Bakker5121ce52009-01-03 21:22:43 +00001959 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001960 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
1961 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001962 continue;
1963 }
1964
1965 /*
1966 * add ei to current window
1967 */
1968 state = 2;
1969
1970 nbits++;
Gilles Peskine449bd832023-01-11 14:50:10 +01001971 exponent_bits_in_window |= (ei << (window_bitsize - nbits));
Paul Bakker5121ce52009-01-03 21:22:43 +00001972
Gilles Peskine449bd832023-01-11 14:50:10 +01001973 if (nbits == window_bitsize) {
Paul Bakker5121ce52009-01-03 21:22:43 +00001974 /*
Janos Follath7fa11b82022-11-21 14:48:02 +00001975 * W[x_index] = W[x_index]^window_bitsize R^-1 mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001976 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001977 for (i = 0; i < window_bitsize; i++) {
1978 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
1979 x_index));
1980 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Janos Follathb764ee12022-10-04 14:00:09 +01001981 }
Paul Bakker5121ce52009-01-03 21:22:43 +00001982
1983 /*
Janos Follath7fa11b82022-11-21 14:48:02 +00001984 * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00001985 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001986 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size,
1987 exponent_bits_in_window));
1988 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00001989
1990 state--;
1991 nbits = 0;
Janos Follath7fa11b82022-11-21 14:48:02 +00001992 exponent_bits_in_window = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +00001993 }
1994 }
1995
1996 /*
1997 * process the remaining bits
1998 */
Gilles Peskine449bd832023-01-11 14:50:10 +01001999 for (i = 0; i < nbits; i++) {
2000 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, x_index));
2001 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00002002
Janos Follath7fa11b82022-11-21 14:48:02 +00002003 exponent_bits_in_window <<= 1;
Paul Bakker5121ce52009-01-03 21:22:43 +00002004
Gilles Peskine449bd832023-01-11 14:50:10 +01002005 if ((exponent_bits_in_window & ((size_t) 1 << window_bitsize)) != 0) {
2006 MBEDTLS_MPI_CHK(mpi_select(&WW, W, w_table_used_size, 1));
2007 mpi_montmul(&W[x_index], &WW, N, mm, &T);
Janos Follathb764ee12022-10-04 14:00:09 +01002008 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002009 }
2010
2011 /*
Janos Follath8e7d6a02022-10-04 13:27:40 +01002012 * W[x_index] = A^E * R * R^-1 mod N = A^E mod N
Paul Bakker5121ce52009-01-03 21:22:43 +00002013 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002014 mpi_montred(&W[x_index], N, mm, &T);
Paul Bakker5121ce52009-01-03 21:22:43 +00002015
Gilles Peskine449bd832023-01-11 14:50:10 +01002016 if (neg && E->n != 0 && (E->p[0] & 1) != 0) {
Janos Follath8e7d6a02022-10-04 13:27:40 +01002017 W[x_index].s = -1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002018 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&W[x_index], N, &W[x_index]));
Paul Bakkerf6198c12012-05-16 08:02:29 +00002019 }
2020
Janos Follath8e7d6a02022-10-04 13:27:40 +01002021 /*
2022 * Load the result in the output variable.
2023 */
Chien Wonge2caf412023-08-01 21:38:46 +08002024 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &W[x_index]));
Janos Follath8e7d6a02022-10-04 13:27:40 +01002025
Paul Bakker5121ce52009-01-03 21:22:43 +00002026cleanup:
2027
Janos Follathb2c2fca2022-11-21 15:05:31 +00002028 /* The first bit of the sliding window is always 1 and therefore the first
2029 * half of the table was unused. */
Gilles Peskine449bd832023-01-11 14:50:10 +01002030 for (i = w_table_used_size/2; i < w_table_used_size; i++) {
2031 mbedtls_mpi_free(&W[i]);
2032 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002033
Gilles Peskine449bd832023-01-11 14:50:10 +01002034 mbedtls_mpi_free(&W[x_index]);
2035 mbedtls_mpi_free(&W[1]);
2036 mbedtls_mpi_free(&T);
2037 mbedtls_mpi_free(&Apos);
2038 mbedtls_mpi_free(&WW);
Paul Bakker6c591fa2011-05-05 11:49:20 +00002039
Gilles Peskine449bd832023-01-11 14:50:10 +01002040 if (prec_RR == NULL || prec_RR->p == NULL) {
2041 mbedtls_mpi_free(&RR);
2042 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002043
Gilles Peskine449bd832023-01-11 14:50:10 +01002044 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002045}
2046
Paul Bakker5121ce52009-01-03 21:22:43 +00002047/*
2048 * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
2049 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002050int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
Paul Bakker5121ce52009-01-03 21:22:43 +00002051{
Janos Follath24eed8d2019-11-22 13:21:35 +00002052 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker23986e52011-04-24 08:57:21 +00002053 size_t lz, lzt;
Alexander Ke8ad49f2019-08-16 16:16:07 +03002054 mbedtls_mpi TA, TB;
Paul Bakker5121ce52009-01-03 21:22:43 +00002055
Gilles Peskine449bd832023-01-11 14:50:10 +01002056 MPI_VALIDATE_RET(G != NULL);
2057 MPI_VALIDATE_RET(A != NULL);
2058 MPI_VALIDATE_RET(B != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002059
Gilles Peskine449bd832023-01-11 14:50:10 +01002060 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00002061
Gilles Peskine449bd832023-01-11 14:50:10 +01002062 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TA, A));
2063 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, B));
Paul Bakker5121ce52009-01-03 21:22:43 +00002064
Gilles Peskine449bd832023-01-11 14:50:10 +01002065 lz = mbedtls_mpi_lsb(&TA);
2066 lzt = mbedtls_mpi_lsb(&TB);
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002067
Gilles Peskine27253bc2021-06-09 13:26:43 +02002068 /* The loop below gives the correct result when A==0 but not when B==0.
2069 * So have a special case for B==0. Leverage the fact that we just
2070 * calculated the lsb and lsb(B)==0 iff B is odd or 0 to make the test
2071 * slightly more efficient than cmp_int(). */
Gilles Peskine449bd832023-01-11 14:50:10 +01002072 if (lzt == 0 && mbedtls_mpi_get_bit(&TB, 0) == 0) {
2073 ret = mbedtls_mpi_copy(G, A);
Gilles Peskine27253bc2021-06-09 13:26:43 +02002074 goto cleanup;
2075 }
2076
Gilles Peskine449bd832023-01-11 14:50:10 +01002077 if (lzt < lz) {
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002078 lz = lzt;
Gilles Peskine449bd832023-01-11 14:50:10 +01002079 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002080
Paul Bakker5121ce52009-01-03 21:22:43 +00002081 TA.s = TB.s = 1;
2082
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002083 /* We mostly follow the procedure described in HAC 14.54, but with some
2084 * minor differences:
2085 * - Sequences of multiplications or divisions by 2 are grouped into a
2086 * single shift operation.
Gilles Peskineb09c7ee2021-06-21 18:58:39 +02002087 * - The procedure in HAC assumes that 0 < TB <= TA.
2088 * - The condition TB <= TA is not actually necessary for correctness.
2089 * TA and TB have symmetric roles except for the loop termination
2090 * condition, and the shifts at the beginning of the loop body
2091 * remove any significance from the ordering of TA vs TB before
2092 * the shifts.
2093 * - If TA = 0, the loop goes through 0 iterations and the result is
2094 * correctly TB.
2095 * - The case TB = 0 was short-circuited above.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002096 *
2097 * For the correctness proof below, decompose the original values of
2098 * A and B as
2099 * A = sa * 2^a * A' with A'=0 or A' odd, and sa = +-1
2100 * B = sb * 2^b * B' with B'=0 or B' odd, and sb = +-1
2101 * Then gcd(A, B) = 2^{min(a,b)} * gcd(A',B'),
2102 * and gcd(A',B') is odd or 0.
2103 *
2104 * At the beginning, we have TA = |A| and TB = |B| so gcd(A,B) = gcd(TA,TB).
2105 * The code maintains the following invariant:
2106 * gcd(A,B) = 2^k * gcd(TA,TB) for some k (I)
Gilles Peskine4df3f1f2021-06-15 22:09:39 +02002107 */
2108
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002109 /* Proof that the loop terminates:
2110 * At each iteration, either the right-shift by 1 is made on a nonzero
2111 * value and the nonnegative integer bitlen(TA) + bitlen(TB) decreases
2112 * by at least 1, or the right-shift by 1 is made on zero and then
2113 * TA becomes 0 which ends the loop (TB cannot be 0 if it is right-shifted
2114 * since in that case TB is calculated from TB-TA with the condition TB>TA).
2115 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002116 while (mbedtls_mpi_cmp_int(&TA, 0) != 0) {
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002117 /* Divisions by 2 preserve the invariant (I). */
Gilles Peskine449bd832023-01-11 14:50:10 +01002118 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, mbedtls_mpi_lsb(&TA)));
2119 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, mbedtls_mpi_lsb(&TB)));
Paul Bakker5121ce52009-01-03 21:22:43 +00002120
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002121 /* Set either TA or TB to |TA-TB|/2. Since TA and TB are both odd,
2122 * TA-TB is even so the division by 2 has an integer result.
2123 * Invariant (I) is preserved since any odd divisor of both TA and TB
2124 * also divides |TA-TB|/2, and any odd divisor of both TA and |TA-TB|/2
Shaun Case8b0ecbc2021-12-20 21:14:10 -08002125 * also divides TB, and any odd divisor of both TB and |TA-TB|/2 also
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002126 * divides TA.
2127 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002128 if (mbedtls_mpi_cmp_mpi(&TA, &TB) >= 0) {
2129 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TA, &TA, &TB));
2130 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TA, 1));
2131 } else {
2132 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&TB, &TB, &TA));
2133 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TB, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002134 }
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002135 /* Note that one of TA or TB is still odd. */
Paul Bakker5121ce52009-01-03 21:22:43 +00002136 }
2137
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002138 /* By invariant (I), gcd(A,B) = 2^k * gcd(TA,TB) for some k.
2139 * At the loop exit, TA = 0, so gcd(TA,TB) = TB.
2140 * - If there was at least one loop iteration, then one of TA or TB is odd,
2141 * and TA = 0, so TB is odd and gcd(TA,TB) = gcd(A',B'). In this case,
2142 * lz = min(a,b) so gcd(A,B) = 2^lz * TB.
2143 * - If there was no loop iteration, then A was 0, and gcd(A,B) = B.
Gilles Peskine4d3fd362021-06-21 11:40:38 +02002144 * In this case, lz = 0 and B = TB so gcd(A,B) = B = 2^lz * TB as well.
Gilles Peskine2a63c5b2021-06-16 13:42:04 +02002145 */
2146
Gilles Peskine449bd832023-01-11 14:50:10 +01002147 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&TB, lz));
2148 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(G, &TB));
Paul Bakker5121ce52009-01-03 21:22:43 +00002149
2150cleanup:
2151
Gilles Peskine449bd832023-01-11 14:50:10 +01002152 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TB);
Paul Bakker5121ce52009-01-03 21:22:43 +00002153
Gilles Peskine449bd832023-01-11 14:50:10 +01002154 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002155}
2156
Paul Bakker33dc46b2014-04-30 16:11:39 +02002157/*
2158 * Fill X with size bytes of random.
Gilles Peskine22cdd0c2022-10-27 20:15:13 +02002159 * The bytes returned from the RNG are used in a specific order which
2160 * is suitable for deterministic ECDSA (see the specification of
2161 * mbedtls_mpi_random() and the implementation in mbedtls_mpi_fill_random()).
Paul Bakker33dc46b2014-04-30 16:11:39 +02002162 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002163int mbedtls_mpi_fill_random(mbedtls_mpi *X, size_t size,
2164 int (*f_rng)(void *, unsigned char *, size_t),
2165 void *p_rng)
Paul Bakker287781a2011-03-26 13:18:49 +00002166{
Janos Follath24eed8d2019-11-22 13:21:35 +00002167 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine449bd832023-01-11 14:50:10 +01002168 const size_t limbs = CHARS_TO_LIMBS(size);
Hanno Beckerda1655a2017-10-18 14:21:44 +01002169
Gilles Peskine449bd832023-01-11 14:50:10 +01002170 MPI_VALIDATE_RET(X != NULL);
2171 MPI_VALIDATE_RET(f_rng != NULL);
Paul Bakker33dc46b2014-04-30 16:11:39 +02002172
Hanno Beckerda1655a2017-10-18 14:21:44 +01002173 /* Ensure that target MPI has exactly the necessary number of limbs */
Gilles Peskine449bd832023-01-11 14:50:10 +01002174 MBEDTLS_MPI_CHK(mbedtls_mpi_resize_clear(X, limbs));
2175 if (size == 0) {
2176 return 0;
2177 }
Paul Bakker287781a2011-03-26 13:18:49 +00002178
Gilles Peskine449bd832023-01-11 14:50:10 +01002179 ret = mbedtls_mpi_core_fill_random(X->p, X->n, size, f_rng, p_rng);
Paul Bakker287781a2011-03-26 13:18:49 +00002180
2181cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002182 return ret;
Paul Bakker287781a2011-03-26 13:18:49 +00002183}
2184
Gilles Peskine449bd832023-01-11 14:50:10 +01002185int mbedtls_mpi_random(mbedtls_mpi *X,
2186 mbedtls_mpi_sint min,
2187 const mbedtls_mpi *N,
2188 int (*f_rng)(void *, unsigned char *, size_t),
2189 void *p_rng)
Gilles Peskine02ac93a2021-03-29 22:02:55 +02002190{
Gilles Peskine449bd832023-01-11 14:50:10 +01002191 if (min < 0) {
2192 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2193 }
2194 if (mbedtls_mpi_cmp_int(N, min) <= 0) {
2195 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2196 }
Gilles Peskine1e918f42021-03-29 22:14:51 +02002197
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02002198 /* Ensure that target MPI has exactly the same number of limbs
2199 * as the upper bound, even if the upper bound has leading zeros.
Gilles Peskine6b7ce962022-12-15 15:04:33 +01002200 * This is necessary for mbedtls_mpi_core_random. */
Gilles Peskine449bd832023-01-11 14:50:10 +01002201 int ret = mbedtls_mpi_resize_clear(X, N->n);
2202 if (ret != 0) {
2203 return ret;
2204 }
Gilles Peskine1a7df4e2021-04-01 15:57:18 +02002205
Gilles Peskine449bd832023-01-11 14:50:10 +01002206 return mbedtls_mpi_core_random(X->p, min, N->p, X->n, f_rng, p_rng);
Gilles Peskine02ac93a2021-03-29 22:02:55 +02002207}
2208
Paul Bakker5121ce52009-01-03 21:22:43 +00002209/*
2210 * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
2211 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002212int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
Paul Bakker5121ce52009-01-03 21:22:43 +00002213{
Janos Follath24eed8d2019-11-22 13:21:35 +00002214 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002215 mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
Gilles Peskine449bd832023-01-11 14:50:10 +01002216 MPI_VALIDATE_RET(X != NULL);
2217 MPI_VALIDATE_RET(A != NULL);
2218 MPI_VALIDATE_RET(N != NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +00002219
Gilles Peskine449bd832023-01-11 14:50:10 +01002220 if (mbedtls_mpi_cmp_int(N, 1) <= 0) {
2221 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2222 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002223
Gilles Peskine449bd832023-01-11 14:50:10 +01002224 mbedtls_mpi_init(&TA); mbedtls_mpi_init(&TU); mbedtls_mpi_init(&U1); mbedtls_mpi_init(&U2);
2225 mbedtls_mpi_init(&G); mbedtls_mpi_init(&TB); mbedtls_mpi_init(&TV);
2226 mbedtls_mpi_init(&V1); mbedtls_mpi_init(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002227
Gilles Peskine449bd832023-01-11 14:50:10 +01002228 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&G, A, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002229
Gilles Peskine449bd832023-01-11 14:50:10 +01002230 if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002231 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002232 goto cleanup;
2233 }
2234
Gilles Peskine449bd832023-01-11 14:50:10 +01002235 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&TA, A, N));
2236 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TU, &TA));
2237 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TB, N));
2238 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&TV, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002239
Gilles Peskine449bd832023-01-11 14:50:10 +01002240 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U1, 1));
2241 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&U2, 0));
2242 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V1, 0));
2243 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002244
Gilles Peskine449bd832023-01-11 14:50:10 +01002245 do {
2246 while ((TU.p[0] & 1) == 0) {
2247 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TU, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002248
Gilles Peskine449bd832023-01-11 14:50:10 +01002249 if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0) {
2250 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&U1, &U1, &TB));
2251 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002252 }
2253
Gilles Peskine449bd832023-01-11 14:50:10 +01002254 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U1, 1));
2255 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&U2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002256 }
2257
Gilles Peskine449bd832023-01-11 14:50:10 +01002258 while ((TV.p[0] & 1) == 0) {
2259 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&TV, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002260
Gilles Peskine449bd832023-01-11 14:50:10 +01002261 if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0) {
2262 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, &TB));
2263 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &TA));
Paul Bakker5121ce52009-01-03 21:22:43 +00002264 }
2265
Gilles Peskine449bd832023-01-11 14:50:10 +01002266 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V1, 1));
2267 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&V2, 1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002268 }
2269
Gilles Peskine449bd832023-01-11 14:50:10 +01002270 if (mbedtls_mpi_cmp_mpi(&TU, &TV) >= 0) {
2271 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TU, &TU, &TV));
2272 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U1, &U1, &V1));
2273 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&U2, &U2, &V2));
2274 } else {
2275 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&TV, &TV, &TU));
2276 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, &U1));
2277 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V2, &V2, &U2));
Paul Bakker5121ce52009-01-03 21:22:43 +00002278 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002279 } while (mbedtls_mpi_cmp_int(&TU, 0) != 0);
2280
2281 while (mbedtls_mpi_cmp_int(&V1, 0) < 0) {
2282 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&V1, &V1, N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002283 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002284
Gilles Peskine449bd832023-01-11 14:50:10 +01002285 while (mbedtls_mpi_cmp_mpi(&V1, N) >= 0) {
2286 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&V1, &V1, N));
2287 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002288
Gilles Peskine449bd832023-01-11 14:50:10 +01002289 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &V1));
Paul Bakker5121ce52009-01-03 21:22:43 +00002290
2291cleanup:
2292
Gilles Peskine449bd832023-01-11 14:50:10 +01002293 mbedtls_mpi_free(&TA); mbedtls_mpi_free(&TU); mbedtls_mpi_free(&U1); mbedtls_mpi_free(&U2);
2294 mbedtls_mpi_free(&G); mbedtls_mpi_free(&TB); mbedtls_mpi_free(&TV);
2295 mbedtls_mpi_free(&V1); mbedtls_mpi_free(&V2);
Paul Bakker5121ce52009-01-03 21:22:43 +00002296
Gilles Peskine449bd832023-01-11 14:50:10 +01002297 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002298}
2299
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002300#if defined(MBEDTLS_GENPRIME)
Paul Bakkerd9374b02012-11-02 11:02:58 +00002301
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002302/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
2303static const unsigned char small_prime_gaps[] = {
2304 2, 2, 4, 2, 4, 2, 4, 6,
2305 2, 6, 4, 2, 4, 6, 6, 2,
2306 6, 4, 2, 6, 4, 6, 8, 4,
2307 2, 4, 2, 4, 14, 4, 6, 2,
2308 10, 2, 6, 6, 4, 6, 6, 2,
2309 10, 2, 4, 2, 12, 12, 4, 2,
2310 4, 6, 2, 10, 6, 6, 6, 2,
2311 6, 4, 2, 10, 14, 4, 2, 4,
2312 14, 6, 10, 2, 4, 6, 8, 6,
2313 6, 4, 6, 8, 4, 8, 10, 2,
2314 10, 2, 6, 4, 6, 8, 4, 2,
2315 4, 12, 8, 4, 8, 4, 6, 12,
2316 2, 18, 6, 10, 6, 6, 2, 6,
2317 10, 6, 6, 2, 6, 6, 4, 2,
2318 12, 10, 2, 4, 6, 6, 2, 12,
2319 4, 6, 8, 10, 8, 10, 8, 6,
2320 6, 4, 8, 6, 4, 8, 4, 14,
2321 10, 12, 2, 10, 2, 4, 2, 10,
2322 14, 4, 2, 4, 14, 4, 2, 4,
2323 20, 4, 8, 10, 8, 4, 6, 6,
2324 14, 4, 6, 6, 8, 6, /*reaches 997*/
Gilles Peskine30b03782023-08-22 11:06:47 +02002325 0 /* the last entry is effectively unused */
Paul Bakker5121ce52009-01-03 21:22:43 +00002326};
2327
2328/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002329 * Small divisors test (X must be positive)
2330 *
2331 * Return values:
2332 * 0: no small factor (possible prime, more tests needed)
2333 * 1: certain prime
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002334 * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002335 * other negative: error
Paul Bakker5121ce52009-01-03 21:22:43 +00002336 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002337static int mpi_check_small_factors(const mbedtls_mpi *X)
Paul Bakker5121ce52009-01-03 21:22:43 +00002338{
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002339 int ret = 0;
2340 size_t i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002341 mbedtls_mpi_uint r;
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002342 unsigned p = 3; /* The first odd prime */
Paul Bakker5121ce52009-01-03 21:22:43 +00002343
Gilles Peskine449bd832023-01-11 14:50:10 +01002344 if ((X->p[0] & 1) == 0) {
2345 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2346 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002347
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002348 for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
2349 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
Gilles Peskine449bd832023-01-11 14:50:10 +01002350 if (r == 0) {
Gilles Peskineb2bc1712019-02-08 17:27:11 +01002351 if (mbedtls_mpi_cmp_int(X, p) == 0) {
2352 return 1;
2353 } else {
2354 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2355 }
Gilles Peskine449bd832023-01-11 14:50:10 +01002356 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002357 }
2358
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002359cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002360 return ret;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002361}
2362
2363/*
2364 * Miller-Rabin pseudo-primality test (HAC 4.24)
2365 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002366static int mpi_miller_rabin(const mbedtls_mpi *X, size_t rounds,
2367 int (*f_rng)(void *, unsigned char *, size_t),
2368 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002369{
Pascal Junodb99183d2015-03-11 16:49:45 +01002370 int ret, count;
Janos Follathda31fa12018-09-03 14:45:23 +01002371 size_t i, j, k, s;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002372 mbedtls_mpi W, R, T, A, RR;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002373
Gilles Peskine449bd832023-01-11 14:50:10 +01002374 MPI_VALIDATE_RET(X != NULL);
2375 MPI_VALIDATE_RET(f_rng != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002376
Gilles Peskine449bd832023-01-11 14:50:10 +01002377 mbedtls_mpi_init(&W); mbedtls_mpi_init(&R);
2378 mbedtls_mpi_init(&T); mbedtls_mpi_init(&A);
2379 mbedtls_mpi_init(&RR);
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002380
Paul Bakker5121ce52009-01-03 21:22:43 +00002381 /*
2382 * W = |X| - 1
2383 * R = W >> lsb( W )
2384 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002385 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&W, X, 1));
2386 s = mbedtls_mpi_lsb(&W);
2387 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R, &W));
2388 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&R, s));
Paul Bakker5121ce52009-01-03 21:22:43 +00002389
Gilles Peskine449bd832023-01-11 14:50:10 +01002390 for (i = 0; i < rounds; i++) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002391 /*
2392 * pick a random A, 1 < A < |X| - 1
2393 */
Pascal Junodb99183d2015-03-11 16:49:45 +01002394 count = 0;
2395 do {
Gilles Peskine449bd832023-01-11 14:50:10 +01002396 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&A, X->n * ciL, f_rng, p_rng));
Pascal Junodb99183d2015-03-11 16:49:45 +01002397
Gilles Peskine449bd832023-01-11 14:50:10 +01002398 j = mbedtls_mpi_bitlen(&A);
2399 k = mbedtls_mpi_bitlen(&W);
Pascal Junodb99183d2015-03-11 16:49:45 +01002400 if (j > k) {
Gilles Peskine449bd832023-01-11 14:50:10 +01002401 A.p[A.n - 1] &= ((mbedtls_mpi_uint) 1 << (k - (A.n - 1) * biL - 1)) - 1;
Pascal Junodb99183d2015-03-11 16:49:45 +01002402 }
2403
2404 if (count++ > 30) {
Jens Wiklanderf08aa3e2019-01-17 13:30:57 +01002405 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
2406 goto cleanup;
Pascal Junodb99183d2015-03-11 16:49:45 +01002407 }
2408
Gilles Peskine449bd832023-01-11 14:50:10 +01002409 } while (mbedtls_mpi_cmp_mpi(&A, &W) >= 0 ||
2410 mbedtls_mpi_cmp_int(&A, 1) <= 0);
Paul Bakker5121ce52009-01-03 21:22:43 +00002411
2412 /*
2413 * A = A^R mod |X|
2414 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002415 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&A, &A, &R, X, &RR));
Paul Bakker5121ce52009-01-03 21:22:43 +00002416
Gilles Peskine449bd832023-01-11 14:50:10 +01002417 if (mbedtls_mpi_cmp_mpi(&A, &W) == 0 ||
2418 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002419 continue;
Gilles Peskine449bd832023-01-11 14:50:10 +01002420 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002421
2422 j = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +01002423 while (j < s && mbedtls_mpi_cmp_mpi(&A, &W) != 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002424 /*
2425 * A = A * A mod |X|
2426 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002427 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&T, &A, &A));
2428 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &T, X));
Paul Bakker5121ce52009-01-03 21:22:43 +00002429
Gilles Peskine449bd832023-01-11 14:50:10 +01002430 if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002431 break;
Gilles Peskine449bd832023-01-11 14:50:10 +01002432 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002433
2434 j++;
2435 }
2436
2437 /*
2438 * not prime if A != |X| - 1 or A == 1
2439 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002440 if (mbedtls_mpi_cmp_mpi(&A, &W) != 0 ||
2441 mbedtls_mpi_cmp_int(&A, 1) == 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002442 ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker5121ce52009-01-03 21:22:43 +00002443 break;
2444 }
2445 }
2446
2447cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +01002448 mbedtls_mpi_free(&W); mbedtls_mpi_free(&R);
2449 mbedtls_mpi_free(&T); mbedtls_mpi_free(&A);
2450 mbedtls_mpi_free(&RR);
Paul Bakker5121ce52009-01-03 21:22:43 +00002451
Gilles Peskine449bd832023-01-11 14:50:10 +01002452 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002453}
2454
2455/*
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002456 * Pseudo-primality test: small factors, then Miller-Rabin
2457 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002458int mbedtls_mpi_is_prime_ext(const mbedtls_mpi *X, int rounds,
2459 int (*f_rng)(void *, unsigned char *, size_t),
2460 void *p_rng)
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002461{
Janos Follath24eed8d2019-11-22 13:21:35 +00002462 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002463 mbedtls_mpi XX;
Gilles Peskine449bd832023-01-11 14:50:10 +01002464 MPI_VALIDATE_RET(X != NULL);
2465 MPI_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnard7f4ed672014-10-14 20:56:02 +02002466
2467 XX.s = 1;
2468 XX.n = X->n;
2469 XX.p = X->p;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002470
Gilles Peskine449bd832023-01-11 14:50:10 +01002471 if (mbedtls_mpi_cmp_int(&XX, 0) == 0 ||
2472 mbedtls_mpi_cmp_int(&XX, 1) == 0) {
2473 return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002474 }
2475
Gilles Peskine449bd832023-01-11 14:50:10 +01002476 if (mbedtls_mpi_cmp_int(&XX, 2) == 0) {
2477 return 0;
2478 }
2479
2480 if ((ret = mpi_check_small_factors(&XX)) != 0) {
2481 if (ret == 1) {
2482 return 0;
2483 }
2484
2485 return ret;
2486 }
2487
2488 return mpi_miller_rabin(&XX, rounds, f_rng, p_rng);
Janos Follathf301d232018-08-14 13:34:01 +01002489}
2490
Manuel Pégourié-Gonnard378fb4b2013-11-22 18:39:18 +01002491/*
Paul Bakker5121ce52009-01-03 21:22:43 +00002492 * Prime number generation
Jethro Beekman66689272018-02-14 19:24:10 -08002493 *
Janos Follathf301d232018-08-14 13:34:01 +01002494 * To generate an RSA key in a way recommended by FIPS 186-4, both primes must
2495 * be either 1024 bits or 1536 bits long, and flags must contain
2496 * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR.
Paul Bakker5121ce52009-01-03 21:22:43 +00002497 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002498int mbedtls_mpi_gen_prime(mbedtls_mpi *X, size_t nbits, int flags,
2499 int (*f_rng)(void *, unsigned char *, size_t),
2500 void *p_rng)
Paul Bakker5121ce52009-01-03 21:22:43 +00002501{
Jethro Beekman66689272018-02-14 19:24:10 -08002502#ifdef MBEDTLS_HAVE_INT64
2503// ceil(2^63.5)
2504#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL
2505#else
2506// ceil(2^31.5)
2507#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U
2508#endif
2509 int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
Paul Bakker23986e52011-04-24 08:57:21 +00002510 size_t k, n;
Janos Follathda31fa12018-09-03 14:45:23 +01002511 int rounds;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002512 mbedtls_mpi_uint r;
2513 mbedtls_mpi Y;
Paul Bakker5121ce52009-01-03 21:22:43 +00002514
Gilles Peskine449bd832023-01-11 14:50:10 +01002515 MPI_VALIDATE_RET(X != NULL);
2516 MPI_VALIDATE_RET(f_rng != NULL);
Hanno Becker73d7d792018-12-11 10:35:51 +00002517
Gilles Peskine449bd832023-01-11 14:50:10 +01002518 if (nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS) {
2519 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
2520 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002521
Gilles Peskine449bd832023-01-11 14:50:10 +01002522 mbedtls_mpi_init(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002523
Gilles Peskine449bd832023-01-11 14:50:10 +01002524 n = BITS_TO_LIMBS(nbits);
Paul Bakker5121ce52009-01-03 21:22:43 +00002525
Gilles Peskine449bd832023-01-11 14:50:10 +01002526 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR) == 0) {
Janos Follathda31fa12018-09-03 14:45:23 +01002527 /*
2528 * 2^-80 error probability, number of rounds chosen per HAC, table 4.4
2529 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002530 rounds = ((nbits >= 1300) ? 2 : (nbits >= 850) ? 3 :
2531 (nbits >= 650) ? 4 : (nbits >= 350) ? 8 :
2532 (nbits >= 250) ? 12 : (nbits >= 150) ? 18 : 27);
2533 } else {
Janos Follathda31fa12018-09-03 14:45:23 +01002534 /*
2535 * 2^-100 error probability, number of rounds computed based on HAC,
2536 * fact 4.48
2537 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002538 rounds = ((nbits >= 1450) ? 4 : (nbits >= 1150) ? 5 :
2539 (nbits >= 1000) ? 6 : (nbits >= 850) ? 7 :
2540 (nbits >= 750) ? 8 : (nbits >= 500) ? 13 :
2541 (nbits >= 250) ? 28 : (nbits >= 150) ? 40 : 51);
Janos Follathda31fa12018-09-03 14:45:23 +01002542 }
2543
Gilles Peskine449bd832023-01-11 14:50:10 +01002544 while (1) {
2545 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(X, n * ciL, f_rng, p_rng));
Jethro Beekman66689272018-02-14 19:24:10 -08002546 /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */
Gilles Peskine449bd832023-01-11 14:50:10 +01002547 if (X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2) {
2548 continue;
2549 }
Jethro Beekman66689272018-02-14 19:24:10 -08002550
2551 k = n * biL;
Gilles Peskine449bd832023-01-11 14:50:10 +01002552 if (k > nbits) {
2553 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(X, k - nbits));
2554 }
Jethro Beekman66689272018-02-14 19:24:10 -08002555 X->p[0] |= 1;
2556
Gilles Peskine449bd832023-01-11 14:50:10 +01002557 if ((flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH) == 0) {
2558 ret = mbedtls_mpi_is_prime_ext(X, rounds, f_rng, p_rng);
Jethro Beekman66689272018-02-14 19:24:10 -08002559
Gilles Peskine449bd832023-01-11 14:50:10 +01002560 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Paul Bakker5121ce52009-01-03 21:22:43 +00002561 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002562 }
2563 } else {
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002564 /*
Tom Cosgrovece7f18c2022-07-28 05:50:56 +01002565 * A necessary condition for Y and X = 2Y + 1 to be prime
Jethro Beekman66689272018-02-14 19:24:10 -08002566 * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
2567 * Make sure it is satisfied, while keeping X = 3 mod 4
Manuel Pégourié-Gonnardddf76152013-11-22 19:58:22 +01002568 */
Jethro Beekman66689272018-02-14 19:24:10 -08002569
2570 X->p[0] |= 2;
2571
Gilles Peskine449bd832023-01-11 14:50:10 +01002572 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, 3));
2573 if (r == 0) {
2574 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 8));
2575 } else if (r == 1) {
2576 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 4));
2577 }
Jethro Beekman66689272018-02-14 19:24:10 -08002578
2579 /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
Gilles Peskine449bd832023-01-11 14:50:10 +01002580 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Y, X));
2581 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&Y, 1));
Jethro Beekman66689272018-02-14 19:24:10 -08002582
Gilles Peskine449bd832023-01-11 14:50:10 +01002583 while (1) {
Jethro Beekman66689272018-02-14 19:24:10 -08002584 /*
2585 * First, check small factors for X and Y
2586 * before doing Miller-Rabin on any of them
2587 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002588 if ((ret = mpi_check_small_factors(X)) == 0 &&
2589 (ret = mpi_check_small_factors(&Y)) == 0 &&
2590 (ret = mpi_miller_rabin(X, rounds, f_rng, p_rng))
2591 == 0 &&
2592 (ret = mpi_miller_rabin(&Y, rounds, f_rng, p_rng))
2593 == 0) {
Jethro Beekman66689272018-02-14 19:24:10 -08002594 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002595 }
Jethro Beekman66689272018-02-14 19:24:10 -08002596
Gilles Peskine449bd832023-01-11 14:50:10 +01002597 if (ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
Jethro Beekman66689272018-02-14 19:24:10 -08002598 goto cleanup;
Gilles Peskine449bd832023-01-11 14:50:10 +01002599 }
Jethro Beekman66689272018-02-14 19:24:10 -08002600
2601 /*
2602 * Next candidates. We want to preserve Y = (X-1) / 2 and
2603 * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
2604 * so up Y by 6 and X by 12.
2605 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002606 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(X, X, 12));
2607 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&Y, &Y, 6));
Paul Bakker5121ce52009-01-03 21:22:43 +00002608 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002609 }
2610 }
2611
2612cleanup:
2613
Gilles Peskine449bd832023-01-11 14:50:10 +01002614 mbedtls_mpi_free(&Y);
Paul Bakker5121ce52009-01-03 21:22:43 +00002615
Gilles Peskine449bd832023-01-11 14:50:10 +01002616 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002617}
2618
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002619#endif /* MBEDTLS_GENPRIME */
Paul Bakker5121ce52009-01-03 21:22:43 +00002620
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002621#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +00002622
Paul Bakker23986e52011-04-24 08:57:21 +00002623#define GCD_PAIR_COUNT 3
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002624
2625static const int gcd_pairs[GCD_PAIR_COUNT][3] =
2626{
2627 { 693, 609, 21 },
2628 { 1764, 868, 28 },
2629 { 768454923, 542167814, 1 }
2630};
2631
Paul Bakker5121ce52009-01-03 21:22:43 +00002632/*
2633 * Checkup routine
2634 */
Gilles Peskine449bd832023-01-11 14:50:10 +01002635int mbedtls_mpi_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +00002636{
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002637 int ret, i;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002638 mbedtls_mpi A, E, N, X, Y, U, V;
Paul Bakker5121ce52009-01-03 21:22:43 +00002639
Gilles Peskine449bd832023-01-11 14:50:10 +01002640 mbedtls_mpi_init(&A); mbedtls_mpi_init(&E); mbedtls_mpi_init(&N); mbedtls_mpi_init(&X);
2641 mbedtls_mpi_init(&Y); mbedtls_mpi_init(&U); mbedtls_mpi_init(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002642
Gilles Peskine449bd832023-01-11 14:50:10 +01002643 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&A, 16,
2644 "EFE021C2645FD1DC586E69184AF4A31E" \
2645 "D5F53E93B5F123FA41680867BA110131" \
2646 "944FE7952E2517337780CB0DB80E61AA" \
2647 "E7C8DDC6C5C6AADEB34EB38A2F40D5E6"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002648
Gilles Peskine449bd832023-01-11 14:50:10 +01002649 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&E, 16,
2650 "B2E7EFD37075B9F03FF989C7C5051C20" \
2651 "34D2A323810251127E7BF8625A4F49A5" \
2652 "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
2653 "5B5C25763222FEFCCFC38B832366C29E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002654
Gilles Peskine449bd832023-01-11 14:50:10 +01002655 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16,
2656 "0066A198186C18C10B2F5ED9B522752A" \
2657 "9830B69916E535C8F047518A889A43A5" \
2658 "94B6BED27A168D31D4A52F88925AA8F5"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002659
Gilles Peskine449bd832023-01-11 14:50:10 +01002660 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002661
Gilles Peskine449bd832023-01-11 14:50:10 +01002662 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2663 "602AB7ECA597A3D6B56FF9829A5E8B85" \
2664 "9E857EA95A03512E2BAE7391688D264A" \
2665 "A5663B0341DB9CCFD2C4C5F421FEC814" \
2666 "8001B72E848A38CAE1C65F78E56ABDEF" \
2667 "E12D3C039B8A02D6BE593F0BBBDA56F1" \
2668 "ECF677152EF804370C1A305CAF3B5BF1" \
2669 "30879B56C61DE584A0F53A2447A51E"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002670
Gilles Peskine449bd832023-01-11 14:50:10 +01002671 if (verbose != 0) {
2672 mbedtls_printf(" MPI test #1 (mul_mpi): ");
2673 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002674
Gilles Peskine449bd832023-01-11 14:50:10 +01002675 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2676 if (verbose != 0) {
2677 mbedtls_printf("failed\n");
2678 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002679
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002680 ret = 1;
2681 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002682 }
2683
Gilles Peskine449bd832023-01-11 14:50:10 +01002684 if (verbose != 0) {
2685 mbedtls_printf("passed\n");
2686 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002687
Gilles Peskine449bd832023-01-11 14:50:10 +01002688 MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi(&X, &Y, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002689
Gilles Peskine449bd832023-01-11 14:50:10 +01002690 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2691 "256567336059E52CAE22925474705F39A94"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002692
Gilles Peskine449bd832023-01-11 14:50:10 +01002693 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&V, 16,
2694 "6613F26162223DF488E9CD48CC132C7A" \
2695 "0AC93C701B001B092E4E5B9F73BCD27B" \
2696 "9EE50D0657C77F374E903CDFA4C642"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002697
Gilles Peskine449bd832023-01-11 14:50:10 +01002698 if (verbose != 0) {
2699 mbedtls_printf(" MPI test #2 (div_mpi): ");
2700 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002701
Gilles Peskine449bd832023-01-11 14:50:10 +01002702 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0 ||
2703 mbedtls_mpi_cmp_mpi(&Y, &V) != 0) {
2704 if (verbose != 0) {
2705 mbedtls_printf("failed\n");
2706 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002707
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002708 ret = 1;
2709 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002710 }
2711
Gilles Peskine449bd832023-01-11 14:50:10 +01002712 if (verbose != 0) {
2713 mbedtls_printf("passed\n");
2714 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002715
Gilles Peskine449bd832023-01-11 14:50:10 +01002716 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&X, &A, &E, &N, NULL));
Paul Bakker5121ce52009-01-03 21:22:43 +00002717
Gilles Peskine449bd832023-01-11 14:50:10 +01002718 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2719 "36E139AEA55215609D2816998ED020BB" \
2720 "BD96C37890F65171D948E9BC7CBAA4D9" \
2721 "325D24D6A3C12710F10A09FA08AB87"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002722
Gilles Peskine449bd832023-01-11 14:50:10 +01002723 if (verbose != 0) {
2724 mbedtls_printf(" MPI test #3 (exp_mod): ");
2725 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002726
Gilles Peskine449bd832023-01-11 14:50:10 +01002727 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2728 if (verbose != 0) {
2729 mbedtls_printf("failed\n");
2730 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002731
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002732 ret = 1;
2733 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002734 }
2735
Gilles Peskine449bd832023-01-11 14:50:10 +01002736 if (verbose != 0) {
2737 mbedtls_printf("passed\n");
2738 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002739
Gilles Peskine449bd832023-01-11 14:50:10 +01002740 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&X, &A, &N));
Paul Bakker5121ce52009-01-03 21:22:43 +00002741
Gilles Peskine449bd832023-01-11 14:50:10 +01002742 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&U, 16,
2743 "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
2744 "C3DBA76456363A10869622EAC2DD84EC" \
2745 "C5B8A74DAC4D09E03B5E0BE779F2DF61"));
Paul Bakker5121ce52009-01-03 21:22:43 +00002746
Gilles Peskine449bd832023-01-11 14:50:10 +01002747 if (verbose != 0) {
2748 mbedtls_printf(" MPI test #4 (inv_mod): ");
2749 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002750
Gilles Peskine449bd832023-01-11 14:50:10 +01002751 if (mbedtls_mpi_cmp_mpi(&X, &U) != 0) {
2752 if (verbose != 0) {
2753 mbedtls_printf("failed\n");
2754 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002755
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002756 ret = 1;
2757 goto cleanup;
Paul Bakker5121ce52009-01-03 21:22:43 +00002758 }
2759
Gilles Peskine449bd832023-01-11 14:50:10 +01002760 if (verbose != 0) {
2761 mbedtls_printf("passed\n");
2762 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002763
Gilles Peskine449bd832023-01-11 14:50:10 +01002764 if (verbose != 0) {
2765 mbedtls_printf(" MPI test #5 (simple gcd): ");
2766 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002767
Gilles Peskine449bd832023-01-11 14:50:10 +01002768 for (i = 0; i < GCD_PAIR_COUNT; i++) {
2769 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, gcd_pairs[i][0]));
2770 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Y, gcd_pairs[i][1]));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002771
Gilles Peskine449bd832023-01-11 14:50:10 +01002772 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&A, &X, &Y));
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002773
Gilles Peskine449bd832023-01-11 14:50:10 +01002774 if (mbedtls_mpi_cmp_int(&A, gcd_pairs[i][2]) != 0) {
2775 if (verbose != 0) {
2776 mbedtls_printf("failed at %d\n", i);
2777 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002778
Manuel Pégourié-Gonnard9e987ed2014-01-20 10:03:15 +01002779 ret = 1;
2780 goto cleanup;
2781 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002782 }
2783
Gilles Peskine449bd832023-01-11 14:50:10 +01002784 if (verbose != 0) {
2785 mbedtls_printf("passed\n");
2786 }
Paul Bakker4e0d7ca2009-01-29 22:24:33 +00002787
Paul Bakker5121ce52009-01-03 21:22:43 +00002788cleanup:
2789
Gilles Peskine449bd832023-01-11 14:50:10 +01002790 if (ret != 0 && verbose != 0) {
2791 mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret);
2792 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002793
Gilles Peskine449bd832023-01-11 14:50:10 +01002794 mbedtls_mpi_free(&A); mbedtls_mpi_free(&E); mbedtls_mpi_free(&N); mbedtls_mpi_free(&X);
2795 mbedtls_mpi_free(&Y); mbedtls_mpi_free(&U); mbedtls_mpi_free(&V);
Paul Bakker5121ce52009-01-03 21:22:43 +00002796
Gilles Peskine449bd832023-01-11 14:50:10 +01002797 if (verbose != 0) {
2798 mbedtls_printf("\n");
2799 }
Paul Bakker5121ce52009-01-03 21:22:43 +00002800
Gilles Peskine449bd832023-01-11 14:50:10 +01002801 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +00002802}
2803
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002804#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +00002805
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002806#endif /* MBEDTLS_BIGNUM_C */